Taking multiple scans in C - c

this may be a silly question but is there a way for me to scan in multiple inputs for example I scan one key which then runs through traverse_search, after that, it takes another scan to perform the same task. At the moment it is only able to take 1 scan, performing the task only once.
*Note MAXLEN = 128
void list_search(list_t* list, FILE* outFile){
char key[MAXLEN + 1];
while(scanf("%129[^\n]", key)){
traverse_search(list, key, outFile);
}
}

The issue you are facing has to do how scanf read the input buffer.
With your current format string, scanf reads at most 129 characters (or when it encounters a newline \n) into the key array.
This means that the next character in the input buffer is \n. On the second call to scanf, the first character in the input buffer is a newline and the scanning will fail and scanf return 0 (and the loop exits).
If we assume that the user will only type one newline at the end of the input, you could add a call to getc in your code and discard the read value.
void list_search(list_t* list, FILE* outFile){
char key[MAXLEN + 1];
getc(stdin); // read the newline and hope the next character is not a newline again
while(scanf("%129[^\n]", key)){
traverse_search(list, key, outFile);
}
}
Please not that your code does not handle EOF. When hit with an EOF on the standard input, your code will loop forever (in case of EOF, scanf return EOF, usually -1).
I would strongly advise to use a more robust way of scanning and validating the input, such as with getline and sscanf.

Code never consumes '\n'
scanf("%129[^\n]", key) returns 0 on the 2nd call as it fails to scan in '\n', left over from the first line of user input.
Lead with a " " in the format to consume all optional leading white-space including the prior line's '\n'.
Even better, look to fgets() to read a line of user input and avoid scanf() until you understand why it is bad.
Off-by-one
To read a max length of 128, use "%128[^\n]".
Test for success
while(scanf("%129[^\n]", key)) loops when scanf() returns 1 or EOF. Instead, loop on success.
// while(scanf("%129[^\n]", key))
while(scanf("%129[^\n]", key) == 1)
void list_search(list_t* list, FILE* outFile){
char key[MAXLEN + 1];
// v--- consume optional leading white-space including prior \n
while(scanf(" %128[^\n]", key) == 1) {
traverse_search(list, key, outFile);
}
}

Related

Difference between `"%[^\n]"` and `"%[^\n]\n"` and `"%[^\n]%*c"` in C how do they work?

