why %*c not working in the expression "%[^\n]s%*c" - c

Here is the code :
#include <stdio.h>
#include <string.h>
struct driverDetail
{
char name[20];
int licenseNumber;
char route[20];
int kms;
};
int main()
{
struct driverDetail drivers[1];
for (int i = 0; i < 1; i++)
{
printf("\nEnter details for driver %d :\n", i+1);
printf("Enter driver's name : ");
scanf("%[^\n]s%*c", &drivers[i].name);
printf("Enter driver's license number : ");
scanf("%[^\n]d%*c", &drivers[i].licenseNumber);
printf("Enter driver's route : ");
scanf("%[^\n]s%*c", &drivers[i].route);
printf("Enter driver's kilometers driven : ");
scanf("%[^\n]d%*c", &drivers[i].kms);
}
for (int i = 0; i < 1; i++)
{
printf("driver %d name : %s\n", i+1, drivers[i].name);
printf("driver %d license number : %d\n", i+1, drivers[i].licenseNumber);
printf("driver %d route : %s\n", i+1, drivers[i].route);
printf("driver %d kilometers driven : %d\n", i+1, drivers[i].kms);
}
return 0;
}
%[^\n]%*c works completely fine but why %[^\n]s%*c is not working.
when I use %[^\n]%*c \n gets rejected by the first format specifier and then %*c read the \n and discards it. But why *%c is not discarding \n when used with %[^\n]s%*c.
Same case with %d, *%c works with %d%*c but not with %[^\n]d%*c.
Why is this happening ? can somebody explain.

