c - scanf not storing input properly - c

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.

Related

Why does printf prints only first character of a character array whose input was read through scanf

This code is supposed to read input string through scanf and store the input string in an array declared here as msg[] and then print those input string, but when I run the code all it prints is just the first character of the string. It looks really simple but I am not able to solve it.
If I type i do, it only reports i.
#include <stdio.h>
int main()
{
char msg[5];
printf("enter the message: ");
scanf("%s",msg);
printf("entered msg is: %s", msg);
}
The answer is hidden in the comments. The OP states if i give input "i do" it prints only 'i' .
scanf only reads until the first whitespace (which is the i in i do).
If you input 4 characters, 4 characters are printed.
Please edit your question to include this information for future searchers.
The %s conversion specifier tells scanf to skip over any leading whitespace, then read up to (but not including) the next whitespace character. So when you enter "i do", the %s conversion specifier only reads "i".
If you want to read strings with whitespace, you'll have to use a different method. You can use the %[ conversion specifier like so:
scanf( "%[^\n]", msg );
which will read everything (including leading whitespace characters) until it sees the '\n' newline character and stores it to msg. Unfortunately, this (and the %s specifier above) leave you open to buffer overflow - if your user enters a string longer than msg is sized to hold, scanf will happily write those extra characters to the memory following the msg buffer, leading to all kinds of mayhem. To prevent that, you'd use a field width in the conversion spec, like so:
scanf( "%4[^\n]", msg );
This tells scanf to read no more than 4 characters into msg. Unfortunately, that width has to be hardcoded - you can't pass it as an argument the way you can with printf.
IMO, a better way to go would be to use fgets:
fgets( msg, sizeof msg, stdin );

How to limit scanf function in C to print error when input is too long?

