我的CLI程序在windows上编译并运行良好。在linux上编译良好,但在运行时会导致分段错误。
我向stackoverflow寻求帮助,发现了一些类似于我要问的问题,建议使用valgrind,我只是碰巧安装了它(哇!(。
因此,我通过valgrind运行了我的程序,得到了令人沮丧的大量输出,但我将从第一条错误消息开始:
==11951== Command: ./vt
==11951==
Loading...
Load default database? (y/n)y
Opened input file vtdb.~sv, reading contents...
==11951== Invalid write of size 1
==11951== at 0x400FA9: readnumberfromfile (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951== by 0x400C21: getrecordsfromfile (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951== by 0x401FFD: main (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951== Address 0x53b05bb is 0 bytes after a block of size 11 alloc'd
==11951== at 0x4C28FAC: malloc (vg_replace_malloc.c:236)
==11951== by 0x400EAC: readnumberfromfile (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951== by 0x400C21: getrecordsfromfile (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951== by 0x401FFD: main (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951==
...finished.
1180 entries read from vtdb.~sv.
问题似乎在readnumberfromfile
中,我已经仔细查看了它,但似乎找不到它出了什么问题!
有人能透露一些信息吗?
int readnumberfromfile (int maxvalue,char separator)
{
int number, i=0;
char ch;
char * buff = (char *)malloc(11);//allocate enough space for an 10-digit number and a terminating null
if (!buff) {printf("Memory allocation failed!n");return 0;}//return 0 and print error if alloc failed
if (!maxvalue) maxvalue=MAXINTVALUE;
ch=getc(inputfile);
while (!isdigit(ch))
{
if (ch == separator||ch=='n'||ch==EOF) {fprintf(stderr,"Format error in filen");return 0;}//if no number found(reached separator before digit), print error and return 0
ch = getc(inputfile);//cycle forward until you reach a digit
}
while (i<11 && ch!=separator && ch!='n')//stop when you reach '~', end of line, or when number too long
{
buff[i++]=ch;
ch = getc(inputfile); //copy number from file to buff, one char at a time
}
buff[i] = ' ';//terminate string
number = atoi(buff)<=maxvalue ? atoi(buff) : maxvalue;//convert string to number and make sure it's in range
free(buff);
return number;
}
这是从getrecordsfromfile
调用的,如果有任何用处的话:
void getrecordsfromfile(char * inputfilename,char separator)
{
int counter = 0;
struct vocab * newvocab;
struct listinfo * newvocablist;
if (!(inputfile = fopen(inputfilename, "r")))
{
printf("Unable to read input file. File does not exist or is in use.n");
}
else
{
printf("Opened input file %s, reading contents...n",inputfilename);
while (!feof(inputfile))
{
newvocab = (struct vocab *)malloc(sizeof(struct vocab));
if (!newvocab)
{
printf("Memory allocation failed!n");
return;
}
else
{
newvocab->question=readtextfromfile(MAXTEXTLENGTH,separator);
newvocab->answer=readtextfromfile(MAXTEXTLENGTH,separator);
newvocab->info=readtextfromfile(MAXTEXTLENGTH,separator);
newvocab->hint=readtextfromfile(MAXTEXTLENGTH,separator);
newvocab->right=readnumberfromfile(1,separator);
newvocab->counter=readnumberfromfile(0,separator);
newvocab->known=readnumberfromfile(3,separator);
switch (newvocab->known)
{
case 0: newvocablist = &n2l;break;
case 1: newvocablist = &norm;break;
case 2: newvocablist = &known;break;
case 3: newvocablist = &old;break;
}
addtolist(newvocab,newvocablist);
if (newvocab->question==NULL||newvocab->answer==NULL)
{
printf("Removing empty vocab record created from faulty input file...n");
removefromlist(newvocab,newvocablist,1);
}
else counter++;
}
}
fclose(inputfile);
printf("...finished.n%i entries read from %s.nn",counter,inputfilename);
}
return;
}
完整的源代码可以从https://github.com/megamasha/Vocab-Tester
有几点需要注意:我正在努力帮助自己,我已经做了研究,研究了类似的问题,并自己发现了关于valgrind的信息。
不过,我仍然是一个相对初学者,虽然我很欣赏解决方案(如何解决(,但更有用的是知识(下次如何自己解决或避免(。我在这里(并且非常渴望(学习。
buff[i] = ' ';//terminate string
在这里,i==11,因为您只分配了11个字符,而while条件在i=11时结束。
因此,您访问了一个未分配的内存。
这种情况下的行为没有定义。
您可以通过在malloc
上分配一个额外的字符来解决这个问题。
int number, i=0;
...
while (i<11 ...
对于i=0、1、2、3、4、5、6、7、8、9和10,您最多读取11位数字。然后尝试将CCD_ 5粘在第十二时隙CCD_。
这被称为"一次失误"。
因此,修复取决于你想要改变什么。如果你想接受11个字符,请更改buff的malloc。如果您只想接受10,请更改while条件。
大小为1的写入无效
你可能正在写一个字符
地址0x53b05bb在分配的大小为11的块之后为0字节
你刚刚溢出了11号
两者都在readnumberfromfile
中
这是可疑的相关(按大小(:
char * buff = (char *)malloc(11);
这将在循环后用i = 11
完成,循环已过分配结束:
buff[i] = ' '
正如wormsparty所说,通过在二进制文件中获得调试符号,可以让valgrind更有帮助。
稍后,如果使用-g进行编译,valgrind将准确地显示segfault发生在哪一行。