free() on char* recognized as invalid by valgrind

huangapple go评论81阅读模式
英文:

free() on char* recognized as invalid by valgrind

问题

I am attempting to free char* pointers that exist within a char** array, but valgrind is determining this operation as invalid.

Here is a simple example of what I'm doing:

struct building{
  int propertyPrice;
  int totalArea;
  char** floors;
}

int main(){

  struct building* B = malloc(sizeof(struct building));

  for(size_t i=0;i<10;i++)
    B->floors[i] = malloc(20 * sizeof(char*));

}

Here's where I'm confused - I can access the elements with the following loop:

for(size_t i=0;i<10;i++)
    printf("%s", B->floors[i]); //assume that a valid string exists at each floors[i]!

I am attempting to free the allocated memory as follows:

for(size_t i=0;i<10;i++)
    free(B->floors[i]);

free(B);

Please excuse the lack of malloc() check against NULL, I'm cutting that out for brevity.

Valgrind determines that the operation free(B->floors[i]) is Invalid free() / delete / delete[] / realloc(). Yet, if I can access the individual char* elements through B-floors[i], shouldn't I be able to free it using the same syntax by just switching the function call from printf() to free() (I got the idea from this stackoverflow answer)?

The second free() call works perfectly fine.

My program is executing as expected, but I'd like to get rid of memory leaks - hence the usage of valgrind. If it's helpful, I'm using the -Werror -ggdb switches for gcc and the --track-origins=yes --leak-check=full arguments when executing valgrind.

英文:

I am attempting to free char* pointers that exist within a char** array, but valgrind is determining this operation as invalid.

Here is a simple example of what I'm doing:

struct building{
  int propertyPrice;
  int totalArea;
  char** floors;
}

int main(){

  struct building* B = malloc(sizeof(struct building));

  for(size_t i=0;i<10;i++)
    B->floors[i] = malloc(20 * sizeof(char*));

}

Here's where I'm confused - I can access the elements with the following loop:

for(size_t i=0;i<10;i++)
    printf("%s", B->floors[i]); //assume that a valid string exists at each floors[i]!

I am attempting to free the allocated memory as follows:

for(size_t i=0;i<10;i++)
    free(B->floors[i]);

free(B);

Please excuse the lack of malloc() check against NULL, I'm cutting that out for brevity.

Valgrind determines that the operation free(B->floors[i]) is Invalid free() / delete / delete[] / realloc(). Yet, if I can access the individual char* elements through B-floors[i], shouldn't I be able to free it using the same syntax by just switching the function call from printf() to free() (I got the idea from this stackoverflow answer)?

The second free() call works perfectly fine.

My program is executing as expected, but I'd like to get rid of memory leaks - hence the usage of valgrind. If it's helpful, I'm using the -Werror -ggdb switches for gcc and the --track-origins=yes --leak-check=full arguments when executing valgrind.

答案1

得分: 5

以下是翻译好的部分:

这里:

    for(size_t i=0;i<10;i++)
        B->floors[i] = malloc(20 * sizeof(char*));

`B->floors` 未经初始化。

您需要为10个元素预留空间:

    B->floors = malloc(10 * sizeof(char*));

然后您可以填充这个多维数组:

    for (int i = 0; i < 10; i++) {
        B->floors[i] = strdup(...); // 或者如果没有 strdup 可用,可以使用 malloc + memcpy
    }

最后:

    for (int i = 0; i < 10; i++) {
        free(B->floors[i]);
    }
    free(B->floors);

由于`floors`是数组的最后一个成员,您可以将其用作"柔性数组成员":

    struct building* B = malloc(sizeof(struct building) + (sizeof(char *) * 10));

在这种情况下,您不需要在最后调用 `free(B->floors);`。
英文:

Here:

for(size_t i=0;i&lt;10;i++)
    B-&gt;floors[i] = malloc(20 * sizeof(char*));

B-&gt;floors is used uninitialized.

You need to reserve space for 10 elements:

B-&gt;floors = malloc(10 * sizeof(char*));

then you can fill the jagged array:

for (int i = 0; i &lt; 10; i++) {
    B-&gt;floors[i] = strdup(...); // or malloc + memcpy if strdup is not available
}

finally:

for (int i = 0; i &lt; 10; i++) {
    free(B-&gt;floors[i]);
}
free(B-&gt;floors);

Since floors is the last member of the array you can use it as a "flexible array member":

struct building* B = malloc(sizeof(struct building) + (sizeof(char *) * 10));

in this case you don't call free(B-&gt;floors); at the end.

huangapple
  • 本文由 发表于 2023年8月4日 23:53:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76837481.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定