I could not find the answer anywhere else.
%[^\n] - When I run this one, scanf is getting input and terminating after I press enter. ( Probably leaving \n in the input system)
%[^\n]\n - this one is getting the input but scanf is NOT terminating immediately after I press enter like the one above. I hit more enter and it makes more newlines. When I give a character and then press enter it finally terminates. Example:
int main(void)
{
char s[100];
scanf("%[^\n]\n", s);
printf("%s", s);
return 0;
}
The results:
Last one:
%[^\n]%*c - When I give some input and press enter. scanf immediately terminates.
How do those 3 work and how do they differ?
All 3 format begin with "%[^\n]".
"%[^\n]" is poor code2 that lacks a width limit and is susceptible to buffer overrun. Use a width limit like "%99[^\n]" with char s[100];.
"%[...]" does not consume leading whitespace like many other specifiers.
This specifier directs reading input until a '\n'1 is encountered. The '\n' is put back into stdin. All other characters are saved in the matching destination's array s.
If no characters were read (not counting the '\n'), the specifier fails and scanf() returns without changing s - rest of the format is not used. No null character appended.
If characters were read, they are saved and a null character is appended to s and scanning continues with the next portion of the format.
"\n" acts just like " ", "\t", "any_white_space_chracter" and reads and tosses 0 or more whitespace characters. It continues to do so until a non-white-space1 is read. That non-whitespace character is put back into stdin.
Given line buffered input, this means a line with non-whitespace following input is needed to see the next non-whitespace and allow scanf() to move on.
With scanf(), a "\n" at the end of a format is bad and caused OP's problem.
"%*c" reads 1 character1 and throws it away - even if it is not a '\n'. This specifier does not contribute to the return count due to the '*'.
A better alternative is to use fgets().
char s[100];
if (fgets(s, sizeof s, stdin)) {
s[strcspn(s, "\n")] = '\0'; // To lop off potential trailing \n
A lesser alternative is
char s[100] = { 0 };
scanf("%99[^\n]", s);
// With a separate scanf ....
scanf("%*1[\n]"); // read the next character if it is a \n and toss it.
1 ... or end-of-file or rare input error.
2 IMO, worse than gets().

C - Enter dead loop after trying to read line by line of a file and lines might contain space character?

I'm trying to read a file line by line and count the characters of each line. Those line might contains space characters and I need also to count them. I'm only allowed to use feof and scanf functions.
Sample Code
...
while(!feof(stdin)){
char inputLineArray[1000];
scanf("%[^\n]s", inputLineArray);
printf(inputLineArray);
}
...
My sample file is a txt file which contains the following content:
hello world
abcdsdsdsdsd
But after it prints:
hello world
My program is stuck into infinite loop which does nothing.
From man 3 scanf:
The scanf() family of functions scans input according to format as described below.
This means that your provided pattern %[^\n]s (don't match newlines) will stop matching after world because there is a newline. You'd need to skip to the next char in the stream.
There are many questions like yours on Stackoverflow, search for scanf infinite loop.
scanf("%[^\n]s", inputLineArray); is incorrect and inappropriate:
the conversion specifier does not have a trailing s, it is just %[^\n] ;
scanf reads the stream and stores any characters before the newline into inputLineArray and leaves the newline pending in the stream ;
scanf should be given the maximum number of characters to store to avoid undefined behavior on long lines: scanf("%999[^\n]", inputLineArray) ;
you should test the return value of scanf() to determine if the conversion was successful. The test while (!feof(stdin)) is pathologically inappropriate: Why is “while ( !feof (file) )” always wrong? ;
you would then see another problem: this conversion fails on empty lines because there are no characters to store into the destination array, and since scanf() leaves the newline pending, the second call fails and all successive ones too.
Note also that it is highly risky to call printf with user supplied data as a format string. The behavior is undefined if the line contains non trivial format specifications.
Here is a better way to read the file line by line:
#include <stdio.h>
#include <string.h>
...
char inputLineArray[1001];
while (fgets(inputLineArray, sizeof inputLineArray, stdin)) {
buf[strcspn(buf, "\n")] = '\0'; // strip the trailing newline if present
printf("%s\n", inputLineArray);
}
...
Note however that input lines with 1000 bytes or more will be broken into multiple output lines.
scanf() is not the right tool for your purpose, indeed it is full of quirks and shortcomings, but if you are required to use scanf(), here is a corrected version:
char inputLineArray[1000];
while (scanf("%c", &inputLineArray[0]) == 1) {
/* one byte was read, check if it is a newline */
if (inputLineArray[0] == '\n') {
/* empty line must be special cased */
inputLineArray[0] = '\0';
} else {
/* set the null terminator in case the next `scanf` fails */
inputLineArray[1] = '\0';
/* attempt to read the rest of the line */
scanf("%998[^\n]", inputLineArray + 1);
/* consume the pending newline, if any */
scanf("%*1[\n]");
}
printf("%s\n", inputLineArray);
}
if (feof(stdin)) {
/* scanf() failed at end of file, OK */
} else {
printf("read error\n");
}
Note that feof() is not used as scanf("%c", ...) will return EOF at end of file, so the while() loop with stop as expected.
feof() is only used to distinguish end of file from read error conditions in stream I/O. Most C programs do not need to distinguish between these as read errors can be handled the same way as truncated input files. This function is almost always used incorrectly. In short, you should never use feof(), nor other error-prone or deprecated functions such as gets() and strncpy(). Be also very careful with sprintf(), strcpy(), strcat()...

Scanf clarification in c language

Is it possible to read an entire string including blank spaces like gets() function in scanf()?
I am able to do it using the gets() function.
char s[30];
gets(s);
This will read a line of characters. Can this be done in scanf()?
You can read a line, including blank spaces, with scanf(), but this function is subtle, and using it is very error-prone. Using the %[^\n] conversion specifier, you can tell scanf() to match characters to form a string, excluding '\n' characters. If you do this, you should specify a maximum field width. This width specifies the maximum number of characters to match, so you must leave room for the '\0' terminator.
It is possible that the first character in the input stream is a '\n'. In this case, scanf() would return a value of 0, since there were no matches before encountering the newline. But, nothing would be stored in s, so you may have undefined behavior. To avoid this, you can call scanf() first using the %*[\n] conversion specifier, discarding any leading '\n' characters.
After the string has been read, there will be additional characters in the input stream. At least a '\n' is present, and possibly more characters if the user entered more than the maximum field width specifies. You might then want to discard these extra characters so that they don't interfere with further inputs. The code below includes a loop to do this operation.
The first call to scanf() will consume all newline characters in the input stream until a non-newline character is encountered. While I believe that the second call to scanf() should always be successful, it is good practice to always check the return value of scanf() (which is the number of successful assignments made). I have stored this value in result, and check it before printing the string. If scanf() returns an unexpected result, an error message is printed.
It is better, and easier, to use fgets() to read entire lines. You must remember that fgets() keeps the trailing newline, so you may want to remove it. There is also a possibility that the user will enter more characters than the buffer will store, leaving the remaining characters in the input stream. You may want to remove these extra characters before prompting for more input.
Again, you should check the return value of fgets(); this function returns a pointer to the first element of the storage buffer, or a NULL pointer in the event of an error. The code below replaces any trailing newline character in the string, discards extra characters from the input stream, and prints the string only if the call to fgets() was successful. Otherwise, an error message is printed.
#include <stdio.h>
int main(void)
{
char s[30];
int result;
printf("Please enter a line of input:\n");
scanf("%*[\n]"); // throw away leading '\n' if present
result = scanf("%29[^\n]", s); // match up to 29 characters, excluding '\n'
/* Clear extra characters from input stream */
int c;
while ((c = getchar()) != '\n' && c != EOF)
continue; // discard extra characters
if (result == 1) {
puts(s);
} else {
fprintf(stderr, "EOF reached or error in scanf()\n");
}
printf("Please enter a line of input:\n");
char *ps = fgets(s, 30, stdin); // keeps '\n' character
if (ps) {
while (*ps && *ps != '\n') {
++ps;
}
if (*ps) { // replace '\n' with '\0'
*ps = '\0';
} else {
while ((c = getchar()) != '\n' && c != EOF)
continue; // discard extra characters
}
puts(s);
} else {
fprintf(stderr, "EOF reached or error in fgets()\n");
}
return 0;
}
Note that these two methods of getting a line of input are not exactly equivalent. The scanf() method, as written here, does not accept an empty line (i.e., a line consisting of only the '\n' character), but does accept lines consisting of other whitespace characters. The fscanf() method will accept an empty line as input.
Also, if it is acceptable to ignore leading whitespace characters, it would be simpler to follow the recommendation given by Jonathan Leffler in the comments to use only a single call to scanf():
result = scanf(" %29[^\n]", s);
This will ignore leading whitespace characters, including newlines.
Do not use scanf() or gets() function — use fgets() instead. But for the above question please find the answer.
int main() {
char a[30];
scanf ("%29[^\n]%*c", name);
printf("%s\n", a);
return 0;
}
Its also highly recommended like I told in the beginning to use fgets() instead. We clearly do not understand the weird requirement. I would have used the fgets() to read the character.
fgets(a, size(a), stdin);

What does %[^\n] mean in C?

What does %[^\n] mean in C?
I saw it in a program which uses scanf for taking multiple word input into a string variable. I don't understand though because I learned that scanf can't take multiple words.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main() {
char line[100];
scanf("%[^\n]",line);
printf("Hello,World\n");
printf("%s",line);
return 0;
}
[^\n] is a kind of regular expression.
[...]: it matches a nonempty sequence of characters from the scanset (a set of characters given by ...).
^ means that the scanset is "negated": it is given by its complement.
^\n: the scanset is all characters except \n.
Furthermore fscanf (and scanf) will read the longest sequence of input characters matching the format.
So scanf("%[^\n]", s); will read all characters until you reach \n (or EOF) and put them in s. It is a common idiom to read a whole line in C.
See also §7.21.6.2 The fscanf function.
scanf("%[^\n]",line); is a problematic way to read a line. It is worse than gets().
C defines line as:
A text stream is an ordered sequence of characters composed into lines, each line consisting of zero or more characters plus a terminating new-line character. Whether the last line requires a terminating new-line character is implementation-defined.
The scanf("%[^\n]", line) has the specifier "%[^\n]". It scans for unlimited number of characters that match the scan-set ^\n. If none are read, the specifier fails and scanf() returns with line unaltered. If at least one character is read, all matching characters are read and saved and a null character is appended.
The scan-set ^\n implies all character that are not (due to the '^') '\n'.
'\n' is not read
scanf("%[^\n]",.... fails to read a new line character '\n'. It remains in stdin. The entire line is not read.
Buffer overflow
The below leads to undefined behavior (UB) should more than 99 characters get read.
char line[100];
scanf("%[^\n]",line); // buffer overflow possible
Does nothing on empty line
When the line consists of only "\n", scanf("%[^\n]",line); returns a 0 without setting line[] - no null character is appended. This can readily lead to undefined behavior should subsequent code use an uninitialized line[]. The '\n' remains in stdin.
Failure to check the return value
scanf("%[^\n]",line); assumes input succeeded. Better code would check the scanf() return value.
Recommendation
Do not use scanf() and instead use fgets() to read a line of input.
#define EXPECTED_INPUT_LENGTH_MAX 49
char line[EXPECTED_INPUT_LENGTH_MAX + 1 + 1 + 1];
// \n + \0 + extra to detect overly long lines
if (fgets(line, sizeof line, stdin)) {
size_t len = strlen(line);
// Lop off potential trailing \n if desired.
if (len > 0 && line[len-1] == '\n') {
line[--len] = '\0';
}
if (len > EXPECTED_INPUT_LENGTH_MAX) {
// Handle error
// Usually includes reading rest of line if \n not found.
}
The fgets() approach has it limitations too. e.g. (reading embedded null characters).
Handling user input, possible hostile, is challenging.
scanf("%[^\n]",line);
means: scan till \n or an enter key.
scanf("%[^\n]",line);
Will read user input until enter is pressed or a newline character is added (\n) and store it into a variable named line.
Question: what is %[^\n] mean in C?
Basically the \n command prints the output in the next line, but in
case of C gives the Null data followed by the above problem only.
Because of that to remove the unwanted data or null data, need to add
Complement/negotiated symbol[^\n]. It gives all characters until the next line
and keeps the data in the defined expression.
Means it is the Complemented data or rewritten data from the trash
EX:
char number[100]; //defined a character ex: StackOverflow
scanf("%[^\n]",number); //defining the number without this statement, the
character number gives the unwanted stuff `���`
printf("HI\n"); //normaly use of printf statement
printf("%s",number); //printing the output
return 0;

What's the better way to read a char?

i write a little code to simply read a char from the keyboard but the program fails, why? How must i read a char?
int main(int argc, char** argv)
{
char op;
do
{
printf("¿Sigues?");
scanf("%c",&op);
}while(op=='s' || op=='S');
return 0;
}
Your problem is that the %c conversion specifier doesn't cause scanf() to skip leading whitespace. You need to handle the newline character that's still in the stream after reading your input.
The input stream is empty when scanf() is called the first time through the loop, so it waits for you to type something. You type s and hit the Enter key, so the input stream contains the characters s and \n (newline). scanf() removes the s from the input stream and assigns it to op. When scanf() is called the second time, the input stream is not empty; it still has the \n character in it, so scanf() reads it and assigns it to op, which causes the loop condition to fail, so your loop exits.
There are several ways to get around this problem. I'm going to recommend reading strings as opposed to individual characters using fgets(), as follows:
char op[3] = {0}; // input character + newline character + 0 terminator
do
{
printf("¿Sigues?");
if (fgets(op, sizeof op, stdin))
{
/**
* Check for a newline character in the input. If it's not there
* then the user typed in too many characters. In order to keep
* the input stream from getting clogged up with bad input, read
* until we find a newline character.
*/
char tmp[3];
char *newline = strchr(op, '\n');
while (!newline && fgets(tmp, sizeof tmp, stdin))
{
newline = strchr(tmp, '\n');
}
}
else
{
printf("Error while reading input\n");
op[0] = 0;
}
} while (tolower(op[0]) == 's');
op = getc(stdin);
scanf flushes only after reading a newline. it cant be done in platform independent way
You're seeing the line "Sigues" twice because there's a \n still in the input stream. If you type in a character and hit enter there are now two characters in your input stream. Your scanf formatter only specifies one char, so scanf reads in one char and then advances. However, the next character in the stream is a \n, hence the exit from the loop on the second go.
NB. #eduffy's technique of getc(stdin) will do the exact same thing, there's still a \n in stdin. You need to advance past that \n somehow.
How about reading in your char, and then chomping the rest of the stream up to the \n char? I tried this and it works for me:
char op;
do
{
printf("¿Sigues?");
scanf("%c",&op);
while(getchar() != '\n') continue;
}while(op=='s'|| op=='S');

Resources