Home > Back-end >  Reading a string in C using fgets
Reading a string in C using fgets

Time:11-17

I am trying to read a string from the user using the following code

char array[4];
fgets(array , 5, stdin);

I am using the fgets command because with the scanf it reads the entire string regardless of the size of the array and if it doesn't fit inside the array it automatically changes the size of the array in order for the string to fit. I want always to read a string of maximum length 4, that is why I use the fgets, because fgets will always get the characters that you tell it to get regardless of how long the string from the user will be.

My problem is this, as you can see I have declared the array of size 4 but inside the fgets I have to write 5 because it reads one less character than the number. Why does it do that? Why does it read one character less than the number? am I doing something wrong?

CodePudding user response:

A string in C is a sequence of characters including the terminating zero character '\0'.

So this array

char array[4];

can contain a string with in maximum three characters apart from the terminating zero character '\0'.

If you want to enter more than three characters you need to declare the array at least like

char array[5];

And then you can write

fgets(array , sizeof( array ), stdin);

In this case the new line character '\n' that corresponds to the pressed key Enter will not be stored in the array and will stay in the input buffer.

As a result if you after that will call fgets one more then a string that contains only that new line character '\n' (if not to count the terminating zero character '\0') will be read.

So it is better to declare the array like

char array[6];

To remove the new line character from the array you can write

array[ strcspn( array, "\n" ) ] = '\0';

As for this call

fgets(array , 5, stdin);

then it will invoke undefined behavior if you will try to enter four characters because the terminating zero character '\0' will be written by the function in memory outside the array.

As for the function scanf then you could use it the following way

char array[5];
scanf( "%4s", array );

or

char array[5];
scanf( " %4[^\n]", array );

Pay attention to the leading space in the format string. It allows to skip white space characters as for example the new ,line character '\n' that can be stored in the buffer after a preceding call of scanf.

CodePudding user response:

Writing fool-proof input routines is hard. Many traditional *nix programs used to fail when presented with unusual or extreme inputs (e.g. very long lines).

Unfortunately, beginner problems often deal with manual input. I see the following strategies, depending on the use case (e.g., the exact assignment).

  1. Ignore all input trouble and don't handle any errors. Assume that no word is longer than x bytes, no line longer than y bytes and no file larger than z bytes. This is not recommended, even if you are fairly sure that your manual input will not violate your arbitrary assumptions: Constraints are forgotten, routines get repurposed, and inevitably you'll have a program that malfunctions one way or another.
  2. Do some judicious error checking. This is what traditional *nix programs did before hacking became so much of an issue. Deal with the most common errors (file not found) and constraints that are the most likely to cause problems (line length), and fail when those are exceeded. Your program may still fail in certain situations, and it will be vulnerable to attacks.
  3. Make your program fool proof. This is relatively hard, even for simple programs, and tends to obscure the actual control flow and purpose with error checking and -handling. On the other hand you can be sure that when your routines is plugged into the software for the next bigger rocket it will trigger an assertion or otherwise fail gracefully.

In your case, you must:

  1. Make sure that the routine does not read more characters than space is available in the buffer, for which Vlad has given you the information.
  2. Think about how you detect words or lines that are too long.
  3. Handle the detected condition gracefully.

As an aside, scanf("%5s", buf) will also read up to 5 characters and no more, and store a null character after those so that your buffer array must be 6 characters big.

  • Related