Valgrind 修复内存泄漏
Valgrind to fix memory leaks
我有一个程序,我正在阅读一个包含 30,000 个数字的文本文件,这些数字被 space 分隔(每行 5 个)。当我 运行 程序时,有时它可以工作,但有时它不工作(段错误),我认为这意味着我有内存泄漏。
我有以下内容:
int main(int argc, char const *argv[])
{
char input[256];
char buffer[30000];
char **nums = NULL;
nums = malloc(sizeof(char) * 30000);
char *token;
int counter = 0;
FILE *fp;
fp = fopen("textfile.txt","r");
fgets(input,sizeof(input),stdin);
while (fgets(buffer,sizeof(buffer),fp) != NULL)
{
token = strtok(buffer," ");
nums[counter] = malloc(sizeof(char) * 50);
while (token != NULL)
{
if (strlen(token) > 1)
{
strcpy(nums[counter],token);
counter++;
}
token = strtok(NULL," ");
}
}
for (int x = 0; x < 30000;x++)
{
free(nums[x]);
}
free(nums);
fclose(fp);
return 0;
}
我正在 运行宁 valgrind 尝试调试,但我在读取输出时遇到问题。有人能告诉我哪里错了吗?
==24368== Use of uninitialised value of size 8
==24368== at 0x4C2588C: strcpy (mc_replace_strmem.c:311)
==24368== by 0x400820: main (in /home/a.out)
==24368==
==24368== Invalid write of size 1
==24368== at 0x4C2588C: strcpy (mc_replace_strmem.c:311)
==24368== by 0x400820: main (in /home/a.out)
==24368== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==24368==
nums = malloc(sizeof(char) * 30000);
不会在数字上保留 30000 个指针。尺寸太小,应该是:
nums = malloc(sizeof(char*) * 30000);
撇开,而不是做:
token = strtok(buffer," ");
nums[counter] = malloc(sizeof(char) * 50);
你应该做的:
token = strtok(buffer," ");
nums[counter] = malloc(strlen(token)+1);
所以你为每个token分配合适的内存量(不要太多,也不要太少),注意sizeof(char)
总是1,所以省略。
如果您使用调试符号进行编译,通常使用 -g
,那么 valgrind 将在其输出中包含文件和行号,使其更容易理解。
,您的 while 循环包含更多内容。
while (fgets(buffer,sizeof(buffer),fp) != NULL)
{
token = strtok(buffer," ");
nums[counter] = malloc(sizeof(char) * 50);
您一直在为 nums[counter]
分配内存,但是...
while (token != NULL)
{
if (strlen(token) > 1)
{
strcpy(nums[counter],token);
counter++;
你只是有时增加 counter
。你会泄漏很多内存。
您还要将最多 29998 字节的 token
复制到只有 50 字节的 nums[counter]
。
}
token = strtok(NULL," ");
}
}
相反,根据需要分配 nums[counter]
,大小合适。
while (fgets(buffer,sizeof(buffer),fp) != NULL)
{
token = strtok(buffer," ");
while (token != NULL)
{
if (strlen(token) > 1)
{
nums[counter] = malloc(sizeof(char) * (strlen(token) + 1));
strcpy(nums[counter],token);
counter++;
}
token = strtok(NULL," ");
}
}
或者,如果您不介意使用 POSIX 函数,请使用 strdup
。
nums[counter] = strdup(token);
而且,正如其他人在评论中指出的那样,为什么要将数字存储为字符串是值得怀疑的。使用 strtol
或 strtod
立即将它们转换为数字并存储。它更简单并且消耗更少的内存。
long nums[30000];
...
char *end;
nums[counter] = strtol(token, &end, 10);
if( end != '[=15=]' ) {
fprintf(stderr, "Couldn't understand %s\n", token);
}
end
是指向 token
上 strtol
停止解析的位置的指针。检查它是否为空字节要求 token
必须仅包含数字。您希望对转换的严格程度取决于您。
我有一个程序,我正在阅读一个包含 30,000 个数字的文本文件,这些数字被 space 分隔(每行 5 个)。当我 运行 程序时,有时它可以工作,但有时它不工作(段错误),我认为这意味着我有内存泄漏。
我有以下内容:
int main(int argc, char const *argv[])
{
char input[256];
char buffer[30000];
char **nums = NULL;
nums = malloc(sizeof(char) * 30000);
char *token;
int counter = 0;
FILE *fp;
fp = fopen("textfile.txt","r");
fgets(input,sizeof(input),stdin);
while (fgets(buffer,sizeof(buffer),fp) != NULL)
{
token = strtok(buffer," ");
nums[counter] = malloc(sizeof(char) * 50);
while (token != NULL)
{
if (strlen(token) > 1)
{
strcpy(nums[counter],token);
counter++;
}
token = strtok(NULL," ");
}
}
for (int x = 0; x < 30000;x++)
{
free(nums[x]);
}
free(nums);
fclose(fp);
return 0;
}
我正在 运行宁 valgrind 尝试调试,但我在读取输出时遇到问题。有人能告诉我哪里错了吗?
==24368== Use of uninitialised value of size 8
==24368== at 0x4C2588C: strcpy (mc_replace_strmem.c:311)
==24368== by 0x400820: main (in /home/a.out)
==24368==
==24368== Invalid write of size 1
==24368== at 0x4C2588C: strcpy (mc_replace_strmem.c:311)
==24368== by 0x400820: main (in /home/a.out)
==24368== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==24368==
nums = malloc(sizeof(char) * 30000);
不会在数字上保留 30000 个指针。尺寸太小,应该是:
nums = malloc(sizeof(char*) * 30000);
撇开,而不是做:
token = strtok(buffer," ");
nums[counter] = malloc(sizeof(char) * 50);
你应该做的:
token = strtok(buffer," ");
nums[counter] = malloc(strlen(token)+1);
所以你为每个token分配合适的内存量(不要太多,也不要太少),注意sizeof(char)
总是1,所以省略。
如果您使用调试符号进行编译,通常使用 -g
,那么 valgrind 将在其输出中包含文件和行号,使其更容易理解。
while (fgets(buffer,sizeof(buffer),fp) != NULL)
{
token = strtok(buffer," ");
nums[counter] = malloc(sizeof(char) * 50);
您一直在为 nums[counter]
分配内存,但是...
while (token != NULL)
{
if (strlen(token) > 1)
{
strcpy(nums[counter],token);
counter++;
你只是有时增加 counter
。你会泄漏很多内存。
您还要将最多 29998 字节的 token
复制到只有 50 字节的 nums[counter]
。
}
token = strtok(NULL," ");
}
}
相反,根据需要分配 nums[counter]
,大小合适。
while (fgets(buffer,sizeof(buffer),fp) != NULL)
{
token = strtok(buffer," ");
while (token != NULL)
{
if (strlen(token) > 1)
{
nums[counter] = malloc(sizeof(char) * (strlen(token) + 1));
strcpy(nums[counter],token);
counter++;
}
token = strtok(NULL," ");
}
}
或者,如果您不介意使用 POSIX 函数,请使用 strdup
。
nums[counter] = strdup(token);
而且,正如其他人在评论中指出的那样,为什么要将数字存储为字符串是值得怀疑的。使用 strtol
或 strtod
立即将它们转换为数字并存储。它更简单并且消耗更少的内存。
long nums[30000];
...
char *end;
nums[counter] = strtol(token, &end, 10);
if( end != '[=15=]' ) {
fprintf(stderr, "Couldn't understand %s\n", token);
}
end
是指向 token
上 strtol
停止解析的位置的指针。检查它是否为空字节要求 token
必须仅包含数字。您希望对转换的严格程度取决于您。