释放子串而不在c中做双重自由

时间:2010-07-07 15:58:04

标签: c free malloc substring

昨天我问过一个类似的question关于如何freesub-string分配内存的问题。现在我还有一个关于同一问题的问题(涉及一系列条件),如何在不进行双重释放的情况下释放以下子字符串?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct st_ex {
    char product[16];
    float price;
};
struct st_temp {
    char *prod;
};

char *temp = NULL;

// from stackoverflow
char* substr( const char* source, size_t start, size_t end )
{
    char* dest = malloc( end - start + 1) ;
    memcpy( dest, &source[start], end - start ) ;
    dest[end - start] = 0 ;
    return dest ;
}

int main()
{
    struct st_ex structs[] = {{"mp3 player", 2.0f}, {"plasma tv", 20.0f},
                              {"notebook", 10.0f},  {"smartphone", 49.9f},
                              {"dvd player", 10.0f}, {"matches", 0.2f }};
    struct st_temp **temp_struct;

    size_t j, i;
    temp_struct = malloc(sizeof *temp_struct * 6);
    for (j = 0; j < 6; j++)
        temp_struct[j] = malloc(sizeof *temp_struct[j]);

    size_t structs_len = sizeof(structs) / sizeof(struct st_ex);

    // NOTE: that structs_len may vary in size - not just 6 
    for(i=0; i<structs_len; i++){
        if (i == 0)
            temp_struct[i]->prod = "+";
        else if(i == 1)
            temp_struct[i]->prod = "Bar";
        else if(i == 5)
            temp_struct[i]->prod = "Foo";
        else {
            temp = substr(structs[i].product, 0, 4);
            temp_struct[i]->prod = temp;
        }
    }
    for(i=0; i<6; i++ )
        printf("%s\n",temp_struct[i]->prod);

    for(i = 0; i < 6; i++ ){
        /* can I do something like this? */
        /*if (i != 0 || i != 1 || i != 5)*/
        free(temp_struct[i]->prod);
        free(temp_struct[i]);
    }
    free(temp_struct);
    return 0;
}

5 个答案:

答案 0 :(得分:1)

问题在于,有时您会将temp_struct[i]->prod设置为引用的字符串(“条形码”),您无法释放它,有时也会将其设置为您必须释放的子视图调用的结果。

最简单的解决方案是始终将其设置为必须释放的字符串。

  temp_struct[i]->prod = new_string("Bar");

,其中

char* new_string( const char* source )
{
    char* dest = malloc( strlen(source) + 1 ) ;
    strcpy(dest, source);        
    return dest ;
}

或者,如果您需要免费

,您必须跟踪
 struct st_temp {
     char *prod;
     int prod_must_be_freed;
 };

将prod_must_be_freed设置为0或1并在释放之前检查它。

最后,通过使用函数来操作这些结构而不是直接使用它们来改善整个过程。然后你可以创建一个free_st_temp(st_temp*)来检查是否应该释放prod,然后释放结构。你的循环将是

for(i = 0; i < 6; i++ ){    
    free_st_temp(temp_struct[i]);
}

答案 1 :(得分:0)

是的,虽然您希望取消注释if,并更改if&&而不是||相关联的条件(否则它将始终是真的 - 每个数字不等于零或不等于一个!)

存储在temp_struct[i]->prodi除了0,1和5之外的子字符串在substr函数内分配malloc,因此您可以而且应该取消分配他们与free

同样,每个temp_struct元素都分配了malloc,因此可以并且应该使用free取消分配。

我不确定你认为双免费会来自哪里。您是否在考虑在调用free(tmp_struct[i])tmp_struct[i]->prod指向的内存也将被释放?情况并非如此。当你释放指向包含指针的结构的指针时,结构指针本身的内存被释放(因为它是结构的一部分),但那些指针指向的内存不是,并且必须单独解除分配(因为它在结构外部)。除了if条件中的错误之外,你编写它的方式是正确的方法。

答案 2 :(得分:0)

子字符串不会占用额外的内存。它们是指向现有字符串部分的指针。

答案 3 :(得分:0)

是的,假设您的substr正在为malloc分配子字符串的内存,那么当您完成内存时,free内存是合理的(必要的)。也就是说,我认为你现在正在做的事情是非常脆弱和容易出错的(温和地说)。如果您有任何选择,我会以相同的方式为所有 prod成员分配字符串 - 如果您不能静态分配它们,那么动态分配它们,所以当你释放结构时,你可以统一地这样做。当且仅当动态分配时,试图确保您将下标与免费prod匹配,这实际上是在乞求麻烦。

答案 4 :(得分:0)

您还有其他问题。当你执行temp_struct[i]->prod = "Bar";时你正在为prod分配一个const char *。该指针无法释放(最可能的结果是崩溃)。因此,如果您希望以这种方式设置代码,使得prod可以指向您从malloc获得的动态内存或指向常量字符串文字,您还需要跟踪它是哪一个并且只释放动态内存

评论中的条件在技术上会起作用,但形式会非常糟糕。最好的想法是不要在同一个指针中混合和匹配字符串类型。但是如果你坚持这样做,那么改进就是在你的结构中添加另一个变量,当需要释放prod时设置为true,否则为false。