1

昨天我问了一个类似的问题,关于如何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;
}
4

5 回答 5

1

问题是有时您设置temp_struct[i]->prod为无法释放的带引号的字符串(“Bar”),有时设置为您必须释放的 substr 调用的结果。

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

  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]);
}
于 2010-07-07T16:07:35.663 回答
0

是的,尽管您将要取消注释if,并更改if要加入的条件,&&而不是||(否则它将始终为真——每个数字要么不等于 0,要么不等于 1!)

存储在0、1 和 5 之外的子字符串在函数内部使用 分配temp_struct[i]->prod,因此您可以并且应该使用 取消分配它们。isubstrmallocfree

同样,每个temp_struct元素都使用 分配malloc,因此可以而且应该使用 释放free

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

于 2010-07-07T16:03:36.570 回答
0

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

于 2010-07-07T16:04:45.520 回答
0

是的,鉴于您substr正在为带有 的子字符串分配内存,当您完成它时,该内存malloc是合理的(确实是必要的) 。free也就是说,我认为您现在做事的方式非常脆弱且容易出错(委婉地说)。如果你有任何选择,我会以同样的方式为所有成员分配字符串——如果prod你不能静态分配它们,然后动态分配它们,所以当你释放结构时,你可以做如此均匀。当且仅当它是动态分配时,试图确保您保持匹配的下标是免费prod的,实际上是在自找麻烦。

于 2010-07-07T16:06:46.330 回答
0

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

您评论中的条件在技术上可行,但形式很差。最好的办法是不要在同一个指针中混合和匹配字符串类型。但是,如果您坚持这样做,那么改进将是在您的结构中添加另一个变量,当 prod 需要被释放时设置为 true,而在不需要时设置为 false。

于 2010-07-07T16:07:37.077 回答