Reading multiple lines of input with scanf() - c

Relevant code snippet:
char input [1024];
printf("Enter text. Press enter on blank line to exit.\n");
scanf("%[^\n]", input);
That will read the whole line up until the user hits [enter], preventing the user from entering a second line (if they wish).
To exit, they hit [enter] and then [enter] again. So I tried all sorts of while loops, for loops, and if statements around the scanf() involving the new line escape sequence but nothing seems to work.
Any ideas?

Try this:
while (1 == scanf("%[^\n]%*c", input)) { /* process input */ }

As was yet pointed out, fgets() is better here than scanf().
You can read an entire line with fgets(input, 1024, stdin);
where stdin is the file associated to the standard input (keyboard).
The function fgets() reads every character from the keyboard up to the first new-line character: '\n' (obtained after pressing ENTER key, of course...).
Important: The character '\n' will be part of the array input.
Now, your next step is to verify if all the characters in the array input,
from the first to the '\n', are blanks.
Besides, note that all the characters after the first '\n' in input are garbage, so you have not to check them.
Your program could be as follows:
char input[1024];
printf("Enter text. Press enter on blank line to exit.\n");
while (1) {
if (fgets(input, 1024, stdin) == NULL)
printf("Input Error...\n");
else {
/* Here we suppose the fgets() has reached a '\n' character... */
for (char* s = input; (*s != '\n') && isspace(*s); s++)
; /* skipping blanks */
if (*s == '\n')
break; /* Blank line */
else
printf("%s\n", input); /* The input was not a blank line */
}
}
That code must be written inside your main() block and,
more importantly, it is necessary to include the header <ctype.h> before all,
because the isspace() function is used.
The code is simple: the while is executed for ever, the user enter a line in each iteration, the if sentences checks if some error has happened.
If everything was fine, then a for(;;) statement is executed, which explores the array input to watch if there are just blanks there... or not.
The for iterations continue up to the first new-line '\n' is found, or well, a non-blank character appears.
When for terminates, it means that the last analyzed character, which is held in *s, is a newline (meaning that all earlier characters were blanks), or not (meaning that at least there is some non-blank character in input[], so input is a normal text).
The "ethernal" while(1) is broken only in case that a blank-line is
read (see the break statement in 11th line).

OP says "To exit, they hit [enter] and then [enter] again"
unsigned ConsecutiveEnterCount = 0;
for (;;) {
char buffer[1024];
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
break; // handle error or EOF
}
if (buffer[0] == '\n') {
ConsecutiveEnterCount++;
if (ConsecutiveEnterCount >= 2 /* or 1, not clear on OP intent */) {
break;
}
}
else ConsecutiveEnterCount = 0;
// Do stuff with buffer;
}

#include <stdio.h>
int main(){
char arr[40];
int i;
for( i = 0; i < sizeof(arr); i +=2 ){
scanf("%c%c",&arr[i],&arr[i+1]);
if( arr[i] == '\n' && arr[i+1] == '\n' )
break;
}
printf("%s", arr);
return 0;
}

