Issues with scanf() and accepting user input - c

I am trying to take in user input with spaces and store it in an array of characters.
After, I want to take in a single character value and store it as a char.
However, when I run my code, the prompt for the character gets ignored and a space is populated instead. How can I take in an array of chars and still be allowed to prompt for a single character after?
void main()
{
char userIn[30];
char findChar;
printf("Please enter a string: ");
scanf("%[^\n]s", userIn);
printf("Please enter a character to search for: ");
scanf("%c", &findChar);
//this was put here to see why my single char wasnt working in a function I had
printf("%c", findChar);
}

scanf("%c", &findChar); reads the next character pending in the input stream. This character will be the newline entered by the user that stopped the previous conversion, so findChar will be set to the value '\n', without waiting for any user input and printf will output this newline without any other visible effect.
Modify the call as scanf(" %c", &findChar) to ignore pending white space and get the next character from the user, or more reliably write a loop to read the read and ignore of the input line.
Note also that scanf("%[^\n]s", userIn); is incorrect:
scanf() may store bytes beyond the end of userIn if the user types more than 29 bytes of input.
the s after the ] is a bug, the conversion format for character classes is not a variation of the %s conversion.
Other problems:
void is not a proper type for the return value of the main() function.
the <stdio.h> header is required for this code.
Here is a modified version:
#include <stdio.h>
int main() {
char userIn[30];
int c;
char findChar;
int i, found;
printf("Please enter a string: ");
if (scanf("%29[^\n]", userIn) != 1) {
fprintf(stderr, "Input failure\n");
return 1;
}
/* read and ignore the rest of input line */
while ((c = getchar()) != EOF && c != '\n')
continue;
printf("Please enter a character to search for: ");
if (scanf("%c", &findChar) != 1) {
fprintf(stderr, "Input failure\n");
return 1;
}
printf("Searching for '%c'\n", findChar);
found = 0;
for (i = 0; userIn[i] != '\0'; i++) {
if (userIn[i] == findChar) {
found++;
printf("found '%c' at offset %d\n", c, i);
}
}
if (!found) {
printf("character '%c' not found\n", c);
}
return 0;
}

scanf("%[^\n]s", userIn); is a bit weird. The s is guaranteed not to match, since that character will always be \n. Also, you should use a width modifier to avoid a buffer overflow. Use scanf("%29[^\n]", userIn); That alone will not solve the problem, since the next scanf is going to consume the newline. There are a few options. You could consume the newline in the first scanf with:
scanf("%29[^\n]%*c", userIn);
or discard all whitespace in the next call with
scanf(" %c", &findChar);
The behavior will differ on lines of input that exceed 29 characters in length or when the user attempts to assign whitespace to findChar, so which solution you use will depend on how you want to handle those situations.

Related

Program is not accepting second string and giving output directly

