1

I have an array of sentences and I want to scan them first with fgets() and then print them one by one. Here is the program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>





int main(int argc,char *argv[]) {

    char sentence[100][100]; /* 100 sentences with at most 100 characters*/
    int n,i,j;

    scanf("%d",&n); /* number of sentences*/

    for (i=0;i<n;i++) {
        fgets(sentence[i],100,stdin);
    }
    printf("****************************");
    for (i=0;i<n;i++) {
        for(j=0;j<strlen(sentence[i]);j++) {
            putchar(sentence[i][j]);
        }

    }


    return 0;
}

The problem is that this only scans n-1 sentences. Why is that?

And the other weird thing is that after printing the asterisks, it starts printing at a new line without me telling it to do so.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
odin19
  • 147
  • 1
  • 8

3 Answers3

1

Assume the input is

3
abc
def
ghi

The cursor stays after the number 3 on the first line after n is scanned.

You can add a space after %d, like scanf("%d ", &n); to move the cursor to the next line. (This assumes that the first sentence does not start with spaces).

Depends on whether your environment is (Windows / Unix), and whether you want every string to keep the end of line character, you need to increase the buffer size to:

  • 101 - for Unix line ending and you are fine to discard the end of line character for sentences of 100 characters long
  • 102 - for Windows line ending and you are fine to discard the end of line character for sentences of 100 characters long
  • 102 - for Unix line ending and you want to keep the end of line character for all sentences
  • 103 - for Windows line ending and you want to keep the end of line character for all sentences

For example, if you incorrectly used 101 for Windows, for the following input

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789

The output would be:

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789


0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789


0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789

(there are some empty lines)

microtony
  • 192
  • 7
  • That fixed it, thanks! But what exactly has the cursor position have to do with how many strings are read? – odin19 Jan 28 '16 at 19:46
  • The first `fgets` will read an empty string because it sees an end of line character immediately. So `sentence[0]` will be `"\n"`. Then the first sentence will go to `sentence[1]` etc. The 100th sentence would not be read. (You can imagine fgets as pressing Shift+End and then move to the next line) – microtony Jan 28 '16 at 19:49
  • 2
    Rather "So `sentence[0]` will be `"\n"`" – chux - Reinstate Monica Jan 28 '16 at 19:53
  • You would also want to increase the size of the buffer to something like 102 if your sentences are at most 100 characters long. – microtony Jan 28 '16 at 19:55
  • @TonyWong why 102? and Please extend your answer to cover the second issue in the question also. :) – Sourav Ghosh Jan 28 '16 at 19:56
1

Both the cases will be solved by one concept, fgets() considers a newline as a part of the input.

Issue 1:

You have a newline left in the input buffer (due to the ENTER key press after the first input) which is picked up by the immediate next fgets().

Resolve issue 1:

Use

  scanf("%d%*c",&n);   //simple solution

or

 scanf("%d",&n);
 while (getchar() != '\n');  //eat up anything upto newline

to clear the trailing newline.

Issue 2:

fgets() scans and stores the newline as a per of the input. If you don't want the newline as a part of the input, you've to check and remove that manually.

Related quote from the man page:

[...] If a newline is read, it is stored into the buffer. [...]

Resolve issue 2:

  sentence[strcspn(sentence, "\r\n")] = 0;

Thanks to @chux, more about this here

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • Now consider [hacker exploit](http://stackoverflow.com/questions/35069399/find-number-of-sub-strings-in-a-string/35069527#comment57862941_35069527) vs. http://stackoverflow.com/a/28462221/2410359 – chux - Reinstate Monica Jan 28 '16 at 20:59
  • @chux Thank you once again for noticing these minor but very relevant details and leaving the comments!! It's people like you who defines the perfection. Appreciate it. :) – Sourav Ghosh Jan 28 '16 at 21:07
0

Did you read the man page for fgets?

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.

So your code should be, as pointed out by chux :

fgets(sentence[i],sizeof sentence[i],stdin);
Claudio Cortese
  • 1,372
  • 2
  • 10
  • 21
  • 1
    This is wrong advice. "So your code should be `fgets(sentence[i],101,stdin);`. "The fgets function reads at most one less than the number of characters specified by `n` ..." – chux - Reinstate Monica Jan 28 '16 at 19:57
  • 1
    `sentence[i]` is an array of 100 `char`. `fgets(sentence[i],101,stdin);` allows `fgets()` to read 100 characters _and_ attempt to save the appended `'\0'` resulting in UB. Better to use `fgets(sentence[i], sizeof sentence[i],stdin)` – chux - Reinstate Monica Jan 28 '16 at 20:03
  • @chux would strlen works as well? sizeof does work now because the size in bytes of char is 1, right? – Claudio Cortese Jan 28 '16 at 20:07
  • 1
    `fgets(sentence[i], strlen(sentence[i]),stdin)` would not work well. When `fgets()` is called, the prior contents of `sentence[i]` are not defined - and irrelevant to the read operation. We need to pass the size of the array. – chux - Reinstate Monica Jan 28 '16 at 20:15
  • @chux thank you, I didn't know that. I appreciate that you have learned me something! LSNED – Claudio Cortese Jan 28 '16 at 20:17