SCANF probably not reading the correct value - c

If you enter more than five characters in the "name" field the function giving the wrong output, otherwise if the input is less than or equal to five characters the function works just fine, or if I use just %s instead of reading five characters using %5s then also the function works.
Is there any fix available (I want to use %5s)?
#include<stdio.h>
int main(void)
{
char name[6];
int age;
printf("Enter your name: ");
scanf("%5s",name);
printf("Enter your age: ");
scanf("%d",&age);
printf("Your name: %.4s\n",name);
printf("Your age: %d\n",age);
return 0;
}

It's good that you limit the input to five characters, as that will make it fit perfectly in the array you have (including the terminator). However, if the user inputs a longer string, the remaining will be left in the buffer and the input of the age will not work.
As a (relatively) simple way to improve input, use fgets instead to read a line but increase array size as it can include the newline itself. And that's kind of the point here: If the buffer contains the newline, then you know you have read the full string, can replace it with the string terminator, and then move on. However, if the buffer doesn't contain a newline, you need to "flush" the input buffer by reading all the remaining characters of the line and ignore them.

Related

c - scanf not storing input properly

My code looks like this:
int nameFull;
printf("What is your name?\n");
scanf("%d\n", &nameFull); \\up until here it seems to work
printf("Hello %d", nameFull);
return 0;
But my output every time I run the program is "Hello 0" no matter what I input.
Does anyone know how to fix this?
First of all scanf() doesn't emit a prompt so its not a good idea to use any trailing whitespace character in the format string like \n here , It will cause it to read and discard character until next non-whitespace character.
To read a name you can do it like :
char name[50];
scanf("%49s",name); // 49 to limit the buffer input to prevent buffer overrun , this is a security issue.
You should also check the return value of scanf to see if the operation was successful. Personally , I don't prefer using scanf() at all because of various potential problems. It takes as input only what the program author expects it to, not considering other inputs which user might accidentally input. Check out here and here. Also check the scanf() man page
A better and safer method would be use fgets(),
fgets(name,sizeof(name),stdin);
You want to read a string, but you are an integer to store the input. That's not the right approach.
A better aproach would be to use an array of characters, to store the string in it.
char nameFull[100]; // can store up to 100 characters, 99 + 1 for the null-terminator ideally
Now, you could use scanf, like this:
scanf(" %99[^\n]", nameFull);
Note that I used 99, as a guard for not overflowing your array nameFull, if the user inputs too many characters for the size of your array. I didn't use %s, which would stop at a whitespace, and you seem to want to input a full name, which is usually two words and a space in between.
An alternative would be to use fgets(), which provides more safety, like this:
fgets(nameFull, sizeof(nameFull), stdin)
It will read the whole line though and store the trailing newline, while scanf() will read a single string.
Moreover, use the string identifier to print, not the integer one (%s is for string, %d is for integers). Like this:
printf("Hello %d", nameFull);
to this:
printf("Hello %s", nameFull);
as discussed about the string format.
%s reads a string of characters.
%d reads a integer.
So, your correct code will be like following code :
#include <stdio.h>
int main(){
char nameFull[100];
printf("What is your name?\n");
scanf("%99s", nameFull); //to avoid potential buffer overflow
printf("Hello %s\n", nameFull);
return 0;
}
N.B: Check this comment for nice explanation.
Well, int stores a number, a name is not a number. A name is a set of characters (aka strings). So this program would work (no error checking and such since you are in an introductory course):
char name[1024]; // 1024 is more than enough space for a name
scanf("%s", name); // %s reads a string of characters
printf("Hello %s\n", name);
return 0;
You are trying to assign an array of character (commonly referred as string) to an integer variable.
That's not correct.
Just change your variable as such
char nameFull[1024] = {0};
And then use scanf(3) with the appropriate format specifiers for strings, which is %s
scanf("%s", nameFull);
Normally you would check for the return of scanf to know if errors occurs, and in such cases, handle them.
Anyway, I would advice you to use fgets(3) which prevents buffer overflow
char *fgets(char *s, int size, FILE *stream);
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (aq\0aq) is stored after the last character in the buffer.

Program To Check If A Number Is Present In An Array