I want to limit the scanf function so when I enter for example a char* array <String...> that has more then 30 characters, it will not get it and my output will be error.
I got a hint to use [^n] or something like that but I don't understand how to do it?
I know that I can use scanf("%30s"..) but I don't want the input to be valid and just the error.
Any help would be great.
If you must use scanf then I believe that the best that you can do is use the width specifier with something like: "%31s", as you've already mentioned, then use strlen to check the length of the input, and discard the string and report an error if the input is longer than your limit.
Or possibly skip the strlen by additionally using an %n in your format string, e.g. "%31s%n".
A format string using something like %[^\n] in place of %s simply instructs the function to continue reading until a newline, consuming other whitespace characters along the way. This is useful if you want to allow the input to include whitespace characters.
Review the docs for scanf (here's a copy of the man page).
You could use fgets and sscanf. With fgets you can read a little bit more than 30 characters and then check that you didn't get more than 30 characters.
Or if you really want to use scanf use it with something more than 30 like %32s.
Take a look at this page http://linux.die.net/man/3/sscanf and look for the %n format specifier. I would also recommend looking the sscanf function's return value, which will tell you the number of formatted arguments, as well as the presence of error.
I've used the %n format specifier to help in parsing a string of parameters:
ret = sscanf(line, "%d %d %s %d %d %n", &iLoad, &iScreen, &filename, &stage, &bitmapType, &offset);
The number of chars formatted by the preceding arguments is stored in the variable offset.
You could use getchar in a loop, and count the characters coming in.
int iCharCount = 0;
ch = getchar();
while( ch != EOF ) {
iCharCount++;
if(30 < iCharCount)
{
printf("You have attempted to enter more than 30 characters.\n");
printf("Aborting.");
break;
}
printf( "%c", ch );
ch = getchar();
}
This is a crude example. If it were up to me, I'd allocate a maximum-sized character array, read the whole line in, and then use string utilities to count it, edit it, and so on.
Well in C you can do:
#include <string.h>
...
if(strlen(array_ptr) > 0) error();
Obviously you need a bigger buffer to actually first get the input to it, and then check it's length, so the array could be of e.g. 512 bytes. When you copy strings to it, you need to check that you are getting 0 at the end.
sscanf ,is very good for this kind of thing, but a careful scanf can do the trick here too. You'll want to make sure that you're correctly limiting the number of characters the user can enter, so %31s would mean that 30 chars max + the \0 null terminator (31).
What you're preventing is buffer overflow attacks, which can be extremely effective ways to break sloppily written c programs. Here's an excellent article by Aleph One on BO:
http://insecure.org/stf/smashstack.html

scanf problem in input

hi I am having problems using scanf when reading two strings with spaces consecutively
char name[50] = {0};
char address[100] = {0};
char name1[50] = {0};
char address1[100] = {0};
int size = 0;
//input = fopen("/dev/tty","r+");
//output = fopen("/dev/tty","w");
printf("\nenter the name:");
scanf("%[^\n]s",name);
//fgets(name,sizeof(name),input); // this works fine
printf("\nenter the address:");
scanf("%[^\n]s",address);
//fgets(address,sizeof(address),input); // this works fine
the input for address is not taken at all.. maybe it takes the return key as an input?
The newline ('\n') character is still on the input stream after the first scanf call, so the second scanf call sees it immediately, and immediately stops reading.
I notice that you mention fgets in comments - why not use that ? It does what you want to do quite well.
You have a couple of problems.
As #sander pointed out, you're not doing anything to clear the newline out of the input buffer.
You've also used %[^\n]s -- but the s isn't needed for (nor it is part of) a scanset conversion. Since it's not part of the conversion, scanf attempts to match that character in the input -- but since you've just read up to a new-line (and not read the newline itself) it's more or less demanding that 's' == '\n' -- which obviously can't be, so the scan fails.
To make this work, you could use something like this:
scanf("%49[^\n]%*c", name);
scanf("%99[^\n]%*c", address);
As to why you'd want to use this instead of fgets, one obvious reason is that it does not include the trailing (and rarely desired) newline character when things work correctly. fgets retaining the newline does give you one result that can be useful though: the newline is present if and only if the entire content of the line has been read. If you're really concerned about that (e.g., you want to resize your buffer and continue reading if the name exceeds the specified size) you can get the same with scanf as well -- instead of using %*c for the second conversion, use %c, and pass the address of a char. You read the entire line if and only if you've read a newline into that char afterwards.

how does fgets internally works?

Well it is a basic question but I seem confused enough.
#include<stdio.h>
int main()
{
char a[100];
printf("Enter a string\n");
scanf("%s",a);
}
Basically the above is what I want to achieve.
If I enter a string
James Bond
then I want that to be stored in array a.
But the problem is because of presence of a blank space in between only James word is stored.
So how can I solve this one.
UPDATE
After the replies given below I understand fgets() would be a better choice. I want to know internal working of fgets as why is it able to store the string with space where as scanf is not able to do the same.
Is this what you need?
freeBSD: http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdio/fgets.c?rev=1.14.14.1;content-type=text%2Fplain
open implementation: https://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=7425&lngWId=3
OWP(dead) http://www.koders.com/c/fid042417FA231704B84308A66E1B82EADEDAB22051.aspx
ReactOS http://www.koders.com/c/fidEB3507945463053CEFCD518EA0CDFF9EB78E24C9.aspx?s=fgets.c#L1
All implementations scans the input file(or stream) until it reaches \n or EOF, or the maxSize param is hit...
scanf reads up until the first whitespace character. The solution is to use fgets, if memory serves me correctly, in your instance it'd be:
fgets(a, 100, STDIN);
It will read up to 100 characters (or the first \n) from standard input and store it in a.
Do not use the gets function ever, even if it looks easier.
Usually scanf breaks the input at whitespace (space, tab, newline, ...).
For example, the input " 5 42 -100" is accepted with scanf("%d%d%d") because each %d strips the leading whitespace. The same behaviour happens with %s.
The only conversion specifiers where the ignoring of leading whitespace doesn't happen are %%, %[ and %c (and, for different reasons, %n)
char input[] = " hello world";
char buf[100];
sscanf(input, "%8c", buf); /* buf contains " hello w" */
sscanf(input, "%8[^o]", buf); /* buf contains " hell" */
The fgets function reads as many characters as there are, up to the nest line break.
I use The Open Group Base Specifications Issue 7 for online documentation
You should use gets(a)/fgets(a, sizeof(a), stdin) instead of sscanf().
Try fgets():
char a[100];
printf("Enter a string\n");
fgets(a, sizeof(a), STDIN);
To learn more about STDIN, check this.

How do I return a printf statement if the user inputs nothing?

I want to execute a statement based on the input of the user:
#include <stdio.h>
#include <string.h>
void main() {
char string_input[40];
int i;
printf("Enter data ==> ");
scanf("%s", string_input);
if (string_input[0] == '\n') {
printf("ERROR - no data\n");
}
else if (strlen(string_input) > 40) {
printf("Hex equivalent is ");
}
else {
printf("Hex equivalent is ");
}
}
When I run it, and just press enter, it goes to a new line instead of saying "ERROR - no data".
What do I do?
CANNOT USE FGETS as we have not gone over this in class.
Use
char enter[1];
int chk = scanf("%39[^\n]%c", string_input, enter);
but string_input will not have a '\n' inside. Your test
if (string_input[0] == '\n') {
printf("ERROR - no data\n");
}
will have to be changed to, for example
if (chk != 2) {
printf("ERROR - bad data\n");
}
use fgets instead of scanf. scanf doesn't check if user enters a string longer than 40 chars in your example above so for your particular case fgets should be simpler(safer).
Can you use a while loop and getch, then test for the <Enter> key on each keystroke?
scanf won't return until it sees something other than whitespace. It also doesn't distinguish between newlines and other whitespace. In practice, using scanf is almost always a mistake; I suggest that you call fgets instead and then (if you need to) use sscanf on the resulting data.
If you do that, you really ought to deal with the possibility that the user enters a line longer than the buffer you pass to fgets; you can tell when this has happened because your entire buffer gets filled and the last character isn't a newline. In that situation, you should reallocate a larger buffer and fgets again onto the end of it, and repeat until either you see a newline or the buffer gets unreasonably large.
You should really be similarly careful when calling scanf or sscanf -- what if the user enters a string 100 characters long? (You can tell scanf or sscanf to accept only a limited length of string.)
On the other hand, if this is just a toy program you can just make your buffer reasonably long and hope the user doesn't do anything nasty.
fgets does what you need. Avoid using scanf or gets. If you can't use fgets try using getchar
The problem is that "%s" attempts to skip white-space, and then read a string -- and according to scanf, a new-line is "whitespace".
The obvious alternative would be to use "%c" instead of "%s". The difference between the two is that "%c" does not attempt to skip leading whitespace.
A somewhat less obvious (or less known, anyway) alternative would be to use "%[^\n]%*[\n]". This reads data until it encounters a new-line, then reads the new-line and doesn't assign it to anything.
Regardless of which conversion you use, you want (need, really) to limit the amount of input entered so it doesn't overflow the buffer you've provided, so you'd want to use "%39c" or "%39[^\n]". Note that when you're specifying the length for scanf, you need to subtract one to leave space for the NUL terminator (in contrast to fgets, for which you specify the full buffer size).
What platform are you running on?
Is the character sent when your press the ENTER key actually '\n', or might it be '\r'? Or even both one after the other (ie. "\r\n").

Resources