【问题标题】:freeing substring without doing double free in c释放子字符串而不在c中进行双重释放
【发布时间】:2010-07-07 15:58:03
【问题描述】:

昨天我问了一个类似的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;
}

【问题讨论】:

    标签: c free malloc substring


    【解决方案1】:

    问题在于,有时您将temp_struct[i]-&gt;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]);
    }
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            【解决方案5】:

            是的,尽管您希望取消注释 if,并将 if 中的条件更改为与 &amp;&amp; 而不是 || 连接(否则它将始终为真 - 每个数字都是不等于零或不等于一!)

            存储在temp_struct[i]-&gt;prod 中的i 的子字符串(除0、1 和5 之外)在substr 函数中分配为malloc,因此您可以并且应该使用free 释放它们。

            同样,每个temp_struct 元素都分配有malloc,因此可以而且应该使用free 解除分配。

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

            【讨论】:

            • 我在想,如果我不执行 if (i != 0 && i != 1 && i != 5) 那么我将释放我没有分配的东西,例如“ +"...但是谢谢这样更有意义!
            • 你肯定确实想要if在里面!只是它应该只包含第一个free,而第二个应该是无条件的。为 i=0,1,5 释放 tmp_struct[i] 没有问题,但如果您尝试为这些值释放 tmp_struct[i]-&gt;prod 则会出现问题。
            猜你喜欢
            • 2021-12-15
            • 1970-01-01
            • 2014-11-10
            • 2019-02-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多