I am writing a function in C, that is supposed to input information about students and their grades from a file. However, upon running the programme at times the tests show profiler error at fscanf by fscanf, even though the output is as expected.
/*structure for grade*/
struct Grade {
char subject[51];
int grade;
};
/*structure for student*/
struct Student {
char name[21], surname[21];
int no_grades;
struct Grade grades[100];
};
int input_students(struct Student *students, int n) {
int i = 0, no, j, first;
char name[21], surname[21], subject[51];
FILE *database = fopen("input.txt", "r");
if (database == NULL) {
printf("Error while opening input.txt");
return 0;
}
while (/*i < n && */fscanf(database, "%20s %20s %50s %d\n", name, surname, subject,
&no) == 4) {
first = 1;
for (j = 0; j < i; j++) {
if (strcmp(students[j].name, name) == 0 &&
strcmp(students[j].surname, surname) == 0) {
first = 0;
if (students[j].no_grades >= 100) { /*limit for number of grades per student is 100*/
break;
}
strcpy(students[j].grades[students[j].no_grades].subject,
predmet);
students[j].grades[students[j].no_grades].grade = no;
students[j].no_grades++;
break;
}
}
if (first && i < n) {
strcpy(students[i].name, name);
strcpy(students[i].surname, surname);
students[i].no_grades = 0;
strcpy(students[i].grades[students[i].no_grades].subject, subject);
students[i].grades[students[i].no_grades].grade = no;
students[i].no_grades++;
i++;
}
}
/*while (fscanf(database, "%20s %20s %50s %d\n", name, surname, subject,
&no) == 4) {
for (j = 0; j < i; j++) {
if (strcmp(students[j].name, name) == 0 &&
strcmp(students[j].surname, surname) == 0) {
if (students[j].no_grades >= 100) {
break;
}
strcpy(students[j].grades[students[j].no_grades].subject,
subject);
students[j].grades[students[j].no_grades].grade = no;
students[j].no_grades++;
break;
}
}
}*/
fclose(database);
return i;
}
/update, comments changing the code to only one loop, same thing happens/ Return value is the number of students whose information was read from the file, while i < n.
The profiler message indicates a mistake in the line with fscanf.
==3928== Invalid write of size 1
==3928== at 0x37154582C7: _IO_vfscanf (in /lib64/libc-2.12.so)
==3928== by 0x371546465A: __isoc99_fscanf (in /lib64/libc-2.12.so)
==3928== by 0x400AD5: input_students (main.c:22)
==3928== by 0x401394: main (main.c:174)
==3928== Address 0x7feff2e00 expected vs actual:
==3928== Expected: stack array "name" of size 21 in frame 2 back from here
==3928== Actual: stack array "surname" of size 21 in frame 2 back from here
==3928== Actual: is 32 before Expected
I can't seem to be able to find what is the cause of this. I have double-checked that each string ends with '\0', I have run the programme through debugger and it stops where it should, I have not seen it going over and working with uninitalised values, and the values it takes are as expected.
I have translated the name of the function and variables as it wasn't originally in English, therefore the problem can not be in the name of the function overlapping with the name of a library function but I will change it here.
Test code. It's an autotest.
int i, j, no_students;
struct Student students[10];
FILE* database = fopen("input.txt", "w");
fputs("Pero Peric Osnove_racunarstva 8", database);
fputc(10, database);
fputs("Suljo Suljic Osnove_racunarstva 9", database);
fputc(10, database);
fputs("Pero Peric Inzenjerska_matematika_1 6", database);
fclose(database);
no_students=input_students(students, 10);
printf("%d\n", no_students);
for (i=0; i<no_students; i++) {
printf("%s %s ", students[i].name, studenti[i].surname);
for (j=0; j<students[i].no_grades; j++)
printf("%s %d ", students[i].grades[j].subject, students[i].grades[j].grade);
printf("\n");
}
Output for this test.
2
Pero Peric Osnove_racunarstva 8 Inzenjerska_matematika_1 6
Suljo Suljic Osnove_racunarstva 9
When the test code is run within the main.c, it does not show any compiler errors, nor does debugger show segmentation error.
Example for input.txt, created by this autotest.
Pero Peric Osnove_racunarstva 8
Suljo Suljic Osnove_racunarstva 9
Pero Peric Inzenjerska_matematika_1 6
This would be the information about the profiler, bare in mind I am still only a student
==17000== exp-sgcheck, a stack and global array overrun detector
==17000== NOTE: This is an Experimental-Class Valgrind Tool
==17000== Copyright (C) 2003-2012, and GNU GPL'd, by OpenWorks Ltd et al.
==17000== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==17000== Command: outputP9YqwH
read
when it compilesmain
? This is the name of a standard library function, so it is at least confusing, but may as well lead to errors. Do you get any compiler warnings? If yes, show the warnings in your question. If not, how do you compile your program? Please answer in your question, not in comments. – Bodopredmet
?strcpy(students[j].grades[students[j].no_grades].subject, predmet);
looks unsafe. – chux - Reinstate Monicawhile (i < n && fscanf(database, "%20s %20s %50s %d\n", name, surname, subject, &no) == 4) {
loops ininput_students()
? – chux - Reinstate Monica