我在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;
}
所以,我不明白为什么我不能释放final_filenames数组然后释放images_filenames,因为它让我 * glibc检测到 ./ main:double free或corruption(!prev):0x0986d228 * *。
无论如何,如果您在此代码中看到不正确的内容,虽然它有效,但请随时指出。
答案 0 :(得分:3)
问题是你释放了一个可能已经被释放的指针,并且你不知道有多少空间正在使用没有指向最近分配空间的指针(一般情况下)所以你不能准确地释放内存。在main()
中,您有:
char **images_filenames;
[...]
if ((images_filenames = ((char**) malloc(10 * sizeof (char*)))) == NULL) {
[...]
if (readInputFile(fpin, images_filenames) == -1) {
[...]
deallocate2D(images_filenames, num_lines);
您分配10个字符指针,然后将该数组传递给readInputFile()
函数。在该函数内部,有重新分配数组的代码,但是您没有为主程序提供一种知道新地址是什么的方法。你这样做的方法是通过将指针传递给你想要修改的任何东西,或者让函数返回修改后的值(或者你采用肮脏的做法,比如使用全局变量而不是参数 - 但是你不应该这样做)。
所以,你需要:
if (readInputFile(fpin, &images_filenames) == -1) {
在readInputFile()
函数中,您需要进行大量更改 - 处理三指针参数的最大变化,然后是各种编码问题:
int readInputFile(FILE *fp, char ***ppp_files)
{
num_lines = 0;
int s = 10;
char line[MAX_LENGTH];
char **file_images = *ppp_files;
char **final_filenames;
更新:我没有注意到这只是初始化num_lines,而不是声明它。因此,num_lines必须是某种全局变量......下面的一些评论需要调整以允许这种情况。
到目前为止,这种变化(几乎)是微不足道的;我们得到一个指向'char **'的指针,因此是三指针参数。要简化以下代码,请在旧名称(file_images
)下创建参数的本地副本,并使用参数指向的值对其进行初始化。以下代码可以继续使用file_images
;只需确保在返回之前更新参数。
...除
你假设's = 10',但实际上,你应该让main函数告诉你有多少行可用。它确实分配了10行,但如果没有经过仔细审查就不清楚了。您应该让main()
程序说明预分配了多少行 - 该函数的额外参数。您还面临这样的问题:main()
程序无法告诉deallocate2D()
函数数组中有多少行,因为它不知道。目前尚不清楚你的代码如何编译;你在这里有一个局部变量num_lines
,但是在num_lines
中有一个变量main()
的引用没有声明。局部变量屏蔽任何全局变量。
while (fgets(line, sizeof line, fp) != NULL) {
if (line[0] != '\n') {
if (num_lines >= s) {
s += 100;
添加大量行是个好主意;它“分摊”重新分配的成本。
if ((file_images = (char**) realloc(file_images, s * sizeof (char*))) == NULL)
您使用的技术存在特定问题。
纯代码样式:当一行包含带有嵌入赋值的if
并且它太长时,在条件之前拆分该赋值:
file_images = (char**) realloc(file_images, s * sizeof (char*));
if (file_images == NULL)
现在只剩下一个微妙的错误。如果realloc()
失败,会发生什么......
没错,你已经泄露了内存,因为file_images
中的值为null,所以无法释放它曾经指向的内容。 从不写:
x = realloc(x, size);
故障时泄漏内存!因此,您需要:
char **new_space = realloc(file_images, s * sizeof (char*));
if (new_space == NULL)
{
printf("Error reallocating space for 2d array: %s\n",
strerror(errno));
*ppp_files = file_images;
return -1;
}
}
作为一般规则,错误消息应打印在stderr
;我没有解决这个问题。
请注意,我小心地将file_images
的最后一个(非空)值复制回主程序中的变量。也可能适合对大小进行相同的操作(另一个接口更改),或者使用结构来封装数组 - 大小和指向其基础的指针。
if ((file_images[num_lines] = malloc(MAX_LENGTH * sizeof (char))) == NULL)
{
printf("Error allocating space for 2d array: %s\n", strerror(errno));
return -1;
}
此错误返回需要设置*ppp_files = file_images;
。
strncpy(file_images[num_lines], line, MAX_LENGTH);
if (file_images[num_lines] == NULL) {
printf("Strncpy failed: %s\n", strerror(errno));
return -1;
}
这个测试很奇怪;您知道file_images[num_lines]
不为空,strncpy()
不会更改。您不需要测试和错误处理。
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
很好的触感。它几乎不值得;即使在64位机器上,你最多也浪费不到1 KiB。但是,整洁没有坏处 - 好。
if ((final_filenames = realloc(file_images, num_lines * sizeof (char*))) == NULL) {
printf("Error reallocating space for 2d array: %s\n", strerror(errno));
return -1;
同样,您需要在返回前设置*ppp_files = file_images;
。
} else {
file_images = final_filenames;
这不会影响main()
程序中的值。它需要再次*ppp_files = file_images;
。
deallocate2D(final_filenames, num_lines);
坚持 - 你释放所有精心分配的空间?所以你毕竟不打算使用它?上面的赋值只复制了一个指针值;它没有复制记忆......
}
return 0;
//don't forget to free lines 2d array! (here or at the end of the code)
}
此评论错误 - 成功返回后,内存已被解除分配。
Lemme guess - 你不要使用'vim'或其他'vi'衍生物进行编辑。在第1列中确实具有其功能的左大括号的人,因为这样您就可以使用“]]
”或“[[
”在文件中向前或向后跳转到下一个或上一个函数的开头。使用代码无法正常工作。
嗯,这是一个开始诊断......这是使用结构来传递文件名数组的工作代码。我使用从结构中复制的局部变量离开了readInputFile()
函数的主体,并确保结构始终正确更新。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
enum { MAX_LENGTH = 512 };
typedef struct FileNameArray
{
size_t nfiles; /* Number of file names allocated and in use */
size_t maxfiles; /* Number of entries allocated in array */
char **files; /* Array of file names */
} FileNameArray;
static void deallocate2D(FileNameArray *names)
{
for (size_t i = 0; i < names->nfiles; i++)
free(names->files[i]);
free(names->files);
names->nfiles = 0;
names->files = 0;
names->maxfiles = 0;
}
static int readInputFile(FILE *fp, FileNameArray *names)
{
int num_lines = names->nfiles;
int max_lines = names->maxfiles;
char **file_names = names->files;
char line[MAX_LENGTH];
char **final_filenames;
while (fgets(line, sizeof line, fp) != NULL)
{
if (line[0] != '\n')
{
/* Remove newline from end of file name */
char *nl = strchr(line, '\n');
if (nl != 0)
*nl = '\0';
if (num_lines >= max_lines)
{
max_lines += 100;
char **space = realloc(file_names, max_lines * sizeof (char*));
if (space == NULL)
{
fprintf(stderr, "Error reallocating space for 2d array: %s\n",
strerror(errno));
return -1;
}
names->maxfiles = max_lines;
names->files = space;
file_names = space;
}
if ((file_names[num_lines] = malloc(strlen(line) + 1)) == NULL)
{
fprintf(stderr, "Error allocating space for 2d array: %s\n",
strerror(errno));
return -1;
}
names->nfiles++;
strcpy(file_names[num_lines], line);
printf("name of file %d is: %s \n", num_lines, file_names[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_names, num_lines * sizeof (char*))) == NULL)
{
fprintf(stderr, "Error reallocating space for 2d array: %s\n",
strerror(errno));
return -1;
}
names->maxfiles = num_lines;
names->files = final_filenames;
return 0;
}
int main(int argc, char *argv[])
{
FileNameArray names = { 0, 0, 0 };
//check parameters
if (argc < 4)
{
fprintf(stderr, "Usage: %s input_filename.ppm charWidth charHeight\n",
argv[0]);
return -1;
}
printf("Opening input file [%s]\n", argv[1]);
FILE *fpin = fopen(argv[1], "r");
if (fpin == NULL) {
fprintf(stderr, "Could not open input file %s (%s)\n",
argv[1], strerror(errno));
return -1;
}
if ((names.files = malloc(10 * sizeof (char*))) == NULL)
{
fprintf(stderr, "Error allocating initial space for 2d array: %s\n",
strerror(errno));
return -1;
}
names.maxfiles = 10;
if (readInputFile(fpin, &names) == -1)
{
fprintf(stderr, "Error reading image filenames from input\n");
return -1;
}
fclose(fpin);
printf("###########\n");
deallocate2D(&names);
printf("Done!\n");
return 0;
}