Vishal Dalwadi
Vishal Dalwadi

Reputation: 23

Array containing more characters than specified

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

Answers (2)

bruno
bruno

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

Radu Diță
Radu Diță

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

Related Questions