What's the better way to read a char? - c

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');

Related

Taking multiple scans in 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);
}
}

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.

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);

Reading of standard input with fgets not waiting for input

Having this piece of code:
int main(void)
{
char str[4];
do
{
if (fgets(str,sizeof(str),stdin) == NULL)
break;
printf("\n %s \n", str);
}while (strncmp(str,"q\n",sizeof("q\n")));
return 0;
}
if i type more than 4 characters, then two lines are displayed. if i type 123456 and then press enter, does input store ['1','2','\n','\0'] or ['1','2','3','\0']? hen the second time printf is reached if i only press enter key one time?. How i can avoid this behaviour? I would like type 123456 and then get:
1234
The reason why fgets is only reading partial input is because the str array is too small. You need to increase the buffer size of str array.
Also remember that fgets will pick up \n ( enter / return ) that you press after giving your input.
To get rid of the \n do this:
fgets(str,sizeof(str),stdin);
str[strlen(str)-1] = '\0';
There is one MAJOR issue with your while condition ... I am not sure what your are trying to do there but strcmp is used to see if two strings are the same or not ... what you are doing is trying to compare a string to the size of something ...
There are multiple problems in your code:
you do not include <stdio.h>.
fgets() is given a very short buffer: 4 bytes, allowing for only 3 characters to be input at a time, including the '\n'. If you type more characters, they are buffered by the terminal and the standard stream library. It will take several calls to fgets() to read them all, 3 bytes at a time.
Your termination test is bogus: strncmp(str, "q\n", sizeof("q\n")) compares the string read by fgets() with "q\n" upto a maximum number of characters of 3 because sizeof("q\n") counts the q, the \n and the null terminator. You should just use strcmp() for this test.
You print the string with printf("\n %s \n", str);. Note however that a regular line read into str will contain the trailing newline so the printf call will actually output 2 lines.
Here is a modified version:
#include <stdio.h>
#include <string.h>
int main(void) {
char str[80];
while (fgets(str, sizeof(str), stdin) != NULL) {
str[strcspn(str, "\n")] = '\0'; // strip the newline if present
printf("\n %s \n", str);
if (!strcmp(str, "q"));
break;
}
return 0;
}
Try using getc() or fgetc() before using fgets()
When you use a scanf(), you press enter key (newline) which operates as accepting the input and transferring the input from stdin (standard input device) to your program.
scanf() itself does not consume the newline pressed. So, we need something down the code which will accept this newline and prevent this newline from acting as an input to the subsequent fgets(). This newline can be accepted using getc() or fgetc(), which should be written before fgets().
fgetc(stdin); OR getc(stdin);

Changing the scanf() delimiter

My objective is to change the delimiter of scanf to "\n".
I tried using scanf("%[^\n]s",sen); and works fine for single inputs.
But when i put the same line inside a for loop for multiple sentences it gives me garbage values.
Does anyone know why?
Here's my code:
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
}
Consider this (C99) code:
#include <stdio.h>
int main(void)
{
char buffer[256];
while (scanf("%255[^\n]", buffer) == 1)
printf("Found <<%s>>\n", buffer);
int c;
if ((c = getchar()) != EOF)
printf("Failed on character %d (%c)\n", c, c);
return(0);
}
When I run it and type in a string 'absolutely anything with spaces TABTABtabs galore!', it gives me:
Found <<absolutely anything with spaces tabs galore!>>
Failed on character 10 (
)
ASCII (UTF-8) 1010 is newline, of course.
Does this help you understand your problem?
It works in this case (for a single line) but if I want to take multiple lines of input into an array of arrays then it fails. And I don't get how scanf returns a value in your code?
There are reasons why many (most?) experienced C programmers avoid scanf() and fscanf() like the plague; they're too hard to get to work correctly. I'd recommend this alternative, using sscanf(), which does not get the same execration that scanf() and fscanf() do.
#include <stdio.h>
int main(void)
{
char line[256];
char sen[256];
while (fgets(line, sizeof(line), stdin) != 0)
{
if (sscanf(line, "%255[^\n]", sen) != 1)
break;
printf("Found <<%s>>\n", sen);
}
int c;
if ((c = getchar()) != EOF)
printf("Failed on character %d (%c)\n", c, c);
return(0);
}
This reads the line of input (using fgets() which ensures no buffer overflow (pretend that the gets() function, if you've heard of it, melts your computer to a pool of metal and silicon), then uses sscanf() to process that line. This deals with newlines, which are the downfall of the original code.
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
}
Problems:
You do not check whether scanf() succeeded.
You leave the newline in the buffer on the first iteration; the second iteration generates a return value of 0 because the first character to read is newline, which is the character excluded by the scan set.
The gibberish you see is likely the first line of input, repeated. Indeed, if it were not for the bounded loop, it would not wait for you to type anything more; it would spit out the first line over and over again.
Return value from scanf()
The definition of scanf() (from ISO/IEC 9899:1999) is:
§7.19.6.4 The scanf function
Synopsis
#include <stdio.h>
int scanf(const char * restrict format, ...);
Description
2 The scanf function is equivalent to fscanf with the argument stdin interposed
before the arguments to scanf.
Returns
3 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.
Note that when the loop in my first program exits, it is because scanf() returned 0, not EOF.
%[^\n] leaves the newline in the buffer. %[^\n]%*c eats the newline character.
In any case, %[^\n] can read any number of characters and cause buffer overflow or worse.
I use the format string %*[^\n]%*c to gobble the remainder of a line of input from a file. For example, one can read a number and discard the remainder of the line by %d%*[^\n]%*c. This is useful if there is a comment or label following the number, or other data that is not needed.
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
getchar();
}
Hope this helps ... actually "\n" remains in stream input buffer... Ee need to flush it out before scanf is invoked again
I know I am late, but I ran into same problem after testing C after a long time.
The problem here is the new line is considered as input for next iteration.
So, here is my solution, use getchar() to discard the newline the input stream:
char s[10][25];
int i;
for(i = 0; i < 10; i++){
printf("Enter string: ");
scanf("%s", s[i]);
getchar();
}
Hope it helps :)
While using scanf("%[^\n]", sen) in a loop, the problem that occurs is that the \n stays within the input buffer and is not flushed. As a result next time, when the same input syntax is used, it reads the \n and considers it as a null input. A simple but effective solution to address this problem is to use:
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]%*c",sen);
printf("%s\n",sen);
}
%*c gets rid of the \n character in the input buffer.

Resources