I wrote the below C code to check if a number is present in an array whose elements are input by the user. But weirdly it's skipping the the third printf statement, directly taking the input and printing Enter the number you wish to look for after taking that input. What is causing this? Included input and output box below code.
CODE:
#include <stdio.h>
#include <stdlib.h>
void main() {
int arr[30], size, i, num, flag=0;
printf("Enter size of array. \n");
scanf("%d",&size);
printf("Enter %d array elements one by one. \n",size);
for (i=0; i<size; i++) {
scanf("%d \n",&arr[i]);
}
printf("Enter the number you wish to look for. \n");
scanf("%d",&num);
for(i=0;i<size;i++) {
if (num == arr[i]) {
flag++;
}
}
if (flag>0) {
printf("The number %d is present in the array.",num);
} else {
printf("The number %d is not present in the array.",num);
}
}
INPUT/OUTPUT:
Enter size of array.
5
Enter 5 array elements one by one.
1
2
3
4
5
5
Enter the number you wish to look for.
The number 5 is present in the array.
You can see that Enter the number you wish to look for. should come before 5, but it is not so.
Solved
Simply fixed by removing \n from scanf.
In scanf, a space character already represents any whitespace. So in your "%d \n" the function already processes the new line right after the last digit, but then you force it to wait for another newline.
This causes the program to wait for yet another line. After it's input, the program continues and asks for the number to search, and at that point the input was already entered.
Just use only one space in scanf, it will already work for the newline, ideally before the digit itself so that you don't need one extra line to complete the operation:
scanf(" %d", arr + i);
The space in the input format string "%d \n" tells the input system to
consume... all available consecutive whitespace characters from the input
(described here)
So when you enter your last number 5, the system now tries to consume all whitespace characters. To do that, it waits for additional input, until it's not a whitespace. So, paradoxically or not, to consume spaces, the system has to read a non-space, which is the second 5 you input.
To fix this behavior, you can tell your system to input only a number, without consuming whitespace:
scanf("%d",&arr[i]);
However, this will leave the whitespace in the buffer, which may interfere with later input. To discard the whitespace, you can use various techniques, described e.g. here.
In my opinion, the most correct technique (however, maybe the most cryptic one) is
scanf("%d%*[^\n]%*c",&arr[i]);
%d - read the number
%*[^\n] - read a string, terminated by a newline byte; discard it and don't store it anywhere
%*c - read a byte (which is a newline byte); discard it and don't store it anywhere
BTW in your format string "%d \n", there are two whitespaces: a regular space and an end-of-line. They both tell scanf to consume all whitespaces in input. The effect is exactly the same as with one space "%d " or with one end-of-line "%d\n", so this particular format string may be highly confusing to whoever reads your code (including yourself).

Unexpected results when trying to prevent stack overflow

I'm trying to secure the fields below by specifying the width of the variables so that buffer overflow will not occur. I would prefer not to use fgets() as I am trying to write something within the specifications I have been given (using scanf).
The code is below:
char firstName[11], surName[21], job[16];
printf("Enter first name: ");
scanf("%10s", firstName);
printf("Enter surname: ");
scanf("%20s", surName);
printf("Enter job: ");
scanf("%15s", job);
So for input like so:
Enter first Name: UmbertoOverflow
/*surName gets skipped over*/
Enter job: janitor
I get:
First name: UmbertoOve
Surname: rflow
Job: janitor
It doesn't give me a chance to enter surname, it just fills with the remainder of the first name. This seems to be buffer overflow to me, so is there a way of using scanf without getting this result?
%10s for first name reads only first 10 characters - UmbertoOve - from input string and puts into firstname. The remaining - rflow - are still in the input buffer of program and scanf() for surname takes those characters. '\n' - or Return - key pressed while entering first name works as terminator and adds rflow in surname.
Its not buffer overflow, but expected behavior.
It's not bufferoverflow. It's just that scanf takes space or newline as the delimiter. Hence, the first scanf scans for 10 chars and the next continues to scan till it finds a space or '\n'.
Use
scanf("%10s%*s", firstName);
scanf("%20s%*s", surName);
scanf("%15s%*s", job);

string input with spaces [duplicate]

