3
votes

The format %(limit)[^\n] for scanf function is unsafe ? (where (limit) is the length -1 of the string)

If it is unsafe, why ?

And there is a safe way to implement a function that catch strings just using scanf() ?

On Linux Programmer's Manual, (typing man scanf on terminal), the s format said:

Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'),which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.

The input string stops at maximum field width always ? Or is just on GCC ?

Thanks.

2

2 Answers

3
votes

%(limit)[^\n] for scanf" is usually safe.

In the below example, at most 99 char will be read and saved into buf. If any char are saved, a '\0' will be appended and cnt will be 1.

char buf[100];
int cnt = scanf("%99[^\n]", buf);

This functionality is certainly safe, but what about others?


Problems occur when the input is a lone "\n".

In this case, nothing is saved in buf and 0 is returned. Had the next line of code been the following, the output is Undefined Behavior as buf is not initialized to anything.

puts(buf);

A better following line would be

if (cnt == 1) puts(buf);
else printf("Return count = %d\n", cnt);

Problems because the '\n' was not consumed.

The '\n' is still waiting to be read and another call to scanf("%99[^\n]", buf); will not read the '\n'.


Q: is a safe way to implement a function that catch strings just using scanf()
A: Pedantically: Not easily.

scanf(), fgets(), etc. are best used for reading text, not strings. In C a string is an array of char terminated with a '\0'. Input via scanf(), fgets(), etc. typically have issues reading '\0' and typically that char is not in the input anyways. Usually input is thought of as groups of char terminated by '\n' or other white-space.

If code is reading input terminated with '\n', using fgets() works well and is portable. fgets() too has it weakness that are handled in various ways . getline() is a nice alternative.

A close approximate would be scanf(" %99[^\n]", buf) (note the added " "), but alone that does not solve handing excessive long lines, reading multiple empty lines, embedded '\0' detection, loss of ability to report length read (strlen() does not work due to embedded '\0') and its leaving the trailing '\n' in stdin.

Short of using scanf("%c", &ch) with lots of surrounding code (which is silly, just use fgetc()) , I see no way to use a single scanf() absolutely safely when reading a line of user input.


Q: The input string stops at maximum field width always ?
A: With scanf("%99[^\n]", input stops 1) when a '\n' is encountered - the '\n' is not saved and remains in the file input buffer 2) 99 char have been read 3) EOF occurs or 4) IO error occurs (rare).

1
votes

The [^\n] is to make scanf read input until it meets a new line character...while the limit is the maximum number of characters scanf should read...