Here I want to compare two strings in case2. case 1 works well but when I go to case 2 it's not asking for second string input and directly prints "Both strings are different"[1]
[1]: https://i.stack.imgur.com/l2J6L.jpg
#include <stdio.h>
#include <stdlib.h>
#define size 20
int main ()
{
char str1[size],str2[size];
int operation,error=0,i=0;
printf("Enter String: ");
fgets(str1, size, stdin);
do {
printf("1.Copy\n2.Compare\n3.Exit\nWhich operation you want to do:");
scanf("%d",&operation);
switch (operation) {
case 1:
for (int i=0; str1[i] != '\0'; i++) {
str2[i] = str1[i];
}
printf("First string: %s\n",str1);
printf("Second string: %s\n",str2);
break;
default:
printf("Error");
break;
case 2:
printf("Enter second string: "); // it's not executing (Not takin input) and directly i get o/p of line 39
fgets(str2, size, stdin);
for (i=0; str2[i] != '\0'; i++) {
if (str1[i] != str2[i]) {
error++;
}
}
if (error == 0) {
printf("Both strings are same.\n");
}
else
printf("Both strings are not same.\n");
break;
}
} while (operation != 3);
}
As scanf leaves behind a dangling newline character \n it causes the fgets to not wait for the input from the user. Try flushing the input buffer by using getchar.
Update: Added loop to remove all the characters which are skipped by the scanf but can be entered by the user like extra white spaces after the number.
...
do {
printf("1.Copy\n2.Compare\n3.Exit\nWhich operation you want to do:");
scanf("%d",&operation);
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
switch (operation) {
...
Reference: faq.cprogramming.com
Since your strings are lines, scanf() is not a good choice except for getting the integer value, and to clean the buffer of everything after that (might be all sorts of junk, never trust a user), do a fgets into str2. Your new lines will compare, too, if they are identical. You should also test the return from scanf is 1, saying you got a number! What if a user types in 'x' as the number? If you want to ask again, you need to clean the junk out of the buffer. Remember that, since you have 'cooked' input, nothing is sent until the user hits enter, so you always need to deal with the new line character. If all you do is scanf in numbers, scanf will got through an new line as white space seeking a digit, but you are doing mixed string and number input.
You need to compare a null to mis-compare if one string is a prefix of the other, so in 'for' test 'i < size' but break out of the loop if both strings have a null at the same point ( !str1[i] && !str2[i] ) or on the first miscompare (setting error). There is no point in comparing past the first miss! In the prefix case, the null mis-compares some other char value.
Since trailing spaces are part of your string, you might print them in single quotes (after removing the new line).

fgets() doesn't work as expected in C

Given the following code:
#include <stdio.h>
int main()
{
int testcase;
char arr[30];
int f,F,m;
scanf("%d",&testcase);
while(testcase--)
{
printf("Enter the string\n");
fgets(arr,20,stdin);
printf("Enter a character\n");
F=getchar();
while((f=getchar())!=EOF && f!='\n')
;
putchar(F);
printf("\n");
printf("Enter a number\n");
scanf("%d",&m);
}
return 0;
}
I want a user to enter a string, a character and a number until the testcase becomes zero.
My doubts / questions:
1.User is unable to enter a string. It seems fgets is not working. Why?
2.If i use scanf instead of fgets,then getchar is not working properly, i.e whatever character I input in it just putchar as a new line. Why?
Thanks for the help.
Mixing functions like fgets(), scanf(), and getchar() is error-prone. The scanf() function usually leaves a \n character behind in the input stream, while fgets() usually does not, meaning that the next call to an I/O function may or may not need to cope with what the previous call has left in the input stream.
A better solution is to use one style of I/O function for all user input. fgets() used in conjunction with sscanf() works well for this. Return values from functions should be checked, and fgets() returns a null pointer in the event of an error; sscanf() returns the number of successful assignments made, which can be used to validate that input is as expected.
Here is a modified version of the posted code. fgets() stores input in a generously allocated buffer; note that this function stores input up to and including the \n character if there is enough room. If the input string is not expected to contain spaces, sscanf() can be used to extract the string, leaving no need to worry about the newline character; similarly, using sscanf() to extract character or numeric input relieves code of the burden of further handling of the \n.
#include <stdio.h>
int main(void)
{
int testcase;
char arr[30];
char F;
int m;
char buffer[1000];
do {
puts("Enter number of test cases:");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
} while (sscanf(buffer, "%d", &testcase) != 1 || testcase < 0);
while(testcase--)
{
puts("Enter the string");
/* if string should not contain spaces... */
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
sscanf(buffer, "%29s", arr);
printf("You entered: %s\n", arr);
putchar('\n');
puts("Enter a character");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
sscanf(buffer, "%c", &F);
printf("You entered: %c\n", F);
putchar('\n');
do {
puts("Enter a number");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
} while (sscanf(buffer, "%d", &m) != 1);
printf("You entered: %d\n", m);
putchar('\n');
}
return 0;
}
On the other hand, if the input string may contain spaces, fgets() can read input directly into arr, but then the stored string will contain a \n character, which should probably be removed. One way of doing this is to use the strcspn() function to find the index of the \n:
#include <string.h> // for strcspn()
/* ... */
puts("Enter the string");
/* or, if string may contain spaces */
if (fgets(arr, sizeof arr, stdin) == NULL) {
/* handle error */
}
/* replace newline */
arr[strcspn(arr, "\r\n")] = '\0';
printf("You entered: %s\n", arr);
putchar('\n');
/* ... */
Note that a maximum width should always be specified when using %s with the scanf() functions to avoid buffer overflow. Here, it is %29s when reading into arr, since arr can hold 30 chars, and space must be reserved for the null terminator (\0). Return values from sscanf() are checked to see if user input is invalid, in which case the input is asked for again. If the number of test cases is less than 0, input must be entered again.
Finally got the solution how can we use scanf and fgets together safely.
#include <stdio.h>
int main()
{
int testcase,f,F,m;
char arr[30];
scanf("%d",&testcase);
while((f=getchar())!=EOF && f!='\n')
;
while(testcase--)
{
printf("Enter the string\n");
fgets(arr,30,stdin);
printf("Enter a character\n");
F=getchar();
while((f=getchar())!=EOF && f!='\n')
;
putchar(F);
printf("\n");
printf("Enter a number\n");
scanf("%d",&m);
while((f=getchar())!=EOF && f!='\n')
;
}
}
We need to make sure that before fgets read anything,flushout the buffer with simple while loop.
Thanks to all for the help.
A simple hack is to write a function to interpret the newline character. Call clear() after each scanf's
void clear (void){
int c = 0;
while ((c = getchar()) != '\n' && c != EOF);
}
Refer to this question for further explaination: C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf

EOF not working as expected (C)

I'm trying to use the EOF function but it doesn't work as I expect it. In the debugger mode it doesn't detect the second "scanf" function and just carries on. It keeps on missing out the "scanf" function now and then. Code is posted below
int main() {
char tempString;
int i = 0;
printf("Enter your letter\n");
scanf_s("%c", &tempString);
while (tempString != EOF) {
printf("You entered:%c\n", tempString);
scanf_s("%c", &tempString);
}
}
I have also tried it using the getchar() function but the same thing occurs, code is posted below:
int main() {
char tempString;
int i = 0;
printf("Enter your letter\n");
while ((tempString = getchar()) != EOF) {
printf("You entered:%c\n", tempString);
}
}
Thanks for reading
EDIT:
Firstly you omitted the length argument required by scanf_s for %c and %s formats.
Second, the %c format takes the next character from the input buffer. At the second (and subsequent) entries there was a newline left in the input buffer from the first input. Adding a space before the %c format specifier cleans off that leading whitespace.
Other formats, such as %s and %d do ignore leading whitespace, but not %c.
Thirdly, with scanf the use of EOF is not the way to go, you should control the loop with the return value from scanf which tells you the number of items successfully read.
This program starts by using scanf_s. The second entry ignores the newline after the first entry.
Then it moves to using getchar. In this test the function return value is int, so that's my data type here. That way EOF (-1) won't conflict with any required character data. Note that getchar starts by reading the newline left after the previous scanf_s (which only ignores leading whitespace.
#include <stdio.h>
int main(void)
{
char ch_scanf; // char type
int ch_getchar; // int type
printf("Using scanf_s\n");
if (scanf_s(" %c", &ch_scanf, 1) == 1) { // consumes any leading whitespace
printf("scanf_s value: %d\n", ch_scanf);
}
if (scanf_s(" %c", &ch_scanf, 1) == 1) { // consumes any leading whitespace
printf("scanf_s value: %d\n", ch_scanf);
}
printf("\nUsing getchar\n");
while ((ch_getchar = getchar()) != EOF) {
printf("getchar value: %d\n", ch_getchar);
}
return 0;
}
Sample session:
Using scanf_s
A
scanf_s value: 65
B
scanf_s value: 66
Using getchar
getchar value: 10
C
getchar value: 67
getchar value: 10
^Z
Finally if you want to use the standard library function scanf without MSVC ticking you off, you can do it like this
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
try this
#include <stdio.h>
int main(void) {
char tempString;
printf("Enter your letter\n");
while (scanf_s("%c%*c", &tempString, 1) != EOF) {//%*c for consume newline, 1 is buffer size
printf("You entered:%c\n", tempString);
}
return 0;
}
int tempString;//int for check EOF
printf("Enter your letter\n");
while ((tempString = getchar()) != EOF) {
printf("You entered:%c\n", tempString);
getchar();//consume newline
}
The behaviour of scanf() function in C
Is to read the input from the keyboard buffer till it encounters EOF (ie; till we
press enter key)
In general, it is not advisable to use "%c" in C to read an input character because
The value is collected in keyboard buffer till we hit enter and we could not restrict user entering single character
So, the best way to obtain a character is by using getchar() function.
In the program you have provided you can use any other character to check for end and not EOF since it is used in scanf() implementation to mark the input end.
You may other keys like esc to check for the end
#include <stdio.h>
#include <stdlib.h>
#define esc 27
int main()
{
char ch;
while((ch = getchar()) != esc) {
//print the entered character here
}
}
To know in depth about scanf() implementation look into this scanf() source code

How to read a integer followed by a string in C? [duplicate]

This question already has an answer here:
How to read / parse input in C? The FAQ
(1 answer)
Closed 6 years ago.
I am trying to write a simple program which will read two input lines, an integer followed by a string. However, it doesn't seem to work for me.
int main()
{
int i;
char str[1024];
scanf("%d", &i);
scanf("%[^\n]", str);
printf("%d\n", i);
printf("%s\n", str);
return 0;
}
Immediately after entering the integer and pressing "Enter", the program prints the integer. It doesn't wait for me to enter the string. Whats wrong? Whats the correct way to program this?
What you need to know
The problem with %[^\n] is that it fails when the first character to be read is the newline character, and pushes it back into the stdin.
The Problem
After you enter a number for the first scanf, you press Enter. %d in the first scanf consumes the number, leaving the newline character ('\n'), generated by the Enter keypress, in the standard input stream (stdin). %[^\n] in the next scanf sees this \n and fails for the reason given in the first paragraph of this answer.
Fixes
Solutions include:
Changing scanf("%d", &i); to scanf("%d%*c", &i);. What %*c does is, it scans and discards a character.
I wouldn't recommend this way because an evil user could trick the scanf by inputting something like <number><a character>\n, ex: 2j\n and you'll face the same problem again.
Adding a space (any whitespace character will do) before %[^\n], i.e, changing scanf("%[^\n]", str); to scanf(" %[^\n]", str); as #Bathsheba mentioned in a comment.
What the whitespace character does is, it scans and discards any number of whitespace characters, including none, until the first non-whitespace character.
This means that any leading whitespace characters will be skipped when inputting for the second scanf.
This is my recommendation: Clear the stdin after every scanf. Create a function:
void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
and call it after every scanf using flushstdin();.
Other issues:
Issues unrelated to your problem include:
You don't deal with the case if scanf fails. This can be due to a variety of reasons, say, malformed input, like inputting an alphabet for %d.
To do this, check the return value of scanf. It returns the number of items successfully scanned and assigned or -1 if EOF was encountered.
You don't check for buffer overflows. You need to prevent scanning in more than 1023 characters (+1 for the NUL-terminator) into str.
This can be acheived by using a length specifier in scanf.
The standards require main to be declared using either int main(void) or int main(int argc, char* argv[]), not int main().
You forgot to include stdio.h (for printf and scanf)
Fixed, Complete Program
#include <stdio.h>
void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
int main(void)
{
int i;
char str[1024];
int retVal;
while((retVal = scanf("%d", &i)) != 1)
{
if(retVal == 0)
{
fputs("Invalid input; Try again", stderr);
flushstdin();
}
else
{
fputs("EOF detected; Bailing out!", stderr);
return -1;
}
}
flushstdin();
while((retVal = scanf("%1023[^\n]", str)) != 1)
{
if(retVal == 0)
{
fputs("Empty input; Try again", stderr);
flushstdin();
}
else
{
fputs("EOF detected; Bailing out!", stderr);
return -1;
}
}
flushstdin();
printf("%d\n", i);
printf("%s\n", str);
return 0;
}
This simply, will work:
scanf("%d %[^\n]s", &i, str);
Instaed of scanf() use fgets() followed by sscanf().
Check return values of almost all functions with a prototype in <stdio.h>.
#include <stdio.h>
int main(void) {
int i;
char test[1024]; // I try to avoid identifiers starting with "str"
char tmp[10000]; // input buffer
// first line
if (fgets(tmp, sizeof tmp, stdin)) {
if (sscanf(tmp, "%d", &i) != 1) {
/* conversion error */;
}
} else {
/* input error */;
}
// second line: read directly into test
if (fgets(test, sizeof test, stdin)) {
size_t len = strlen(test);
if (test[len - 1] == '\n') test[--len] = 0; // remove trailing ENTER
// use i and test
printf("i is %d\n", i);
printf("test is \"%s\" (len: %d)\n", test, (int)len);
} else {
/* input error */;
}
return 0;
}

Calling scanf() after another string input function creates phantom input

Here's a small program:
#include <stdio.h>
int main() {
char str[21], choice[21]; int size;
while(1){
printf("$ ");
fgets(str, 20, stdin);
printf("Entered string: %s", str);
if(str[0] == 'q') {
printf("You sure? (y/n) ");
scanf("%s", choice);
if(choice[0] == 'y' || choice[0] == 'Y')
break;
}
}
return 0;
}
It reads a string using fgets(). If the string starts with a q, it confirms if the user wants to quit, and exits if the user types y.
When I run it and type q, this happens:
$ q
Entered string: q
You sure? (y/n) n
$ Entered string:
$
Note the $ Entered string:. Clearly, fgets() got an empty character or something as input, even though I didn't type anything.
What's going on?
As described in other answer scanf call leaves the newline in the input buffer you can also use getchar() after scanf like this :
scanf("%20s", choice);// always remember( & good) to include field width
// in scanf while reading
Strings otherwise it will overwrite buffer in case of large strings `
getchar(); //this will eat up the newline
Besides , you should also use fgets like this :
fgets(str,sizeof str, stdin); //Its better
It because the scanf call reads a character, but leaves the newline in the buffer. So when you next time call fgets is finds that one newline character and reads it resulting in an empty line being read.
The solution is deceptively simple: Put a space after the format in the scanf call:
scanf("%s ", choice);
/* ^ */
/* | */
/* Note space */
This will cause scanf to read and discard all training whitespace, including newlines.
Use a 'char' of a specific size char choice [1]
OR
char c[1];
c = getchar();
if(c[0] == 'y' || c[1] == 'y'){
// DO SOMETHING
}

Resources