This question already has answers here:
How do you allow spaces to be entered using scanf?
(11 answers)
Closed 6 years ago.
I'm trying to run the following code in the basic ubuntu gcc compiler for a basic C class.
#include<stdio.h>
struct emp
{
int emp_num, basic;
char name[20], department[20];
};
struct emp read()
{
struct emp dat;
printf("\n Enter Name : \n");
scanf("%s", dat.name);
printf("Enter Employee no.");
scanf("%d", &dat.emp_num);
//printf("Enter department:");
//fgets(dat->department,20,stdin);
printf("Enter basic :");
scanf("%d", &dat.basic);
return dat;
}
void print(struct emp dat)
{
printf("\n Name : %s", dat.name);
printf("\nEmployee no. : %d", dat.emp_num);
//printf("Department: %s", dat.department);
printf("\nBasic : %d\n", dat.basic);
}
int main()
{
struct emp list[10];
for (int i = 0; i < 3; i++)
{
printf("Enter Employee data\n %d :\n", i + 1);
list[i] = read();
}
printf("\n The data entered is as:\n");
for (int i = 0; i < 3; i++)
{
print(list[i]);
}
return 0;
}
I want the name to accept spaces.
The problem comes when I'm entering the values to the structures. I am able to enter the name the first time but the subsequent iterations don't even prompt me for an input.
I've tried using fgets, scanf("%[^\n]",dat.name) and even gets() (I was desperate) but am the facing the same problem every time.
The output for the 1st struct is fine but for the rest is either garbage, the person's last name or just blank.
Any ideas?
When reading a string using scanf("%s"), you're reading up to the first white space character. This way, your strings cannot include spaces. You can use fgetsinstead, which reads up to the first newline character.
Also, for flushing the input buffer, you may want to use e.g. scanf("%d\n") instead of just scanf("%d"). Otherwise, a subsequent fgets will take the newline character and not ask you for input.
I suggest that you experiment with a tiny program that reads first one integer number and then a string. You'll see what I mean and it will be much easier to debug. If you have trouble with that, I suggest that you post a new question.
The problem is that scanf("%[^\n",.. and fgets don't skip over any whitespace that may be left over from the previous line read. In particular, they won't skip the newline at the end of the last line, so if that newline is still in the input buffer (which it will be when the last line was read with scanf("%d",..), the scanf will fail without reading anything (leaving random garbage in the name array), while the fgets will just read the newline.
The easiest fix is to add an explicit space in the scanf to skip whitespace:
printf("\n Enter Name : \n");
scanf(" %19[^\n]", dat.name);
This will also skip over any whitespace at the beginning of the line (and blank lines), so may be a problem if you want to have a name that begins with a space.
Note I also added a length limit of 19 to avoid overflowing the name array -- if the user enters a longer name, the rest of it will be left on the input and be read as the employeee number. You might want to skip over the rest of the line:
scanf("%*[^\n]");
This will read any non-newline characters left on the input and throw them away. You can combine this with the prior scanf, giving you code that looks like:
printf("\n Enter Name : ");
scanf(" %19[^\n]%*[^\n]", dat.name);
printf("Enter Employee no. : ");
scanf("%d%*[^\n]", &dat.emp_num);
printf("Enter department : ");
scanf(" %19[^\n]%*[^\n]", dat.department);
printf("Enter basic : ");
scanf("%d%*[^\n]", &dat.basic);
This will ignore any spurious extra stuff that someone enters on a line, but will still have problems with someone entering letters where numbers are expected, or end-of-file conditions. To deal with those, you need to be checking the return value of scanf.
What you have tried was:-
scanf("%[^\n]",dat.name)
In this you forgot to specify the specifier.
You can try to use this:-
scanf ("%[^\n]%*c", dat.name);
or fgets() if you want to read with spaces.
Note:- "%s" will read the input until whitespace is reached.

Whats wrong with my SIMPLE C program?

I am writing a super simple command line based program in C. It's just a small test and the code is very simple. So what it is meant to do is to ask the user for their name, maths grade, english grade, computing grade. Then it figures out their average grade and also tells them the name they entered. Yes I know this is an extremely simple program, but I'm still doing something wrong.
The problem is, one part of my code will run first telling the user to enter their name and then once they do this and press enter the rest of my code will run all at once and then stop working. It's weird I just don't understand what is wrong.
#include <stdio.h>
int main(int argc, const char * argv[])
{
char chr;
char firstname;
int mathsmark, englishmark, computingmark, averagemark;
printf("What is your name?\n");
scanf("%c", &firstname);
printf("\n");
printf("What is your maths mark?\n");
scanf("%d", &mathsmark);
printf("\n");
printf("What is your english mark?\n");
scanf("%d", &englishmark);
printf("\n");
printf("What is your computing mark?\n");
scanf("%d", &computingmark);
printf("\n");
printf("Your name is: %c", firstname);
printf("\n");
averagemark = (mathsmark + englishmark + computingmark) / 3;
printf("%d", averagemark);
printf("\n");
chr = '\0';
while (chr != '\n') {
chr = getchar ();
}
return 0;
}
One major problem is that you've declared firstname to be a single character long, and when you try to read the name from the console, you're using the %c conversion specifier, which reads the next single character from the input stream and stores it to firstname. The remainder of the name is left in the input stream to foul up the remaining scanf calls.
For example, if you type "Jacob" as a first name, then the first scanf call assigns J to firstname, leaving "acob\n" in the input stream.
The next scanf call attempts to convert "acob\n" to an integer value and save it to mathsmark, which fails ("acob\n" is not a valid integer string). Same thing happens for the next two scanf calls.
The last loop
while (chr != '\n')
{
chr = getchar();
}
finally consumes the rest of "acob\n", which contains the newline character (because you hit Enter after typing the name), causing the loop and program to exit.
How do you fix this?
First, you need to declare firstname as an array of char:
char firstname[SOME_SIZE] = {0};
where SOME_SIZE is large enough to handle all your cases. The you need to change scanf call to
scanf("%s", firstname);
This tells scanf to read characters from the input stream up to the next whitespace character and store the results to the firstname array. Note that you don't need to use the & operator here; under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array.
Note that scanf is not very safe, and it's not very robust. If you enter more characters than your buffer is sized to hold, scanf will happily store those extra characters to memory following the array, potentially clobbering something important. You can guard against this by using an explicit field width in the conversion specifier, like
scanf(*%29s", firstname);
but in general it's a pain.
scanf is also not very good at detecting bad input. If you enter "12er" as one of your marks, scanf will convert and assign the "12", leaving the "er" in the stream to foul up the next read.
scanf returns the number of successful assignments, so one way to guard against bad input is to check the return value, like so:
if (scanf("%d", &mathmarks) != 1)
{
printf("Bad input detected for math marks\n");
}
Unfortunately, scanf won't remove bad characters from the stream; you'll have to do that yourself using getchar or similar.
This is a common mistake amongst newer C/C++ developers. The scanf function detects you hitting the ENTER/RETURN key to signal the end of input, but it also catches the \n character as well at the end of the input string, so you essentially get two RETURNS being detected.
Please read up on an example of using fgets and sscanf here:
http://www.linuxforums.org/forum/programming-scripting/67560-problem-scanf.html
It will resolve this issue very quickly for you. In the meantime, I strongly urge you to check out this book:
http://www.amazon.com/Primer-Plus-5th-Stephen-Prata/dp/0672326965
It is the most commonly used C programming book in high school and colleges in North America, and has TONS of examples for you to work through, including this specific program you demonstrated above. The print version has more examples than the e-book, so I would just cough up the $30.00 for the printed version.
Good luck!
You might want to look at a few tutorials. Maybe one on Format specifiers and one on strings in C
scanf() reads data from stdin and stores them as specified by the format specifiers. In this case:
char firstname;
scanf("%c", &firstname);
Read 1 character from stdin and store it to firstname:
>> What is your first name?
Mike
Now firstname == 'M' because scanf() read 1 character as we requested.
What you wanted to do was read a string (a bunch of characters):
char firstname[5]; // an array of characters
scanf("%s", firstname); // store as a string
firstname[4] = '\0'; // Truncate the result with a NULL to insure no overflow
>> What is your first name?
Mike
Now firstname is [M][i][k][e][\0] because scanf() read 1 string, as we requested.
Note the same holds true for printf(), a printf with a %c will give you one character where as a printf() with a %s will give you all the characters until the NULL terminator.
You have (at least) two choices.
char firstname[number_big_enough_to_hold_long_name];
/*or */
char *firstname = malloc(sizeof(char) * number_big_enough_to_hold_long_name);
/* ... code ... */
free(firstname);
Further it would be best to limit width of read. scanf() does not know the size (available space) of firstname.
scanf("%number_big_enough_to_hold_long_names", ...
/* i.e. */
char firstname[32];
if(scanf("%31s", firstname) == EOF) {
perror("bad");
return 1;
}
Further you should check if there is anything left before trying next read. I.e. If someone enters "My Name" then only "My" will end up in firstname and "Name" will be left in input stream.
And getchar() returns an int not a char.
getchar
scanf
And search "ansi c char arrays tutorial" or similar.

Resources