【问题标题】:How can I free an array of pointers where each pointer points to an address of a string which I allocated inside of a function?如何释放一个指针数组,其中每个指针指向我在函数内部分配的字符串的地址?
【发布时间】:2021-02-17 02:08:25
【问题描述】:

如何释放一个指针数组,其中每个指针指向我在函数内部分配的字符串的地址?

我在main 中创建了一个简单的指针数组*pointers[],并将它传递给readline,它会返回我已阅读的行数。

这样做的目的是存储由'\n'分隔的输入的所有行。每行存储在指针数组中的一个指针中。

所以在调用readline 并返回后,我可以printf("%s", pointers[0]) 显示用户输入的第一行。

我为数组中的每个指针分配一行的方式是在readline 内部,方法是分配一个char 指针*p,使其具有MAXLENGTH 大小并将p 的当前地址传递给相应的指针。每次赋值完成后,我跳转到下一个空闲地址p。

最后,我的问题是,在 readline 例程完成并打印所有存储的行之后,我是否必须释放(以及如何)我的指针数组。

我将把main 和readline 这两个函数留给你。

#define NUMOFLINES 5
#define MAXLENGTH 1000

void main(void) {
    char *pointers[NUMOFLINES]; // Array of pointers to string
    int nlines;                 // Number of pointers read

    nlines = readlines(pointers);
    writelines(pointers, nlines);
    
/* FAILED ATTEMPT TO FREE THE ARRAY OF POINTERS */
    for(int i = 0 ; i < nlines ; i++)
        free(pointers[i]);
}

int readlines(char *pointers[]) {
    char line[MAXLENGTH];
    char *p;

    int iptr, len;
    
    /* ALLOCATE P */
    p = malloc(sizeof(char) * MAXLENGTH); 

    for(iptr = 0 ; iptr < NUMOFLINES && (len = get_line(line)) > 0 ; iptr++) 
    {               
        strcpy(p, line);    // copy the line to the array, ending in len-th position
        pointers[iptr] = p; // Pass current adress 'p' to the respectively index of pointers
        p += len+1;         // Next free adress in array p
    }

    return iptr;
}

