I am writing a program in C with multiple scanfs, but when running it, whenever I get to a scan that is reading for an integer value, it skips it and puts in a different value that begins executing an endless loop. I have even tried separating each of the scanfs into multiple functions and the same thing happens. I have absolutly no idea what is wrong, or what to do for that matter.
Check the return value. C library functions return status codes for a reason.
The main problem people strike with scanf is that the data isn't what they expected. That can lead to a partial scan, leaving you at an unexpected point in the file for future scans. This may be what's causing your infinite loop and you would normally detect it by ensuring that the return value is what you expect (the number of items you tried to scan). It's a little hard to tell without seeing the code.
C99 states, in section 7.19.6.4 The scanf function:
The scanf function returns the value of the macro EOF if an input failure occurs before any conversion. Otherwise, the scanf function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.
But, almost invariably, input should be retrieved as lines and then processed from there with sscanf, since this allows an easy way to try multiple scans on the input data for different format strings, as many times as it takes to figure out what format the line is in.
For example, the following code is a safe way of retrieving user input with buffer overflow protection and detection, and buffer clearing so excess input doesn't affect the next input operation:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
You can call this code with something like:
char buff[50];
int rc = getLine ("What?> ", buff, sizeof(buff));
if (rc != OK) {
// Error condition, either EOF or to long.
}
// Now use sscanf on buff to your heart's content,
// remembering to check the return value.
If you are reading from stdin, scanf will read from a buffer that ends when you press return.
The first scanf will take in what you're looking for, but the rest of the buffer will remain.
For code:
int num;
scanf("%d", &num);
and input:
1 2 3 4 5
num will be 5, as expected. But
2 3 4 5
will still be in the buffer, so the next scanf you run will not prompt for another input, but instead take that as the input.
Your scanf may be reading residual data from a previous buffer.
Related
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.
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.
I'm pretty new in C, I used to work in Python, and I'm trying to see if something that I read is integer number. If not, to read until I manage to entry a number.
I did some research and I found out that the function scanf actually returns 1 if the read is done suitably, and 0 otherwise.
So, I have written this code, and I don't understand why this is an infinite loop, writing "Give an integer" on the console
#include <stdio.h>
int main() {
int a;
int b = 1;
do {
printf("Give an integer\n");
b = scanf("%d", &a);
} while (b == 0);
}
The problem with scanf() is that it stops reading when the first white space is encountered for most specifiers like "%d", so it's left in the input and that's why reading again would cause a problem if you don't discard such white space because it will then return immediately the next time you call it. There is a mandatory white space that is introduced when you press Enter or Return, the '\n' new line character (or line feed).
If you want to read an integer and make sure you did you can try like this
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int
main(void)
{
long int value; // You can adapt this to use `int'
// but be careful with overflow
char line[100];
while (fgets(line, sizeof(line), stdin) != NULL) {
char *endptr;
value = strtol(line, &endptr, 10);
if ((isspace(*endptr) != 0) && (endptr != line))
break;
}
fprintf(stdout, "%ld\n", value);
return 0;
}
read strtol()'s manual to understand this code
You could as suggested in the comments, remove the white space characters from the input, but IMHO that is harder and you would still have other problems with scanf(), like handing empty input which is not straight forward.
I don t understand why this is an infinite loop, writing "Give an intiger" on the console
The problem is that scanf() does not consume data that it cannot match against the specified format. It leaves such characters unread in the input stream. Therefore, if you try reading again from the same stream with the same format, without consuming at least one character by some other means, then you can be certain that the input will again not be matched. And again. And again.
To avoid your infinite loop, you need to consume at least one character of the non-matching input after each matching failure. There are many ways you could do that; here's a fairly simple one:
#include <stdio.h>
int main() {
int a;
do {
printf("Give an intiger\n");
if (scanf("%d", &a)) {
// breaks from the loop on a successful match or an error
break;
}
// consume the remainder of one line of input without storing it
if (scanf("%*[^\n]") == EOF) {
break;
}
} while (1);
}
That consumes the whole remainder of the line on which the non-matching input is encountered, which will yield less surprising interactive behavior for some inputs than many alternatives would.
If you've a penchant for writing terse code, or if you don't like to break out of the middle of a loop, then you might write the same thing like this:
#include <stdio.h>
int main() {
int a;
do {
printf("Give an intiger\n");
} while ((scanf("%d", &a) == 0) && (scanf("%*[^\n]") != EOF));
}
Because the && operator short circuits, the second scanf() call will be executed only if the first returns zero, and the loop will exit after the first iteration wherein either the first scanf() call returns nonzero or the second returns EOF (indicating an error).
I have this assignment where I have to read till the "?" char and then check if it is followed by number and newline, or newline and then the number and than again newline.
I checked the first char after the "?"
if (scanf("%c",c)=='\n') ...;
but that only works if the first one is a newline, and when it isn't and i want to read the number instead, it cuts the first digit ... for example, it doesn´t read 133 but only 33
... how do i do this?
I also tried puting the char back, but that wouldn't work
please help :)
One advantage of getline over either fgets (or a distant scanf) is that getline returns the actual number of characters successfully read. This allows a simple check for a newline at the end by using the return to getline. For example:
while (printf ((nchr = getline (&line, &n, stdin)) != -1)
{
if (line[nchr - 1] = '\n') /* check whether the last character is newline */
line[--nchr] = 0; /* replace the newline with null-termination */
/* while decrementing nchr to new length */
Use fgets(3), or better yet, getline(3) (like here) to read the entire line, then parse the line using strtol(3) or sscanf(3) (like here)
Don't forget to carefully read the documentation of every function you are using. Handle the error cases - perhaps using perror then exit to show a meaningful message. Notice that scanf and sscanf return the number of scanned items, and know about %n, and that strtol can set some end pointer.
Remember that on some OSes (e.g. Linux), the terminal is a tty and is often line-buffered by the kernel; so nothing is sent to your program until you press the return key (you could do raw input on a terminal, but that is OS specific; consider also readline on Linux).
this line: if (scanf("%c",c)=='\n') ...; will NEVER work.
scanf returns a value that indicates the number of successful parameter conversions.
suggest:
// note: 'c' must be defined as int, not char
// for several reasons including:
// 1) getchar returns an int
// 2) on some OSs (dos/windows) '\n' is 2 characters long
// 3) if checking for EOF, EOF is defined as an int
if( '\n' == (c = getchar() ) )
{ // then found newline
...
#include <stdio.h>
int main (void){
int num;
scanf("%*[^?]?");//read till the "?"
while(1==scanf("%d", &num)){
printf("%d\n", num);
}
return 0;
}
DEMO
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.