When scanf reads input according to one of the formats %[^\n]s%*c and %[^\n]d%*c, and the behavior is well defined (i.e. the object receiving the data corresponding to the %[ directive is not overrun), there must be either an input failure or a matching failure at the s or d. This is because scanf will expect each of these to match a literal character (a literal 's' or 'd'), but if there are any more characters available then the next one must be a newline. Anything else will have been consumed by the %[.
Perhaps you meant %[^\n]%d, %[^\n]%*s, or similar. The %s and %d directives skip leading whitespace, including newlines (unlike %c or %*c), so they would attempt to read past the newline (if any) up next in the input.
Note also that all of these alternatives afford the possibility of an input failure, as I already mentioned. That is, if the %[ consumes all the bytes up to the end of the stream, such that there are none left to read, then scanf quits. Its return value will reflect that. Take care, however, not to confuse "end of stream" with the temporary absence of characters to read. These are not at all the same thing.

Related

Issues with scanf() and accepting user input

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.

Function execution not waiting in do-while loop [duplicate]

I tried this code below, but it seems scanf("%c") is skipped. It only asks me to enter name and age and skips the lines below that. It just print the text in the printf above the if statements. Can anyone help?
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
scanf("%s", &name);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf("%c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf("%c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
}
Change
scanf("%c", &sex);
to
scanf(" %c", &sex);
^
space
and
scanf("%c", &status);
to
scanf(" %c", &status);
^
space
The problem is because of trailing newline characters after your second call to scanf(). Since it is of %d type specifier, when you press Enter A newline character ( '\n' ) is left in the stream and the next scanf() tries to read that newline character, and thus, it seems as though it just skipped input, but in fact, it read the newline character.
So, the newline character is stored in the variable sex, and thus, it skips asking you for input for that variable.
Unless you are interested in whitespace like newlines, do not use %c. Simply use the string conversion %s and use the first character of the input.
Rationale: All scanf conversion specifiers except %c ignore white space including newlines. They are designed to read sequences of input tokens (numbers, words) where the amount and nature of white space is irrelevant. The words can all be on the same line, or each word on a different line; scanf wouldn't care unless you force single character reads with %c which is almost never necessary.
Change your code to
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
// scanf("%s", &name);
fgets(name,20,stdin);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf(" %c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf(" %c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
return 0;
}
Here, I have added an extra space before the format specifier %c, to accommodate any previous input like newline (\n). Another alternative method is to use getchar() immediately before you take any character input.
Also, if you perform string input with scanf, it will not read the input after encountering a whitespace. So, instead use fgets for taking any string input which might contain spaces.
Another thing I changed in your code (trivial) is int main() and return 0.
This happens because blankspace is also treated as a character and and happens when you press enter.
So Leave a space.
scanf(" %c",&something);
You can do the following for all scanfs.
scanf("%c\n",&smth);
And then enter the values one by one separating them by newlines (press Enter).
This helped me too when I had the same problem.
scanf("%c*",&smth);
That makes scanf skip any other characters that a user might input, including newlines.
Note: use appropriate format strings for each type (%s for strings, %d for integers, etc).

printing whole line with file io

This is a part of my 'Phonebook' program.
void viewall(){
int n, checking = 0;
char name[50];
fp = fopen("Phonebook.txt","r");
printf ("\n\n");
fscanf (fp, "%s %d", name, &n);
while (!feof(fp)){
printf (" %s +880%d\n", name, n);
fscanf (fp, "%s %d", name, &n);
++checking;
}
if (checking == 0){
printf (" Contact List is Empty. No Contacts to Show...");
}
printf ("\n\n");
fclose(fp);
menu();
}
This part displays all the contacts in list. But if any contact name has two parts they get separated. For example: I enter Anik Shahriar as name and then enter my number. I looked at my file and this data was there how it should be.
Anik Shahriar 01*******93
But when I wanted to display all the contacts. It got printed like this:
Anik 0
Shahriar 01*******93
How can i make the program print the whole line ?
This behaviour is caused by the lines
fscanf (fp, "%s %d", name, &n);
The format identifier %s scans for a single string. Any whitespace character ends the scan.
http://www.cplusplus.com/reference/cstdio/scanf/
%s
String of characters
Any number of non-whitespace characters,
stopping at the first whitespace character found. A terminating null
character is automatically added at the end of the stored sequence.
I suggest to use ca CSV file and use a format string like.
scanf("%[^,] %d", name, number)
Dont forget to test the scanf result value.

Verifying Input in C

I'm trying to write a simple binary calculator to get reaquainted with C. for some reason the first input verification works fine, and even though the second verification for the numbers is written in almost the same way, if the user enters faulty input, the while loop just loops infinitely without ever waiting for new user input. Here is the code, and thanks for the help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char operator[20];
char valid_operator[4] = "+-*/";
printf("Enter operator: ");
scanf("%s", operator);
printf("You entered: %s\n", operator);
while(strchr(valid_operator, (int)operator[0]) == NULL) {
printf("%s is not a valid operator. Enter +, -, /, or *: ", operator);
scanf("%s", operator);
}
The code works up until here. This next part is thrown into an infinite loop if the user enters faulty input the first time. The re-prompting never happens.
int input1;
int input2;
printf("Enter the two inputs (separated by whitespace): ");
int num_ints = 1;
num_ints = scanf("%d %d", &input1, &input2);
printf("Input 1: %d. Input 2: %d.\n", input1, input2);
while(num_ints < 2){
printf("Invalid input. Enter two integers separated by whitespace: ");
num_ints = 0;
num_ints = scanf("%d %d", &input1, &input2);
printf("Input 1: %d. Input 2: %d.\n", input1, input2);
}
return 0;
The reason it loops infinitely without ever waiting for new user input is that when scanf fails to read a char in the requested format (%d in your case) it won't advance the file pointer and at the next iteration of the loop it will try to read the same incorrect char again.
This is consistent with POSIX: http://pubs.opengroup.org/onlinepubs/009695399/functions/fscanf.html
if the comparison shows that they are not equivalent, the directive shall fail, and the differing and subsequent bytes shall remain unread.
Also, return value from the man scanf:
...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.
So, you better combine fgets and sscanf.
do {
char buf[BUFSZ];
printf("Enter the two inputs (separated by whitespace): ");
if(fgets(buf, BUFSZ, stdin) == NULL)
{
/* Error exit. */
break;
}
num_ints = sscanf(buf, "%d %d", &input1, &input2);
} while(num_ints != 2);
You need to clear stdin. If you input a non-integer in your example "1 t", "t" is not consumed (left in the stream). Add this to your loop:
while(num_ints < 2){
while (fgetc(stdin) != '\n'); // clear input
. . .
See C program loops infinitely after scanf gets unexpected data for a good description of the issue.

scanf("%c") call seems to be skipped

I tried this code below, but it seems scanf("%c") is skipped. It only asks me to enter name and age and skips the lines below that. It just print the text in the printf above the if statements. Can anyone help?
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
scanf("%s", &name);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf("%c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf("%c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
}
Change
scanf("%c", &sex);
to
scanf(" %c", &sex);
^
space
and
scanf("%c", &status);
to
scanf(" %c", &status);
^
space
The problem is because of trailing newline characters after your second call to scanf(). Since it is of %d type specifier, when you press Enter A newline character ( '\n' ) is left in the stream and the next scanf() tries to read that newline character, and thus, it seems as though it just skipped input, but in fact, it read the newline character.
So, the newline character is stored in the variable sex, and thus, it skips asking you for input for that variable.
Unless you are interested in whitespace like newlines, do not use %c. Simply use the string conversion %s and use the first character of the input.
Rationale: All scanf conversion specifiers except %c ignore white space including newlines. They are designed to read sequences of input tokens (numbers, words) where the amount and nature of white space is irrelevant. The words can all be on the same line, or each word on a different line; scanf wouldn't care unless you force single character reads with %c which is almost never necessary.
Change your code to
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
// scanf("%s", &name);
fgets(name,20,stdin);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf(" %c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf(" %c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
return 0;
}
Here, I have added an extra space before the format specifier %c, to accommodate any previous input like newline (\n). Another alternative method is to use getchar() immediately before you take any character input.
Also, if you perform string input with scanf, it will not read the input after encountering a whitespace. So, instead use fgets for taking any string input which might contain spaces.
Another thing I changed in your code (trivial) is int main() and return 0.
This happens because blankspace is also treated as a character and and happens when you press enter.
So Leave a space.
scanf(" %c",&something);
You can do the following for all scanfs.
scanf("%c\n",&smth);
And then enter the values one by one separating them by newlines (press Enter).
This helped me too when I had the same problem.
scanf("%c*",&smth);
That makes scanf skip any other characters that a user might input, including newlines.
Note: use appropriate format strings for each type (%s for strings, %d for integers, etc).

Resources