A CLI program of mine compiles and runs fine on windows. Compiles fine on linux, but causes a segmentation fault when running.
I turned to stackoverflow for help, and found a few questions similar to what I was going to ask that suggested valgrind, which I just happen to have installed (woo!).
So I ran my program through valgrind, and got a depressingly large amount of output, but I shall start with the first error message:
==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.
The problem seems to be in readnumberfromfile
, and I've looked through it, and I can't seem to find what's wrong with it!
Can anyone shed some light?
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 file\n");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] = '\0';//terminate string
number = atoi(buff)<=maxvalue ? atoi(buff) : maxvalue;//convert string to number and make sure it's in range
free(buff);
return number;
}
This is called from getrecordsfromfile
if that's of any use:
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.\n\n",counter,inputfilename);
}
return;
}
Full source can be gitted from https://github.com/megamasha/Vocab-Tester
A couple of notes: I am trying to help myself, I have done my research, looked at similar questions and found out about valgrind myself.
I am still a relative beginner though, and while I appreciate solutions (WHAT to do to fix it), yet more useful is knowledge (HOW to fix or avoid it myself next time). I am here (and very keen) to learn.
buff[i] = '\0';//terminate string
in here i == 11, since you allocated only 11 chars, and while condition ends when i=11.
so, you access a memory you did not allocate.
the behavior for this situation is not defined.
you can solve this by allocating one extra character on your malloc
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With