Reputation: 79
I've a txt file like this:
milk l 300
oil l 200
..
and my fuction is the following (some variables are global, some words are in italian):
void Calcola() {
FILE *fp;
fp = fopen("ingredients_out.txt", "r");
float somma = 0.0;
int i;
char ingredient[15]; //this is the problem
char simbolo[1];
float quantita;
while(fscanf(fp, "%s%s%f", ingredient, simbolo, &quantita) == 3){
printf("%s\n", ingredient); //I think the problem is here
if(simbolo[0] != 'g') {
for(i = 0; i < 4; i++) {
if(strcmp(V[i].ingrediente, ingredient) == 0) {
somma += quantita * V[i].peso;
}
}
}
}
fclose(fp);
printf("Somma pesi: %d\n", somma);
}
The problem is that "ingredient" variable is always empty, it's a series of blank spaces..Why?
Upvotes: 0
Views: 255
Reputation: 5615
This is actually quite interesting. So the reason is actually because simbolo[1]
does not have enough storage to hold a C string (i.e strings terminated with a \0
). But what does that have to do with ingredient
being blank?
Well, if you look carefully, the very first character of ingredient
during the first read (i.e reading "milk") is a null terminator, then i
, then l
, then k
. WAIT! How did that \0
get where m
should have been?
The answer? Buffer overflow.
fscanf
first puts "milk" into ingredient
, as it should. Then it tried to put "l"
into the simbolo
(note "l"
is actually l
and \0
) and it does that rightfully. But wait, simbolo
can only hold one character. So it holds the l
, what the heck happened to the \0
?
You guessed it. Due to stack alignment on modern architectures, the ingredient
memory begins right after the end of simbolo
. So \0
is actually put in ingredient[0]
and boom you have just wrecked that memory.
This is a pretty textbook definition of undefined behavior associated with buffer overflow. Don't expect this to happen in every single machine. But I'm pretty sure this is what's happening on your machine.
So yeah, the fix is to just do char simbolo[2]
if you want that l
as a string. Or if you're certain it's always a singular character, simply do char simbolo
and use %c
on the fscanf
Edit: Also as mentioned by @Barmar, %s
with simbolo[2]
alone won't save you unless you're certain of the length in the input file and you 100% trust it. If you insist on using %s
, also mention a n
in %ns
where n
is the amount of characters (excluding null terminator) your buffer can hold.
Upvotes: 2