释放 C 中的动态字符串/行数组
Freeing array of dynamic strings / lines in C
我正在编写一个程序,用于对输入文本文件中的行进行排序。它完成了它的工作,但是我使用 valgrind 得到了内存泄漏。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getline(FILE * infile)
{
int size = 1024;
char * line = (char*)malloc(size);
int temp;
int i=0;
do
{
(temp = fgetc(infile));
if (temp !=EOF)
line[i++]=(char)temp;
if (i>=size)
{
size*=2;
line = (char*)realloc(line, size);
}
}while (temp != '\n' && temp !=EOF);
if (temp==EOF)
return NULL;
return line;
}
void print_line (char * line)
{
printf("%s", line);
}
int myCompare (const void * a, const void * b )
{
const char *pa = *(const char**)a;
const char *pb = *(const char**)b;
return strcmp(pa,pb);
}
int main (int argc, char* argv[])
{
FILE * infile;
FILE * outfile;
infile = fopen(argv[1], "r");
if (infile==NULL)
{
printf("Error");
exit(3);
}
outfile = fopen(argv[2], "w");
if (outfile==NULL)
{
printf("Error");
exit(3);
}
char * line;
char **all_lines;
int nlines=0;
while((line=getline(infile))!=NULL)
{
print_line(line);
nlines++;
}
all_lines=malloc(nlines*sizeof(char*));
rewind(infile);
int j=0;
printf("%d\n\n", nlines);
while((line=getline(infile))!=NULL)
{
all_lines[j]=line;
j++;
}
qsort(all_lines, nlines, sizeof(char*), myCompare);
for (int i=0; i<nlines;i++)
{
print_line(all_lines[i]);
fprintf(outfile, "%s", all_lines[i]);
}
for(int i =0; i<nlines;i++)
{
free(all_lines[i]);
}
free(all_lines);
fclose(infile);
fclose(outfile);
return 0;
}
他们可能来自哪里的任何想法?我遍历 all_lines[] 并释放内容,然后释放 all_lines 本身。
更新:
好的,我已经完成了您建议的更新。但是,现在 valgrind 在我的程序中为函数 fprintf 抛出错误。这是它所说的:
11 errors in context 2 of 2:
==3646== Conditional jump or move depends on uninitialised value(s)
==3646== at 0x40BA4B1: vfprintf (vfprintf.c:1601)
==3646== by 0x40C0F7F: printf (printf.c:35)
==3646== by 0x80487B8: print_line (sort_lines.c:44)
==3646== by 0x804887D: main (sort_lines.c:77)
==3646== Uninitialised value was created by a heap allocation
==3646== at 0x4024D12: realloc (vg_replace_malloc.c:476)
==3646== by 0x8048766: getline (sort_lines.c:30)
==3646== by 0x804889A: main (sort_lines.c:75)
我想知道为什么它会在将这些行简单地 fprintf 到文本文件时报告错误。我查了一下这是关于 gcc 优化将 fprint 变成 fputs 但我不明白这个想法
您的代码中存在多个问题:
函数getline
:
line
缓冲区中的字符串在 do / while
循环结束时未正确 '[=12=]'
终止。
- 它不会
free
在文件结束时 line
缓冲区,因此 内存泄漏 。
- 如果文件不以
'\n'
结束,它不会 return 在文件末尾的部分行。
malloc
和 realloc
return 值均未检查内存分配失败。
- 您应该
realloc
line
到实际使用的大小以减少消耗的内存量。目前,您每行至少分配 1024 个字节。对字典进行排序将需要 100 倍 的内存!
函数MyCompare
:
读取的行在末尾包含 '\n'
。比较可能会产生意想不到的结果:"Hello\tworld\n"
会出现在 "Hello\n"
之前。您应该删除 getline
中的 '\n'
并适当修改 printf
格式。
函数main
:
- 在尝试使用
fopen
打开它们之前,您没有检查是否实际提供了命令行参数,调用未定义的行为
- 第一个计算行数的循环没有
free
由getline
编辑的行return...大内存泄漏!
- 输入流不能总是
rewind
ed。如果您的程序通过管道获得输入,rewind
将失败,除非输入非常小。
- 如果文件被另一个进程异步修改,则第二个循环中读取的行数可能与第一个循环中计数的行数不同。如果文件变大,则在加载它时调用未定义的行为,如果文件缩小,则在对数组排序时调用未定义的行为。您应该在单个循环中读取行时重新分配
all_lines
数组。
在排序前打印行不是很有用并且会使测试复杂化。
我正在编写一个程序,用于对输入文本文件中的行进行排序。它完成了它的工作,但是我使用 valgrind 得到了内存泄漏。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getline(FILE * infile)
{
int size = 1024;
char * line = (char*)malloc(size);
int temp;
int i=0;
do
{
(temp = fgetc(infile));
if (temp !=EOF)
line[i++]=(char)temp;
if (i>=size)
{
size*=2;
line = (char*)realloc(line, size);
}
}while (temp != '\n' && temp !=EOF);
if (temp==EOF)
return NULL;
return line;
}
void print_line (char * line)
{
printf("%s", line);
}
int myCompare (const void * a, const void * b )
{
const char *pa = *(const char**)a;
const char *pb = *(const char**)b;
return strcmp(pa,pb);
}
int main (int argc, char* argv[])
{
FILE * infile;
FILE * outfile;
infile = fopen(argv[1], "r");
if (infile==NULL)
{
printf("Error");
exit(3);
}
outfile = fopen(argv[2], "w");
if (outfile==NULL)
{
printf("Error");
exit(3);
}
char * line;
char **all_lines;
int nlines=0;
while((line=getline(infile))!=NULL)
{
print_line(line);
nlines++;
}
all_lines=malloc(nlines*sizeof(char*));
rewind(infile);
int j=0;
printf("%d\n\n", nlines);
while((line=getline(infile))!=NULL)
{
all_lines[j]=line;
j++;
}
qsort(all_lines, nlines, sizeof(char*), myCompare);
for (int i=0; i<nlines;i++)
{
print_line(all_lines[i]);
fprintf(outfile, "%s", all_lines[i]);
}
for(int i =0; i<nlines;i++)
{
free(all_lines[i]);
}
free(all_lines);
fclose(infile);
fclose(outfile);
return 0;
}
他们可能来自哪里的任何想法?我遍历 all_lines[] 并释放内容,然后释放 all_lines 本身。
更新:
好的,我已经完成了您建议的更新。但是,现在 valgrind 在我的程序中为函数 fprintf 抛出错误。这是它所说的:
11 errors in context 2 of 2:
==3646== Conditional jump or move depends on uninitialised value(s)
==3646== at 0x40BA4B1: vfprintf (vfprintf.c:1601)
==3646== by 0x40C0F7F: printf (printf.c:35)
==3646== by 0x80487B8: print_line (sort_lines.c:44)
==3646== by 0x804887D: main (sort_lines.c:77)
==3646== Uninitialised value was created by a heap allocation
==3646== at 0x4024D12: realloc (vg_replace_malloc.c:476)
==3646== by 0x8048766: getline (sort_lines.c:30)
==3646== by 0x804889A: main (sort_lines.c:75)
我想知道为什么它会在将这些行简单地 fprintf 到文本文件时报告错误。我查了一下这是关于 gcc 优化将 fprint 变成 fputs 但我不明白这个想法
您的代码中存在多个问题:
函数getline
:
line
缓冲区中的字符串在do / while
循环结束时未正确'[=12=]'
终止。- 它不会
free
在文件结束时line
缓冲区,因此 内存泄漏 。 - 如果文件不以
'\n'
结束,它不会 return 在文件末尾的部分行。 malloc
和realloc
return 值均未检查内存分配失败。- 您应该
realloc
line
到实际使用的大小以减少消耗的内存量。目前,您每行至少分配 1024 个字节。对字典进行排序将需要 100 倍 的内存!
函数MyCompare
:
读取的行在末尾包含 '\n'
。比较可能会产生意想不到的结果:"Hello\tworld\n"
会出现在 "Hello\n"
之前。您应该删除 getline
中的 '\n'
并适当修改 printf
格式。
函数main
:
- 在尝试使用
fopen
打开它们之前,您没有检查是否实际提供了命令行参数,调用未定义的行为 - 第一个计算行数的循环没有
free
由getline
编辑的行return...大内存泄漏! - 输入流不能总是
rewind
ed。如果您的程序通过管道获得输入,rewind
将失败,除非输入非常小。 - 如果文件被另一个进程异步修改,则第二个循环中读取的行数可能与第一个循环中计数的行数不同。如果文件变大,则在加载它时调用未定义的行为,如果文件缩小,则在对数组排序时调用未定义的行为。您应该在单个循环中读取行时重新分配
all_lines
数组。
在排序前打印行不是很有用并且会使测试复杂化。