fgets() includes the newline at the end [duplicate]
Asked Answered
D

5

13
fgets(input,sizeof(input),stdin);
if (strcmp(input, "quit") == 0){
  exit(-1);
}

If I type quit, it does not exit the program; I'm wondering why this is the case.

By the way input is declared as char *input;.

Diagram answered 18/11, 2012 at 19:35 Comment(3)
If you really declared char *input; without allocating space for it to point to, you are lucky (or do I mean unlucky?) that you didn't get a crash. You must make sure there's enough space: char input[64]; would be better; I usually use 4096 for the line length unless there's a compelling reason to use something shorter. Also, you should check that fgets() read some data: if (fgets(input, sizeof(input), stdin) != 0) ...OK - read some data....Romaine
I'm confused, the title of this post implies you already know what the issue is. Did you change the title?Thrill
@flarn2006 Simply check the edit history. Someone else changed it.Hothead
T
8

Trailing newline in your input. See man fgets. Test for "quit" + newline, for example:

fgets(input,sizeof(input),stdin);
if(strcmp(input, "quit\n") == 0){
    exit(-1);
}

I completely missed the last sentence, re char *input. Depending on the architecture, input will be 4 or 8 bytes long. So the code is effectively

fgets(input, 8, stdin);

which doesn't reflect the real size of memory, input points to. This might "work" as long as the input is shorter than eight bytes, but will truncate the input, if it is larger. Furthermore, you will get the rest of the input the next time you call fgets.

You should either give the real size or take @JonathanLeffler's advice and declare a char array instead, e.g.

char input[64];
fgets(input, sizeof(input), stdin);

or

char *input = malloc(N);
fgets(input, N, stdin);
Thrombosis answered 18/11, 2012 at 19:38 Comment(2)
Sadly that does not work all the time. Say you've declared input as char input[5] and you enter quit. At that time fgets does not add the newline at the end. So, always check if the newline is added.Lobelia
Just to make my point clear: Compare the outputs of: ideone.com/3vs6Ed and ideone.com/MVfvy6Lobelia
L
14

The function fgets might add a newline at the end of the string read. You'll have to check that:

size_t ln = strlen(input) - 1;
if (input[ln] == '\n')
    input[ln] = '\0';

or even

strtok(input, "\n");
Lobelia answered 18/11, 2012 at 19:37 Comment(4)
It seems like it does when I printf it. How would I remove that newline, or change the strcmp so it accounts for that?Diagram
Thanks, used Olaf's solution since it's a bit simpler. But that works as well.Diagram
fgets() won't add a newline; it will include the newline that it read that marks the end of line. That way, you can tell whether you read the whole line or not.Romaine
If the first char read is the null character, ln takes on the value of SIZE_MAX certainly causing an out of bounds read with input[ln] --> UB. To avoid this exploit, test ln or maybe use ln[strcspn(ln,"\n")] = 0;. strtok(input, "\n"); fails to lop off the '\n' if the first char is '\n'.Codex
T
8

Trailing newline in your input. See man fgets. Test for "quit" + newline, for example:

fgets(input,sizeof(input),stdin);
if(strcmp(input, "quit\n") == 0){
    exit(-1);
}

I completely missed the last sentence, re char *input. Depending on the architecture, input will be 4 or 8 bytes long. So the code is effectively

fgets(input, 8, stdin);

which doesn't reflect the real size of memory, input points to. This might "work" as long as the input is shorter than eight bytes, but will truncate the input, if it is larger. Furthermore, you will get the rest of the input the next time you call fgets.

You should either give the real size or take @JonathanLeffler's advice and declare a char array instead, e.g.

char input[64];
fgets(input, sizeof(input), stdin);

or

char *input = malloc(N);
fgets(input, N, stdin);
Thrombosis answered 18/11, 2012 at 19:38 Comment(2)
Sadly that does not work all the time. Say you've declared input as char input[5] and you enter quit. At that time fgets does not add the newline at the end. So, always check if the newline is added.Lobelia
Just to make my point clear: Compare the outputs of: ideone.com/3vs6Ed and ideone.com/MVfvy6Lobelia
P
0

Suggest you code this as:

if(strstr(input, "quit") != NULL){

Reason: This will solve issue of people adding extra characters (e.g. space before or after text).

Perdu answered 31/5, 2017 at 13:33 Comment(0)
B
-1

This solution only needs the standard library (stdio.h) and gives the same results.

for (i = 0; input[i] != '\0'; i++); /* getting the string size */
input[i-1] = '\0'; /* removing the newline */
Bill answered 24/5, 2015 at 20:31 Comment(0)
S
-2

what i did is to replace newline by '\0' null .

while(fgets(message,80,stdin))
{
    l=strlen(message)-1;
    if(message[l]='\n') message[l]='\0';
            else message[i+1]='\0';
}
Salaam answered 29/7, 2013 at 15:7 Comment(2)
This is not a guaranteed behaviour. Check man 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 (aq\0aq) is stored after the last character in the buffer." So you can have two cases when newline will not be added: strlen(message) > 80 or use EOF as terminator.Watchcase
if(message[l]='\n') message[l]='\0' whaaat?Mum

© 2022 - 2024 — McMap. All rights reserved.