dividedbyzero
dividedbyzero

Reputation: 187

Difference between scanf("%79[^\n]",line); vs scanf("%79[^\n]\n",line) vs scanf("%79[^\n]s",line)

I was writing a program in c to read the contents of a file. The code is as follows:

   #include<stdio.h>
   void main()
   {
   char line[90];
   while(scanf("%79[^\n]\n",line)==1) 
   printf("%s",line);
   }

The above code reads a file content and displays it on the screen.

But

while(scanf("%79[^\n]",line)==1) and while(scanf("%79[^\n]s",line)==1) or while(scanf("%79[^\n]s\n",line)==1) 

doesn't work.(They display only the first line)

Can anyone explain?

Upvotes: 3

Views: 1667

Answers (4)

R Sahu
R Sahu

Reputation: 206607

The format "%79[^\n]" says all the characters up to 79 characters max that are not '\n'.

When you use,

scanf("%79[^\n]s",line)

the return value should not be 1 since the s in the format specifier expects a literal s after it has finished reading all the characters that are not '\n'. In other words, scanf reports failure.

When you use,

scanf("%79[^\n]\n",line)

it succeeds because it finds a literal '\n' at the end.

The difference between

scanf("%79[^\n]",line)

and

scanf("%79[^\n]\n",line)

is that the '\n' is left in the input stream in the first case while it is consumed in the second case. In the second case, not only is the '\n' consumed but any sequence of whitespaces starting at the '\n' is consumed too (Thanks to @MattMcNabb for the additional clarification).

If you want scanf to consume just the '\n', use:

scanf("%79[^\n]%*c",line)

Upvotes: 5

chux
chux

Reputation: 153508

Lots of subtle differences:

1) "%79[^\n]" tells scanf() to scan and save 1 to 79 char except '\n'. If the first char attempted to scan is \n, nothing will be save and scanning stops. In OP's examples, 0 is returned. Else a '\0' is append to the destination line. A 1 is returned if there is nothing more.

2) "%79[^\n]\n" does 1) and if successful continues to look for any consecutive white-space, not just '\n'. This will typically include a '\n' and then all leading whitespace of the next line. It will return 1 regardless if it find a white-space.

3) "%79[^\n]s" does 1 and if successful continues to look a single s. It will return 1 regardless if it find a s. Likely this is not OP's desire - drop the 's'.

4) "%79[^\n]s\n" does 3) and if successful, behaves like 2) continues to look for any consecutive white-space, not just '\n'. It will return 1 regardless if it find a white-space.

5) The 3 while() statement is fairly complex, taken as a whole. It gets stuck trying to read a '\n' into the beginning of 1 of the 3 scanf().

A better approach, if code needs to use scanf() to read a line, is
while (scanf(" %79[^\n]%*c", line) ==1). This will toss leading white-space and then read a line up to '\n', tossing that '\n' via the "%*c".

The best approach is to use fgets(line, sizeof line, stdin).

Upvotes: 1

ETFovac
ETFovac

Reputation: 111

Its possible that the problem is concested to logic values shortcircuting. ie. when compiler determents that he has sufficient information to evaluate the whole expression it doesn't need to test other logic values(and doesn't evaluate them).

i.e. false and call_foo() always evaluate to false, so call_foo() is never called.

It could also be connected to that, when you read a line in scanf(first of 3 logic expresions) others scanf will read on next lines, not that same lines, because the first scanf already had taken the data from the buffer.

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726599

Since the format itself is the same, the key to solving this is, as you can certainly tell, the trailing character after the format string (or the absence of that character)

  • When you put '\n' at the end, you tell scanf to read and ignore the end-of-line character after reading the string. This works fine, because '\n' is what terminates the string in accordance with your format (i.e. %79[^\n]).
  • When you put an 's' at the end, you tell scanf that you expect a literal s after the string that ends in '\n'. This is an error, because scanf will read the string up to, and excluding, the '\n' character* .
  • When you do not put '\n' at the end, the first read will succeed, but all subsequent ones will stumble upon the '\n', and stop reading right away.

Note that the code that works may produce unexpected results for input strings that exceed 79 characters. These strings would be chopped at the 79-character mark, their remainder presented as the beginning of the next string.

* There is an unlikely situation when this read would succeed - namely, when the read terminates due to reaching the limit of 79, and then discovering the letter s at the 80-th space.

Upvotes: 1

Related Questions