这是我第一次使用Valgrind并且我在使用C编写的简单代码中找出问题时遇到了一些问题。所有这一切都是通过文件获取一些字符串,将它们反转然后将它们打印在另一个文件中(或者附加它们,如果我将程序中的字符“a”作为第三个参数传递给它。这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reverse(char*,int);
int main(int argc,char* argv[]) {
FILE *input, *output; char* s;
s=malloc(1024*sizeof(char));
if (argv[3]!=NULL && strcmp(argv[3],"a") == 0) output=fopen(argv[2],"a");
else output=fopen(argv[2],"w");
if((input=fopen(argv[1],"r")) == NULL) {
perror("File inesistente");
return -1;
}
while(fgets(s,1024,input)!=NULL) {
s = reverse(s,strlen(s));
fprintf(output,"%s\n",s);
}
free(s);
fclose(input);
fclose(output);
return 0;
}
char* reverse(char* c,int l) {
char* buf; int i; buf=malloc((l)*sizeof(char));
for(i=0; i<l-1; i++) {
buf[i]=c[l-2-i];
}
buf[l-1]='\0';
return buf;
}
这就是Valgrind告诉我的事情:
==2768== Memcheck, a memory error detector
==2768== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2768== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==2768== Command: ./tokfile input.txt output.txt
==2768==
==2768== Invalid write of size 2
==2768== at 0x4C2FF2B: __GI_memcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x4EA6FA3: _IO_getline_info (iogetline.c:105)
==2768== by 0x4EA5E35: fgets (iofgets.c:56)
==2768== by 0x40083D: main (tokfile.c:17)
==2768== Address 0x51fc9d2 is 2 bytes inside a block of size 3 alloc'd
==2768== at 0x4C2ABA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x40087D: reverse (tokfile.c:27)
==2768== by 0x40080A: main (tokfile.c:18)
==2768==
==2768== Invalid write of size 1
==2768== at 0x4C2FF63: __GI_memcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x4EA6FA3: _IO_getline_info (iogetline.c:105)
==2768== by 0x4EA5E35: fgets (iofgets.c:56)
==2768== by 0x40083D: main (tokfile.c:17)
==2768== Address 0x51fc9d4 is 1 bytes after a block of size 3 alloc'd
==2768== at 0x4C2ABA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x40087D: reverse (tokfile.c:27)
==2768== by 0x40080A: main (tokfile.c:18)
==2768==
==2768== Invalid write of size 1
==2768== at 0x4EA5EA2: fgets (iofgets.c:64)
==2768== by 0x40083D: main (tokfile.c:17)
==2768== Address 0x51fc9d5 is 2 bytes after a block of size 3 alloc'd
==2768== at 0x4C2ABA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x40087D: reverse (tokfile.c:27)
==2768== by 0x40080A: main (tokfile.c:18)
==2768==
==2768== Invalid read of size 1
==2768== at 0x4C2E134: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x4007FA: main (tokfile.c:18)
==2768== Address 0x51fc9d3 is 0 bytes after a block of size 3 alloc'd
==2768== at 0x4C2ABA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x40087D: reverse (tokfile.c:27)
==2768== by 0x40080A: main (tokfile.c:18)
==2768==
==2768== Invalid read of size 1
==2768== at 0x4008AB: reverse (tokfile.c:29)
==2768== by 0x40080A: main (tokfile.c:18)
==2768== Address 0x51fc9d3 is 0 bytes after a block of size 3 alloc'd
==2768== at 0x4C2ABA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x40087D: reverse (tokfile.c:27)
==2768== by 0x40080A: main (tokfile.c:18)
==2768==
==2768==
==2768== HEAP SUMMARY:
==2768== in use at exit: 1,044 bytes in 5 blocks
==2768== total heap usage: 7 allocs, 2 frees, 2,180 bytes allocated
==2768==
==2768== 20 bytes in 4 blocks are definitely lost in loss record 1 of 2
==2768== at 0x4C2ABA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x40087D: reverse (tokfile.c:27)
==2768== by 0x40080A: main (tokfile.c:18)
==2768==
==2768== 1,024 bytes in 1 blocks are definitely lost in loss record 2 of 2
==2768== at 0x4C2ABA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2768== by 0x40074E: main (tokfile.c:10)
==2768==
==2768== LEAK SUMMARY:
==2768== definitely lost: 1,044 bytes in 5 blocks
==2768== indirectly lost: 0 bytes in 0 blocks
==2768== possibly lost: 0 bytes in 0 blocks
==2768== still reachable: 0 bytes in 0 blocks
==2768== suppressed: 0 bytes in 0 blocks
==2768==
==2768== For counts of detected and suppressed errors, rerun with: -v
==2768== ERROR SUMMARY: 17 errors from 7 contexts (suppressed: 0 from 0)
我想我以错误的方式分配内存? fgets有什么问题吗? 谢谢。
答案 0 :(得分:1)
写入字节错误:
你的反向弦太短了。由于空字符串终止符,您必须在reverse
中为已分配的缓冲区添加1。
这不是真正的valgrind问题(除了结果是错误的),但是由于你不这样做,在某些时候你的索引是错误的。例如,如果您尝试反转空字符串,
malloc
零字节,这是依赖于实现的:它返回NULL
(写入时是KABOOM)或指向不应该写入的东西(!)=&gt ;几乎没用。buf[l-1]='\0';
所以你在缓冲区之前写了1个字节。 第二部分:
由于已分配s
,因此执行此操作:
s=reverse(s,strlen(s));
给出了内存泄漏,因为你在reverse
中分配了一个新字符串并且你返回它,覆盖了之前分配的s
指针(你丢失了引用,但你没有释放它)< / p>
最终解释了“记忆丢失”的消息。
编辑:正如osgx评论的那样,这也是无效内存写入的来源:除非文件中字符串的大小是常量/增加,否则返回的缓冲区可能太短。我建议您使用就地反向算法,这样可以节省reverse
例程中的分配。另外,不要通过strlen(s)
。您可以在日常工作中计算长度。
我编写了一个快速的就地实现,避免了例程中的malloc
(修改字符串并返回它以方便/打印)
const char *reverse(char *s)
{
char temp;
int i;
int len=strlen(s);
for (i=0;i<len/2;i++)
{
temp = s[i];
s[i] = s[len-i-1];
s[len-i-1] = temp;
}
return s;
}