... I tried all sorts of while loops, for loops, and if statements around the scanf() involving the new line escape sequence but nothing seems to work.
It seems you tried everything that you shouldn't have tried, prior to reading! A C programmer is expected to read manuals lest they want to run into undefined behaviour which causes headaches like the one you've experienced. To elaborate, you can't learn C by guessing like you can Java.
Consider this your lesson. Stop guessing and start reading (the fscanf manual)!
According to that manual:
[ Matches a non-empty sequence of bytes from a set of expected bytes (the scanset).
The emphasis is mine. What you seem to be describing is an empty sequence of bytes, which means that the match fails. What does the manual say about matching failures?
Upon successful completion, these functions shall return the number of successfully matched and assigned input items; this number can be zero in the event of an early matching failure. If the input ends before the first conversion (if any) has completed, and without a matching failure having occurred, EOF shall be returned. If an error occurs before the first conversion (if any) has completed, and without a matching failure having occurred, EOF shall be returned...
Again, the emphasis is mine... This is telling you that like most other C-standard functions, you need to check the return value! For example, when you call fopen you then write some idiom along the lines of if (fp == NULL) { /* handle error */ }.
Where's your error handling? Note that the return value isn't merely a binary selection; where n conversions are performed, there are n+2 possible return values in the range of: EOF, 0 .. n. You should understand what each of those means, before you try to use fscanf.

Related

Why do I have to use gets() function twice in a row? [duplicate]

This question already has answers here:
What is the effect of trailing white space in a scanf() format string?
(4 answers)
Why is the gets function so dangerous that it should not be used?
(13 answers)
Closed 2 years ago.
I have an unusual problem regarding the code below.
void Menu()
{
bool end = 0;
int n;
while (!end)
{
scanf("%d", &n);
switch(n)
{
case 1:
my_strlen_show();
break;
//other irrelevant cases 2-6
case 7:
end = 1;
break;
default:
printf("ERROR");
break;
}
}
}
int my_strlen(const char *str)
{
int count = 0;
for (; *str != '\0' ; str++)
{
count++;
}
return count;
}
void my_strlen_show()
{
char tab[1000];
printf("\n\nEnter a sentence: ");
gets(tab);
gets(tab);
printf("\nWritten sentence has %d characters.\n\n", my_strlen(tab));
return;
}
I have no idea why I have to write gets(tab) twice to get the program to work properly. When I use it once, my_strlren_show() function executes instantly and shows that the sentence has 0 characters. I am aware that I can use other methods such as a scanf() function inside a for loop, but I am curious why this method works in a peculiar way.
Can anyone explain why that is the case? I would be very thankful.
Do not use gets(). Its dangerous unsafety has earned it the dubious distinction of belonging to a very small set of functions that have been withdrawn from the C language standard.
However, you would probably experience the same issue if you changed to fgets:
fgets(tab, sizeof(tab), stdin);
The issue is that gets() and fgets() read through the end of the current line (or until the buffer is filled in the case of fgets()). The preceding scanf() consumed only the bytes through the end of a decimal integer, leaving the rest of that line on the input stream, waiting to be read. That includes at least a newline marking the end of the line. That has to be consumed before the wanted input can be read with fgets() or gets(). One way to accomplish that would be:
if ((scanf("%*[^\n]") == EOF) || (getchar() == EOF)) {
// handle end-of-file or I/O error ...
}
The scanf reads and discards any characters preceding the next newline, and, supposing that the end of the file is not reached and no I/O error occurs, the getchar() consumes the newline itself.
Your first scanf only reads a single integer from stdin. When you press enter after inputting the integer, a newline (\n) is sent to the stdin, which just stays there - waiting to be picked up by the next function reading from stdin.
The next gets then reads this newline and instantly returns. So you needed another gets to actually read the input.
With that said, you should never even use gets in the first place - it's a deprecated function. On top of that, consider using fgets for reading input. scanf is really an input parsing function, not a reading function. It only reads what it can parse, and leaves everything else in the stdin.
If you still decide to go the scanf route, you should consume the newline on the first input using "%d\n" - not only that, you must also check the return value for scanf, it returns the number of values it was able to parse.
Now the next fgets call won't have to consume the left over newline. It'll wait for another line of user input (note that the newline will be included in the buffer fgets reads into)-
char tab[1000];
printf("\n\nEnter a sentence: ");
if (fgets(tab, 1000, stdin) == NULL)
{
// handle error during reading
return;
}
// tab now has the user input, delimited with a `\n`
// if you want to get rid of this newline - use `strcspn`
tab[strcspn(name, "\n")] = 0
Docs on strcspn
I would however, recommend you to go the full fgets route and do the integer parsing with sscanf.
int n;
char buff[4096];
if (fgets(buff, 4096, stdin) == NULL)
{
// handle error during reading
return;
}
if (sscanf(tab, "%d", &n) != 1)
{
// parsing failed - sscanf should've parsed exactly 1 value
// handle error
return;
}
// use n here
Here's a full guide on how to move away from scanf - which will mention this specific problem.

How to avoid pressing enter twice when using getchar() to clear input buffer?

I have this program:
#include <stdio.h>
#define SIZE 19
int main(){
char string[SIZE];
while (string[0] != 'A'){
printf("\nEnter a new string.\n");
fgets(string,SIZE,stdin);
int storage = 0;
while (storage != '\n')
{
storage = getchar();
}
}
}
The nested while loop with getchar() exists in case the inputted string exceeds the maximum number of characters string[] can hold. If that is not there, inputting a string with, say, 20 characters, would cause the output to be:
Enter a new string.
12345123451234512345
Enter a new string.
Enter a new string.
The problem is that this requires me to press enter twice in order to enter a new string: once for 'fgets' and one for the nested while loop (this is my understanding of what's going on).
Is there a way to change this so I only have to press 'Enter' once, or possibly a way to change the entire while loop into something more elegant?
If the buffer that receives from fgets contains a newline, you know it read everything that was inputted so you don’t need to do anything else. If not, then you use the extra loop to flush the buffer.
You are thinking correctly, you just need to think through how and when you need to empty the input buffer a bit further.
All line-oriented input functions (fgets and POSIX getline) will read, and include, the trailing '\n' in the buffers they fill (fgets only when sufficient space is provided in the buffer).
When using fgets, you have only two possible returns, (1) a pointer to the buffer filled, or (2) "NULL on error or when end of file occurs while no characters have been read."
In case fgets returns a valid pointer, then it is up to you to determine whether a complete line of input was read, or whether the input exceeds the buffer size, leaving characters in the input buffer unread.
To make that determination, you check whether the last character in the buffer is '\n' and if not, whether the buffer contains SIZE-1 characters indicating that characters remain in the input buffer. You can do that a number of ways, you can use strchr (to get a pointer to the '\n'), strcspn (to get an index to it) or good old strlen (to get the length of the string) and then check the character at len-1.
(a note on preference, you can use whatever method you like, but in either case of strcspn or strlen, save the index or length so it can be used to validate whether the input exceeded the buffer size or whether the user ended input by generating a manual EOF. You save the index or length to prevent having to make duplicate function calls to either)
It is also helpful to create a simple helper-function to clear the input buffer to avoid placing loops everywhere you need the check. A simple function will do the trick, e.g.
/* simple function to empty stdin */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
of if you prefer the more-compact, but arguably less readable version, a single for loop will do, e.g.
void empty_stdin (void)
{
for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}
}
The remainder of your example can be structured to complete each of the tests described above to provide input handling as you have described (although using the 1st character of the buffer being 'A' to control the loop is a bit strange), e.g.
#include <stdio.h>
#include <string.h>
#define STRSIZE 19
/* simple function to empty stdin */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
char string[STRSIZE] = ""; /* initialize string all 0 */
while (*string != 'A') { /* up to you, but 'A' is a bit odd */
size_t len = 0; /* variable for strlen return */
printf ("enter a string: "); /* prompt */
if (!fgets (string, STRSIZE, stdin)) { /* validate read */
putchar ('\n'); /* tidy up with POSIX EOF on NULL */
break;
}
len = strlen (string); /* get length of string */
if (len && string[len-1] == '\n') /* test if last char is '\n' */
string[--len] = 0; /* overwrite with nul-character */
else if (len == STRSIZE - 1) /* test input too long */
empty_stdin(); /* empty input buffer */
}
return 0;
}
An arguably more useful approach is to have the loop exit if nothing is input (e.g. when Enter alone is pressed on an empty line). The test would then be while (*string != '\n'). A better approach rather is simply controlling your input loop with while (fgets (string, STRSIZE, stdin)). There, you have validated the read before entering the loop. You can also wrap the whole thing in a for (;;) loop and control the loop exit based on any input condition you choose.
Those are all possibilities to consider. Look things over and let me know if you have further questions.
fgets() does read the newline IF (and only if) the buffer is long enough to reach and contain it, along with a trailing nul terminator.
Your sample input is 20 characters, which will be followed by a newline, and then a nul terminator. That won't go into a buffer of 19 characters.
The simple way is to use fgets() in a loop, until the newline is included in the buffer.
printf("\nEnter a new string.\n");
do
{
fgets(string,SIZE,stdin);
/*
handle the input, noting it may or may not include a trailing '\n'
before the terminating nul
*/
} while (strlen(string) > 0 && string[strlen(string) - 1] != '\n');
This loop will clear input up to and including the first newline, and also allow you to explicit handle (discard if needed) ALL the input received. It is therefore not necessary to use a second loop with getchar().
You haven't checked if fgets() returns NULL, so neither have I. It is advisable to check, as that can indicate errors on input.

