Reputation: 23
I am learning file management in C. I wrote this code and the output wasn't what I expected.
#include <stdio.h>
int main(int argc, char * argv[]){
int i;
char str[12];
FILE *fp;
fp = fopen("Names.dat", "w+");
for(i = 1; i < argc; i++){
fprintf(fp, "%s ", argv[i]);
}
rewind(fp);
fscanf(fp,"%[^\n]", str);
printf("%s", str);
return 0;
}
I compiled it and ran it as follows
gcc test.c
a abcdefghijklmnopqrstuvwxyz
The output was as follows:
abcdefghijklmnopqrstuvwxyz
I thought it would output only first 12 letters.
Where did I go wrong in my thought process?
Upvotes: 0
Views: 79
Reputation: 32596
fscanf(fp,"%[^\n]", str);
attempts to read characters and writes them to memory, starting at str, until '\n' or EOF is encountered, regardless of the length of str
So, with
char str[12]; ... fscanf(fp,"%[^\n]", str);
reading the string of 27 characters "abcdefghijklmnopqrstuvwxyz " from the file writes 28 characters from &str[0] and has an unspecified behavior (probably a crash).
Array containing more characters than specified
no, str[12]
allows to store 11 characters more the null ending character, nothing more.
To read at most 11 characters from the file do :
fscanf(fp,"%11[^\n]", str);
Doing that, compilation and execution :
pi@raspberrypi:/tmp $ gcc -g -pedantic -Wextra m.c
pi@raspberrypi:/tmp $ ./a.out abcdefghijklmnopqrstuvwxyz
abcdefghijkpi@raspberrypi:/tmp $
and under valgrind :
pi@raspberrypi:/tmp $ valgrind ./a.out abcdefghijklmnopqrstuvwxyz
==10408== Memcheck, a memory error detector
==10408== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10408== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10408== Command: ./a.out abcdefghijklmnopqrstuvwxyz
==10408==
abcdefghijk==10408==
==10408== HEAP SUMMARY:
==10408== in use at exit: 352 bytes in 1 blocks
==10408== total heap usage: 3 allocs, 2 frees, 5,472 bytes allocated
==10408==
==10408== LEAK SUMMARY:
==10408== definitely lost: 0 bytes in 0 blocks
==10408== indirectly lost: 0 bytes in 0 blocks
==10408== possibly lost: 0 bytes in 0 blocks
==10408== still reachable: 352 bytes in 1 blocks
==10408== suppressed: 0 bytes in 0 blocks
==10408== Rerun with --leak-check=full to see details of leaked memory
==10408==
==10408== For counts of detected and suppressed errors, rerun with: -v
==10408== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
P.S. add a \n in the printf printf("%s\n", str);
of use puts to have a more readable result :
pi@raspberrypi:/tmp $ gcc -g -pedantic -Wextra m.c
pi@raspberrypi:/tmp $ ./a.out abcdefghijklmnopqrstuvwxyz
abcdefghijk
pi@raspberrypi:/tmp $
P.S. of course to read 12 characters from the file do
char str[13];
...
fscanf(fp,"%12[^\n]", str);
Upvotes: 1
Reputation: 14191
Even though you allocated an array of size 12 this doesn't mean you cannot write (or read) beyond its boundaries.
fscanf
expects a pointer as third argument and pointer have no information regarding length as such fscanf
cannot know how much memory you allocated, this is the reponsability of the caller.
C is very liberal when it comes to accessing memory ;)
Upvotes: 0