如何正确释放数组而不出现错误?
我在 @GWW 的帮助下想出了这段代码,现在我无法释放
char**
。
这是我的代码(它只是读取输入文件并在屏幕上打印其中的名称):
/* deallocate2D
corresponding function to dynamically deallocate 2-dimensional array using
* malloc.
* accepts a char** as the "array" to be allocated, and the number of rows.
* as with all dynamic memory allocation, failure to free malloc'ed memory
* will result in memory leaks
*/
void deallocate2D(char** array, int nrows) {
/* deallocate each row */
int i;
for (i = 0; i < nrows; i++) {
free(array[i]);
}
/* deallocate array of pointers */
free(array);
}
int readInputFile(FILE *fp, char **file_images) {
num_lines = 0;
int s = 10;
char line[MAX_LENGTH];
char **final_filenames;
while (fgets(line, sizeof line, fp) != NULL) /* read a line */ {
if (line[0] != '\n') {
if (num_lines >= s) {
s += 100;
if ((file_images = (char**) realloc(file_images, s * sizeof (char*))) == NULL) {
printf("Error reallocating space for 2d array: %s\n", strerror(errno));
return -1;
}
}
if ((file_images[num_lines] = malloc(MAX_LENGTH * sizeof (char))) == NULL) {
printf("Error allocating space for 2d array: %s\n", strerror(errno));
return -1;
}
strncpy(file_images[num_lines], line, MAX_LENGTH);
if (file_images[num_lines] == NULL) {
printf("Strncpy failed: %s\n", strerror(errno));
return -1;
}
printf("name of file %d is: %s \n", num_lines, file_images[num_lines]);
num_lines++;
}
}
printf("Num_lines: %d\n",num_lines);
//realloc to number of lines in the file, to avoid wasting memory
if ((final_filenames = realloc(file_images, num_lines * sizeof (char*))) == NULL) {
printf("Error reallocating space for 2d array: %s\n", strerror(errno));
return -1;
} else {
file_images = final_filenames;
deallocate2D(final_filenames, num_lines);
}
return 0;
//don't forget to free lines 2d array! (here or at the end of the code)
}
int main(int argc, char *argv[]) {
//pixel* image;
char **images_filenames;
//check parameters
if (argc < 4) {
printf("Incorrect usage.\nPlease use \"./invert input_filename.ppm charWidth charHeight \"\n");
return -1;
}
printf("Opening input file [%s]\n", argv[1]);
FILE *fpin = fopen(argv[1], "r");
if (fpin == NULL) {
printf("Could not open input file\n");
return -1;
}
if ((images_filenames = ((char**) malloc(10 * sizeof (char*)))) == NULL) {
printf("Error allocating initial space for 2d array: %s\n", strerror(errno));
return -1;
}
if (readInputFile(fpin, images_filenames) == -1) {
printf("Error reading image filenames from input\n");
return -1;
}
fclose(fpin);
printf("###########\n");
deallocate2D(images_filenames, num_lines);
printf("Done!\n");
return 0;
}
所以,我不明白为什么我不能 free
final_filenames
和images_filenames
。
这段代码给我的错误是:
*** glibc detected *** ./main: double free or corruption (!prev): 0x0986d228 ***
如何正确释放
我的数组而不出现错误?
I came up with this code with the help of @GWW and now I can't free
a char**
.
Here's my code (it just reads an input file and prints the names in it on the screen):
/* deallocate2D
corresponding function to dynamically deallocate 2-dimensional array using
* malloc.
* accepts a char** as the "array" to be allocated, and the number of rows.
* as with all dynamic memory allocation, failure to free malloc'ed memory
* will result in memory leaks
*/
void deallocate2D(char** array, int nrows) {
/* deallocate each row */
int i;
for (i = 0; i < nrows; i++) {
free(array[i]);
}
/* deallocate array of pointers */
free(array);
}
int readInputFile(FILE *fp, char **file_images) {
num_lines = 0;
int s = 10;
char line[MAX_LENGTH];
char **final_filenames;
while (fgets(line, sizeof line, fp) != NULL) /* read a line */ {
if (line[0] != '\n') {
if (num_lines >= s) {
s += 100;
if ((file_images = (char**) realloc(file_images, s * sizeof (char*))) == NULL) {
printf("Error reallocating space for 2d array: %s\n", strerror(errno));
return -1;
}
}
if ((file_images[num_lines] = malloc(MAX_LENGTH * sizeof (char))) == NULL) {
printf("Error allocating space for 2d array: %s\n", strerror(errno));
return -1;
}
strncpy(file_images[num_lines], line, MAX_LENGTH);
if (file_images[num_lines] == NULL) {
printf("Strncpy failed: %s\n", strerror(errno));
return -1;
}
printf("name of file %d is: %s \n", num_lines, file_images[num_lines]);
num_lines++;
}
}
printf("Num_lines: %d\n",num_lines);
//realloc to number of lines in the file, to avoid wasting memory
if ((final_filenames = realloc(file_images, num_lines * sizeof (char*))) == NULL) {
printf("Error reallocating space for 2d array: %s\n", strerror(errno));
return -1;
} else {
file_images = final_filenames;
deallocate2D(final_filenames, num_lines);
}
return 0;
//don't forget to free lines 2d array! (here or at the end of the code)
}
int main(int argc, char *argv[]) {
//pixel* image;
char **images_filenames;
//check parameters
if (argc < 4) {
printf("Incorrect usage.\nPlease use \"./invert input_filename.ppm charWidth charHeight \"\n");
return -1;
}
printf("Opening input file [%s]\n", argv[1]);
FILE *fpin = fopen(argv[1], "r");
if (fpin == NULL) {
printf("Could not open input file\n");
return -1;
}
if ((images_filenames = ((char**) malloc(10 * sizeof (char*)))) == NULL) {
printf("Error allocating initial space for 2d array: %s\n", strerror(errno));
return -1;
}
if (readInputFile(fpin, images_filenames) == -1) {
printf("Error reading image filenames from input\n");
return -1;
}
fclose(fpin);
printf("###########\n");
deallocate2D(images_filenames, num_lines);
printf("Done!\n");
return 0;
}
So, I don't understand why can't I free
final_filenames
and images_filenames
.
The error that this code gives me is:
*** glibc detected *** ./main: double free or corruption (!prev): 0x0986d228 ***
How do I correctly free
my arrays without errors?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是您正在释放一个可能已经被释放的指针,并且您
不知道正在使用多少空间没有指向最近分配的空间的指针(通常)所以你不能准确地释放内存。在main()
中,您:分配 10 个字符指针,然后将该数组传递给
readInputFile()
函数。在该函数内部,有重新分配数组的代码,但您没有提供主程序知道新地址是什么的方法。这样做的方法是要么传递一个指针到您想要修改的任何内容,要么让函数返回修改后的值(或者您采取肮脏的做法,例如使用全局变量而不是参数 - 但您不应该这样做)。因此,您需要:
在
readInputFile()
函数中,您需要进行大量更改 - 处理三指针参数的大更改,以及各种编码问题:更新:我没有注意到这只是初始化 num_lines,而不是声明它。因此,num_lines 必须是某种全局变量......下面的一些评论需要调整以允许这一点。
到目前为止,变化(几乎)微不足道;我们得到一个指向“char **”的指针,因此是三重指针参数。为了简化以下代码,请在旧名称 (
file_images
) 下创建参数的本地副本,并使用参数指向的值对其进行初始化。接下来的代码可以继续使用file_images
;只需确保在返回之前更新参数即可。除了...
您假设 s = 10',但实际上,您应该让 main 函数告诉您有多少行可用。它确实分配了 10 行,但如果不仔细检查的话,并不清楚情况是否如此。您应该让
main()
程序显示预先分配了多少行 - 函数的额外参数。您还面临这样的问题:main()
程序无法告诉deallocate2D()
函数数组中有多少行,因为它不知道。目前尚不清楚您的代码如何编译;这里有一个局部变量num_lines
,但在main()
中有一个对变量num_lines
的引用,但没有声明。局部变量屏蔽任何全局变量。添加大量行是个好主意;它“摊销”重新分配的成本。
不过,您使用的技术存在一些具体问题。
纯代码风格:当一行包含带有嵌入式赋值的
if
并且它变得太长时,请在条件之前将赋值拆分出来:现在只剩下一个微妙的错误。如果
realloc()
失败会发生什么...没错,你已经泄漏了内存,因为
file_images
中的值为空,所以没有办法释放它的内容用来指。 永远不要写:失败时会泄漏内存!因此,您需要:
作为一般规则,错误消息应打印在
stderr
上;我还没修好这个请注意,我小心地将
file_images
的最后一个(非空)值复制回主程序中的变量中。对大小也做同样的事情(另一个接口更改)可能是合适的,或者使用结构来封装数组 - 大小和指向其基数的指针。此错误返回需要设置
*ppp_files = file_images;
。这个测试很奇怪;您知道
file_images[num_lines]
不为 null,并且strncpy()
不会改变这一点。您不需要测试和错误处理。好的...
手感很好。这几乎不值得;即使在 64 位机器上,您最多浪费不到 1 KiB。不过,保持整洁也没什么坏处——很好。
同样,您需要在返回之前设置
*ppp_files = file_images;
。这不会影响
main()
程序中的值。它需要再次是*ppp_files = file_images;
。等等——你释放了所有精心分配的空间吗?所以你最终不会使用它吗?上面的赋值只是复制了一个指针值;它没有复制内存......
这个评论是错误的 - 成功返回后,内存已经被释放。
让我猜一下 - 你不使用“vim”或其他“vi”衍生词进行编辑。在第 1 列中确实有其函数的左大括号的人,因为这样您就可以使用 '
]]
' 或 '在文件中向前或向后跳转到下一个或上一个函数的开头>[[
'。处理不起作用的代码是令人厌烦的。嗯,这是一个开始的诊断...这是使用结构来转发文件名数组的工作代码。我使用从结构中复制的局部变量保留了 readInputFile() 函数的主体,并确保结构始终正确更新。
The problems are that you are freeing a pointer that may already have been freed, and you
don't know how much space is in usedon't have a pointer to the most recently allocated space (in general) so you can't free the memory accurately. Inmain()
, you have:You allocate 10 character pointers, and then pass that array to the
readInputFile()
function. Inside that function, there is code to reallocate the array, but you have not provided a way for the main program to know what that new address is. The way you do that is either by passing a pointer to whatever it is you want modified, or you have the function return the modified value (or you resort to sordid practices like using global variables instead of parameters - but you shouldn't do that).So, you need:
And in the
readInputFile()
function, you need a whole lot of changes - the big one to deal with the triple-pointer argument, and then a variety of coding problems:Update: I didn't notice that this was simply initializing num_lines, not declaring it. Thus, num_lines must be a global variable of some sort...some of the commentary below needs adjusting to allow for this.
So far, the change is (almost) trivial; we're getting a pointer to a 'char **', hence the triple pointer argument. To simplify the following code, make a local copy of the parameter under the old name (
file_images
) and initialized it with the value that the argument points at. Following code can then continue to work withfile_images
; just ensure that the argument is updated before returning.Except...
You assume that 's = 10', but really, you should have the main function tell you how many rows were available. It did allocate 10 rows, but it is not clear without careful scrutiny that was the case. You should have the
main()
program say how many rows were preallocated - an extra argument to the function. You also face the problem that themain()
program cannot tell thedeallocate2D()
function how many rows are in the array because it does not know. It is not clear how your code compiles; you have a local variablenum_lines
here, but there's a reference to a variablenum_lines
inmain()
for which there is no declaration. The local variable masks any global variable.Adding a large number of rows is a good idea; it 'amortizes' the cost of the reallocations.
There are specific problems with the technique you've used though.
Pure code style: when a line contains an
if
with an embedded assignment and it gets too long, split the assignment out before the condition:Now there's just a subtle bug left. What happens if
realloc()
fails...That's right, you've leaked the memory because the value in
file_images
is null, so there is no way to release what it used to point to. Never write:It leaks memory on failure! Hence, you need:
As a general rule, error messages should be printed on
stderr
; I haven't fixed this.Note that I carefully copied back the last (non-null) value of
file_images
into the variable in the main program. It might be appropriate to do the same with the size, too (another interface change), or use a structure to encapsulate the array - size and pointer to its base.This error return needs to set
*ppp_files = file_images;
.This test is odd; you know that
file_images[num_lines]
is not null, andstrncpy()
doesn't change that. You don't need the test and error handling.OK...
Nice touch. It is barely worth it; even on a 64-bit machine, you are wasting less than 1 KiB at most. However, no harm in being tidy - good.
Again, you need to set
*ppp_files = file_images;
before return.This does not affect the value in the
main()
program. It would need to be*ppp_files = file_images;
again.Hold on - you deallocate all your carefully allocated space? So you aren't going to use it after all? The assignment above merely copied a pointer value around; it did not make a copy of the memory...
This comment is wrong - on successful return, the memory is already deallocated.
Lemme guess - you don't use 'vim' or another 'vi' derivative for editing. People who do have the opening brace of their functions in column 1, because then you can jump forwards or backwards through the file to the start of the next or previous function using '
]]
' or '[[
'. It is irksome working with code where that does not work.Well, that's a starting diagnosis... Here's working code using a structure to relay the array of file names around. I've left the body of the
readInputFile()
function using local variables that are copied out of the structure, and ensured that the structure is properly updated at all times.