Detecting new line in C

My code goes something like this:
char k[1000];
while(1){
scanf("%s",&k);
if(k[0] == '\n'){
exit(0);}
/* Do some processing on k */
memset(k,0,1000);
}
My intention is to process user input per normal and terminate when user inputs empty string or new line. This doesn't seem to work.
Could you guys help on what went wrong?
On related note, I also want to terminate if it is the end of file, how should I do it for EoF?
Thank you in advance for all the help.
First off -- don't use scanf for user input. It is a minefield of subtle issues just waiting to bite new C programmers, instead use a line-oriented input function like fgets or POSIX getline. Both read up to (and including) the trailing '\n' every time (as long as you provide a buffer of sufficient size for fgets -- otherwise it just keep reading blocks of characters of its buffer size until it encounters a '\n' or EOF)
So to read user input until an empty-string or EOF is encountered, you could simply do something like the following:
#include <stdio.h>
#include <string.h>
#define MAXC 1000
int main (void) {
char k[MAXC] = "";
for (;;) { /* loop until empty-string of EOF */
printf ("input: "); /* prompt for input */
if (fgets (k, MAXC, stdin)) { /* read line (MAXC chars max) */
if (*k == '\n') { /* test for empty-string */
fprintf (stderr, "empty-string! bye.\n");
break;
}
size_t l = strlen (k); /* get length of string */
if (l && k[l - 1] == '\n') /* check if last char is '\n' */
k[--l] = 0; /* overwrite with nul-terminator */
printf ("got input: %s\n", k);
}
else { /* got EOF */
fprintf (stderr, "EOF -- bye.\n");
break;
}
}
return 0;
}
Example Use/Output
>bin\fgets_user_input.exe
input: this
got input: this
input: is some
got input: is some
input: input
got input: input
input:
empty-string! bye.
>bin\fgets_user_input.exe
input: this is more
got input: this is more
input: ^Z
EOF -- bye.
>bin\fgets_user_input_cl.exe
input: it works the same
got input: it works the same
input: compiled by gcc
got input: compiled by gcc
input: or by cl.exe (VS)
got input: or by cl.exe (VS)
input:
empty-string! bye.
(note: for Linux Ctrl+d generates the EOF, I just happened to be on windoze above)
Like ever so often, the problem here is inappropriate usage of scanf(). scanf() is not for reading input but for parsing it and the format-string tells it how to parse.
In your case, %s is looking for a sequence of non-whitespace characters (IOW, a word) and it skips any leading whitespace. \n (newline) is just a whitespace character, so it is always skipped -- your scanf() will just wait for more input until it can parse %s.
For more information on scanf() pitfalls, I recommend you my beginners' guide away from scanf(). As a rule of thumb, with interactive input (which is the default), scanf() is almost always wrong.
There's another huge problem with scanf("%s", ...): It will happily overflow any buffer you provide it, as long as the input contains non-whitespace characters, just like gets() which was even removed from C for exactly that reason: Buffer overflows are extremely dangerous! Therefore always use a field-width, in your case scanf("%999s", ...). This parses a maximum of 999 characters, leaving one for the necessary 0 byte terminating a string.
But now for how to do it correctly: There are several functions in C that are indeed for reading input and one of them is for reading a line of input: fgets(). In your code, it would look like this:
char k[1000];
while(fgets(k, 1000, stdin)){
if(k[0] == '\n'){
exit(0);
}
/* Do some processing on k */
memset(k,0,1000);
}
I used your original code here, still some further remarks:
It would be better to define a macro instead of using the magic number 1000, e.g. #define INPUTSIZE 1000 and use this instead, like char k[INPUTSIZE];, fgets(k, INPUTSIZE, stdin) etc.
Clearing the whole array is not needed, so to avoid unnecessary work, replace the memset() with just k[0] = '\0'; or similar. A C string ends at the first 0 byte, so this is enough to make k hold an empty string. If your program does nothing more than shown here, you could even get rid of this completely, as the next fgets() call overwrites the array anyways (or returns NULL on error, which would stop the loop).
Also note that fgets() reads the whole line including the newline character at the end, so keep this in mind when processing the contents of k.
This one is guaranteed to give everything except newlines (and EOFs) for you:
char k[1000];
scanf("%[^\n]", k);
And when it returns, the next character is guaranteed to be either a newline, or non-existent at all (EOF reached). Get it like this:
int next_char = getcgar();
if (next_char == EOF){
your_eof_process();
}
else if (nexr_char == '\n'){
your_newline_process();
}
Personally, I would do it using only getchar():
char k[1000];
int ind, tempc;
for (ind = 0; ind < sizeof k; ind ++){
tempc = getchar();
if (tempc == '\n'){
// Some stuff
}
else if (tempc == EOF){
// Other stuff
}
else {
k[ind] = tempc;
}
}
k[sizeof(k)-1] = '\0';

