Given the following code , which is part of a larger program.
/*Retorna cero si ya no hay más que leer*/
int leer (FILE *file, lista_notas *inicio, lista_notas *final){
/*Nota leída*/
int nota;
char *delimitador = " ";
/*Si ya no hay más que leer, se acabó el fichero*/
int res;
/*Auxiliar para leer la primera linea, pues conocemos el formato de los tres datos
pero no cuántos espacios en blanco hay entre cada dato*/
char *linea;
if( (res = fscanf(file,"%s%d",linea,¬a)) ){/*Cuerpo*/}
/*Más código irrelevante para el caso*/
}
The compiler informs me of a segmentation fault which, by debugging with gdb, specifies that this error is in the fscanf function :
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e4c88c in _IO_vfscanf_internal (s=s@entry=0x555555559260, format=, argptr=argptr@entry=0x7fffffffe820, errp=errp@entry=0x0) at vfscanf.c:1100
1100 vfscanf.c: No such file or directory.
It seems that the ¬e argument is wrong, why? I have tried to introduce a previously initialized integer variable (int note = 5) and neither. From the error code, the entry ¬e is address zero , but I don't understand why the system is assigning that address to "note".
The original program is responsible for verifying that the file is correct so that it can be read without problems. The content of the file is also correct, as is all the data that the program handles until it reaches this function called "read". Ultimately, the bug must be in the shared code section .
The format for each line of the input file is: First Name [n blank spaces] Last Name [n blank spaces] note
What is happening? Thanks.
The error message has sent you on a false trail. If you look closely, the function that is producing the error is not
fscanf()
, but_IO_vfscanf_internal()
, which is known to be an internal function called fromfscanf()
.The 0x0 pointer seen in that error message refers to a named parameter
errp
which the name suggests is a pointer to an error stream . In any case, it cannot be your parameter¬a
because, beingfscanf()
a variadic function (it receives a variable number of arguments), these arguments do not have fixed positions in the prototype, nor a name.A more plausible suspect for causing a segfault is the pointer
linea
that you've declared as achar*
but not initialized, so it points to somewhere (or to NULL, depending on the compiler).That parameter should better be a fixed-size array, for example
char linea[200]
, although you have to set the size making sure that you will never find lines longer than that value.This is a security risk, because if a line were longer than that, it
fscanf()
would still continue to read characters and store them in memory, beyond the completion of that array, possibly overwriting other variables and causing undefined behavior.Also,
fscanf()
with the format string"%s"
you can't read strings containing spaces (it stops at the first space), so it's not a good choice for reading lines or reading "First Name Last Name".I would use it
fgets()
to read the entire line (with note and all), to a buffer of a pre-declared size.fgets()
It has the advantage that you can specify the size of the buffer as a parameter and it will never read more characters than fit in it.Once you have the line read in a buffer, that buffer would be processed letter by letter to separate first name, last name and note (you can also use
strtok()
to separate into pieces by space, but that function has a very confusing way of using it). To convert the note part to an integer you can useatoi()
.Another option once you have the complete line is to use
sscanf()
to separate the values you want to read from that line. For example you can use the format string"%s %s %d"
to separate "FirstName", "LastName" (as strings) and "Age" (as integer), but this will only work correctly if indeed the line contains those three fields separated by spaces and they are of type Right.