如你所见,我试图通过遍历每个指针并调用 free(pointer[i] 来释放,但我得到的只是

malloc(): corrupted top size
Aborted (core dumped)

我需要打电话给free吗?

提前致谢。

【问题讨论】:

  • malloc() 在循环外完成一次。但是您正在免费使用NUMOFLINES 倍。我也不太明白p += len+1; 的目的。
  • 我编辑了这个问题,解释说在我得到一行后,我将该行存储在数组内的指针中,然后通过执行 p = len+1 跳转到 p 内的下一个可用空间。请注意,len 来自“length”,即输入行的长度。 p 这里只是一种缓冲区,我存储了由\0 分隔的所有行。它可能不是完美的代码,我知道,但只是为了练习,因为我还在学习要领。
  • 只做if ( nlines &gt; 0 ) free(pointers[0]); 而不是循环。在函数中,您还应该检查不超过分配的空间大小
  • 你能澄清你的答案吗?如果我这样做free(pointers[0]) 它会释放所有指针?
  • @spiazzy free 释放内存块,而不是指针本身。你只有一个内存块。

标签: c pointers


【解决方案1】:

您只拨打了 1 次 malloc(),但您拨打了多次 free()。数组中的每个char* 都指向单个malloc() ed 内存块。您只能在该块的起始地址上调用free() 1 次。在块内的地址上调用free() 是未定义的行为。

此外,假设get_line() 输出的每个字符串最多可达MAXLENGTH 字符,那么您使用malloc() 分配的内存块还不够大。您只为 1 单行的最大长度分配了足够的内存,因此,一旦您的读取循环将 MAXLENGTH 字符复制到分配的块中,您就会将 p 指针推进到块的边界之外,从而导致后续strcpy()'s 写入并破坏随机内存。

如果您想保留单个 malloc() 并对其进行细分,请尝试类似这样的操作:

#define NUMOFLINES 5
#define MAXLENGTH 1000

int main(void) {
    char *pointers[NUMOFLINES], *buffer;

    int nlines = readlines(pointers, &buffer);
    if (nlines < 0) return -1;

    writelines(pointers, nlines);    

    free(buffer);
    return 0;
}

int readlines(char *pointers[], char **buffer) {
    *buffer = malloc(sizeof(char) * (NUMOFLINES * MAXLENGTH));
    if (*buffer == NULL) return -1;

    int iptr, len;
    char *p = *buffer;
    
    for(iptr = 0; (iptr < NUMOFLINES) && ((len = get_line(p)) > 0); ++iptr) 
    {               
        pointers[iptr] = p;
        p += len + 1;
    }

    return iptr;
}

否则,我建议你为数组中的每个指针分配一个单独的缓冲区,例如:

#define NUMOFLINES 5
#define MAXLENGTH 1000

int main(void) {
    char *pointers[NUMOFLINES];

    int nlines = readlines(pointers);
    if (nlines < 0) return -1;

    writelines(pointers, nlines);
    
    for(int i = 0; i < nlines; ++i)
        free(pointers[i]);

    return 0;
}

int readlines(char *pointers[]) {
    char line[MAXLENGTH], *p;
    int iptr, len;

    for(iptr = 0; (iptr < NUMOFLINES) && ((len = get_line(line)) > 0); ++iptr)
    {               
        p = malloc(sizeof(char) * (len + 1));
        if (p == NULL) {
            for(int j = 0; j < iptr; ++j) free(pointers[j]);
            return -1;
        }

        memcpy(p, line, sizeof(char) * len);
        p[len] = '\0';
        pointers[iptr] = p;
    }

    return iptr;
}

【讨论】:

  • 该函数将每个字符串连续放在同一个缓冲区中,由空终止符分隔。指针指向每个字符串(并非全部指向缓冲区的开头)
  • @M.M 我知道函数在做什么。我已经更新了我的答案以更好地反映这一点。
【解决方案2】:

你只调用一次malloc,所以你应该只调用一次free。

readlines 返回后,pointers[0] 指向您分配的内存的开头,而剩余的数组成员指向同一内存块内 的某个位置。这意味着只有一个指向 free 的指针。

所以不要这样:

for(int i = 0 ; i < nlines ; i++)
    free(pointers[i]);

这样做:

free(pointers[0]);

重申一下,您应该只向free 传递从malloc(或realloc 或calloc)返回的指针值。

【讨论】:

  • 所以,如果我理解正确:如果pointers[0] 指向我在函数内部分配的内存空间的开头,我只需调用free 到该内存空间的开头(在这个案子pointers[0]),对吗?一个额外的问题,如果你不介意,我需要做free(pointers)之后?
  • @spiazzy 没错。不,您不需要free(pointers),因为它是main 函数的本地数组,而不是指向已分配内存的指针。
  • 说得非常有道理,而且比我想象的要简单得多,我会强调你的答案,谢谢你
【解决方案3】:

您不需要释放您在缓冲区中维护的其他指针。如果你做一个

p = malloc(sizeof(char) * MAXLENGTH); 

那么你需要一个

free(p);

malloc 和 free 必须完全一对一匹配,并且使用相同的地址调用。

既然你想修改p,你应该这样做:

char* original = malloc(sizeof(char) * MAXLENGTH);
p = original;

并且,一旦完成:

free(original)

【讨论】:

  • 我明白了。但是如果我释放(原始)我无法打印所有行,因为我释放了指针指向的内容,对吧?
  • free(original) 将是一个错误,因为调用者有一堆悬空指针
  • 只有在打印完内存后才能释放
  • @Jeffrey 打印发生在readlines 返回之后,因此original 将不再存在。 (假设您的建议是在 readlines 内声明 char* original - 如果不是这种情况,请澄清您的答案)
猜你喜欢
  • 2011-06-11
  • 2017-08-23
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 2013-01-16
  • 2014-08-13
  • 2023-03-13
  • 2018-10-17
相关资源
最近更新 更多