While loops repeats with scanf equal to number of characters read

I have a program that is meant to take commands the first question is the format the commands will be taken in command line or file by typing c or f
if neither is typed the while loop repeats without allowing input equal to the number of characters in the incorrect input instead of stopping and allowing scanf to grab input again. I don't use it's return values at any point so I am at a loss as to why this happens. correctly entering 'f' or 'c' does not cause the problem.
any help would be greatly appreciated
#include<stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define true 1
#define false 0
typedef int bool;
double **temp_array;
double temp1d_array[36];
char consolep[100];
char *fp1;
FILE *fp;
char string_IO1[50];
char string_temp[50];
char buffer[50];
char current_command[10];
int halt = 0;
char *strtodptr;
void main(){
printf("welcome \n");
char IO;
char read[250];
char file_console;
int IO_method = 0;
char command[10];
char type_IO;
char type_of_var_IO;
char dim_IO[3];
char array_string_IO[40];
//console or file
//decide IO Method loop 1
while (IO_method==0)
{
printf("please type 'c'for console or 'f' for file to select input type\n");
scanf("%c", &file_console);
//if console
if(file_console =='c')
{
IO_method=1;
printf("method is console\n");
}
//if file
else if(file_console=='f')
{
IO_method=2;
printf("method is file\n");
printf("please enter a file directory\n");
scanf("%s",&string_IO1);
}
else
{
printf("invalid entry\n");
file_console=NULL;
IO_method=0;
}
}}//code here continues but i compiled it without and has no bearing on the error.
The calls to scanf() in the posted code leave characters behind in the input stream. If, for example, the user enters g at the first prompt, pressing ENTER after, the \n character is left behind. If the user enters more than one character, the extra characters are left behind. The later calls to I/O functions will pick up these unexpected characters, causing the program to misbehave.
One solution is to write a little function to clear the input stream after such I/O function calls:
void clear_input(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
This function discards any characters that remain in the input stream (up to and including the first newline character). Note that c must be an int to ensure that EOF is handled correctly. Also note that this function should only be called when the input stream is not empty; an empty input stream will cause the call to getchar() to block, waiting for input.
For example, after the first call to scanf() you know that there is at least a \n character still in the input stream (maybe more characters preceding the newline); just call clear_input() to clean the input stream before the next I/O call:
scanf("%c", &file_console);
clear_input();
The value returned by scanf() should be checked in robust code; the number of successful assignments made is returned, or EOF in rare the event of an error. This can help to validate input.
A better option would be to use fgets() to read from stdin and fetch a line of input to a buffer, and then use sscanf() to parse the buffer. One advantage here is that fgets() will read all characters up to, and including, a newline character, provided there is adequate space in the buffer. So, allocate a generous buffer[] to make it likely that no reasonable input can fail to be contained in the buffer. If you need to be more careful, you can check the input buffer for a \n character (using strchr(), for example). If the \n character is found in the buffer, then the input stream is empty, otherwise there are extra characters left behind, and the clear_input() function can be called to clean things up:
#include <stdlib.h>
#include <string.h>
...
char buffer[1000];
char end;
while (IO_method==0)
{
printf("please type 'c'for console or 'f' for file to select input type\n");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* Handle input error */
perror("Error in fgets()");
exit(EXIT_FAILURE);
}
/* May need to clear input stream, if input is too large */
if (strchr(buffer, '\n') == NULL) {
clear_input();
}
/* Input again if input is not as expected */
if (sscanf(buffer, "%c%c", &file_console, &end) != 2 || end != '\n') {
continue;
}
...
Here, buffer[] is declared with a generous size to hold all reasonable inputs. fgets() places the input in buffer, up to and including the newline (space-permitting). Note that the return value from fgets() is checked; a null pointer is returned if there is a rare I/O error. Next, strchr() is used to check for the \n in buffer; it is expected to be present, but if not, a null pointer is returned, signalling that there are still characters in the input stream to be cleared. Next, sscanf() is used to parse the buffer. Here, note that end is used store the character after the user-input character. In expected input, this is a \n character. If the user enters too many characters, testing end will reveal this, and input is taken again.
Also note that in the posted code, string_IO1 was not declared (and not a great name, since the characters in IO1 are difficult to distinguish on a screen); if this is a character array, then the call to scanf() should have looked like:
scanf("%s",string_IO1);
And, file_console has been declared as a char, so the assigment file_console = NULL; is wrong, since NULL is the null pointer macro, not an integer type.

Recognising an empty line from stdin in C

I'm having some hard time trying to recognise an empty line on the standard input in C. I'm having the following code:
char *line = NULL;
int done = 0;
while (!done) {
scanf("%m[^\n]", &line);
if (line != NULL)
//do something with line
else
done = 1;
scanf("\n");
free(line);
The lines are supposed to be user's commands. Let's say that he is only allowed to call
insert something
delete something
or
exit
In any other case the program should output, let's say, "command not allowed". I can do that in every case except one - when there's an empty line on the input - I don't know how I can recognise one. I would appreciate some help on that.
Instead of using scanf(), used fgets() or *nix getline().
scanf() is designed to read formatted data - it works marginally well with lines.
fgets() is designed to read a line (0 or more characters up to and including a final '\n') and converting that to a C string by appending a null character '\0' to the destination buffer.
char line[100];
while (!done) {
// scanf("%m[^\n]", &line);
if (fgets(line, sizeof line, stdin) == NULL) {
// EOF or input error occurred, for now let us just clear line
line[0] = 0;
}
// get rid of potential trailing \n
line[strcspn(line, "\n")] = 0;
if (line[0])
//do something with line
else
done = 1;
}
All of the information in this answer was extracted from man scanf.
The %[ format code will not match an empty string:
[ Matches a nonempty sequence of characters from the specified set of accepted characters
Remember that scanf has a very useful return value:
These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.
You should always check the return value of scanf, because the output arguments have unspecified values if the corresponding input item couldn't be successfully matched.
In this case, the return value will tell you whether there was a non-empty string preceding the newline character.
As presented, your code has a memory leak (assuming that more than one line is read), because the m modifier causes memory to be allocated, without ever looking at the value originally stored in the corresponding argument. So if the argument held the address of previously allocated storage, it will be overwritten with the address of the newly-allocated storage and the previous allocation will leak.
The loop should be:
while (!done) {
line = NULL; /* Not strictly necessary */
if (scanf("%m[^\n]", &line) == 1) {
/* Do something with line */
free(line);
} else {
/* Handle an empty line */
}
/* skip trailing newline. See below. */
getchar();
}
scanf("\n") does not only skip a single newline character. It is not different from scanf(" "); any whitespace in a scanf format:
matches any amount of white space, including none, in the input.
If you just want to skip the single newline character, use getchar().

Resources