Why is first gets() input is lost in this c program? - c

In the following simple code the input of the first gets is not showing up.
Any help please?
int main()
{
int x;
char tmp[1];
char anystr[10], srchstr[1];
printf("Enter an string : ");
gets(anystr);
printf("Enter any character you want to search in input string: ");
gets(srchstr);
printf("anystr : %s\n",anystr);
printf("anystr : %c\n",anystr[0]);
printf("srchstr : %c\n",srchstr[0]);
return 0;
}
The Output is null for first fgets string anystr:
Enter an string : hello
Enter any character you want to search in input string: h
anystr :
anystr :
srchstr : h

You have a problem because you have undefined behaviour.
The UB is caused by having second gets() write beyond the 1-char array srchstr. What is written beyond is the terminator '\0'.
See the gets() docu: http://en.cppreference.com/w/c/io/gets
No answer to this question should omit to mention (using Jonathan Lefflers nice link):
Why is the gets function so dangerous that it should not be used?
That is it. UB and dangerous. Done. End of answer.
Well....
One speculation of which specific nasal demon is flying around would be:
strchr is located right before anystr. This means that the one beyond access hits right the first char inside anystr.
I.e. it terminates that other string right after zero characters.
I.e. it makes it empty.
Printing it therefor has no output, even though the second character is still from the perviously written string.

Don't use gets() as pointed here in man 3 fges
Never use gets(). Because it is impossible to tell without knowing
the
data in advance how many characters gets() will read, and because
gets() will continue to store characters past the end of the buffer, it
is extremely dangerous to use. It has been used to break computer
security. Use fgets() instead.
Use fgets() like
fgets(anystr,sizeof(anystr),stdin);
Also char srchstr[1]; should be char srchstr; as you are asking in printf Enter any character you want to search in input string:
And to scan srchstr use scanf(" %c",&srchstr);
you may want something like
int main(void ) {
char anystr[10],srchstr;
printf("Enter an string : ");
fgets(anystr,sizeof(anystr),stdin);/*use fgets instead of gets */
printf("Enter any character you want to search in input string: ");
scanf(" %c",&srchstr);/* give the space before %c to avoid buffering problem */
printf("anystr : %s\n",anystr);
printf("anystr : %c\n",anystr[0]);
printf("srchstr : %c\n",srchstr);
return 0;
}

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.

How to check if a string is empty in C (nothing has worked so far)

I have to make a code that checks to see whether the Student 1's first name was blank and if it was then ask the user to input a name. However, when I use this code it doesn't display that message. When I press enter the cursor just goes to the next line until I actually type something in. I've tried this with strcmp too and nothing works.
#include <stdio.h>
#include <string.h>
{
char charStudent1FirstName[50] = "";
printf("Please enter Student 1's First name: ");
scanf("%s", &charStudent1FirstName);
if (charStudent1FirstName[0] == '\0')
{
printf("Please input Student 1's first name again: ");
scanf("%s", &charStudent1FirstName);
}
}
Here's what I changed:
Use fgets instead of scanf. This means you will actually see the blank line if that's all that's entered.
Trim the newline from the fgets result.
Use charStudent1FirstName instead of &charStudent1FirstName. You want to pass a char*, not a char**. If your compiler doesn't warn you about this, consider using a different compiler or changing your compilation settings.
Use a loop so the user is prompted to enter a name as many times as necessary until one is entered.
Complete working code:
#include <stdio.h>
#include <string.h>
int main() {
char charStudent1FirstName[50] = "";
while (charStudent1FirstName[0] == 0) {
printf("Please input Student 1's first name: ");
fgets(charStudent1FirstName, 50, stdin);
charStudent1FirstName[strcspn(charStudent1FirstName, "\n")] = 0;
}
printf("First name: %s\n", charStudent1FirstName);
}
There's nothing wrong with the way that you're checking for the empty string. Your issue is that you're using scanf, which is notoriously hard to use. scanf handles whitespace probably not in the way you expect: you want line-based input, but scanf reads a stream of tokens. scanf does not care about newlines, so in your case, it won't read anything until you type in non-whitespace and therefore will not retrieve an empty string.
Instead, you should read an entire line using fgets (or POSIX getline if available) and then parse that line (if necessary) with sscanf. (Note that fgets can leave a newline at the end of the string, so you must strip that off.)
Perhaps beating a dead horse, your usage of scanf is also unsafe because you do not limit the amount of data that it can write to charStudent1FirstName, and consequently a user could easily overflow the destination buffer. While it's possible to jump through some hoops to use scanf safely when reading strings, using fgets/getline would avoid these problems. (Additionally, using fgets/getline would make it more obvious that you should be passing charStudent1FirstName as an argument, not &charStudent1FirstName.)

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.

Noticing strange behavior with strings in c

Still in learning mode and may be the following question is a really dumb but I dont have any idea why it is happening..
#include<stdio.h>
int main()
{
/* code to accept string and then a character from stdin */
char str[20], inp;
/*take string from stdin */
printf("string:\n");
scanf("%s",str);
fflush(stdin);
/*input a character */
printf("char:\n");
scanf("%c",&inp);/* code does not reach this point and exits */
}
As mentioned in the comment, after I input the string , for eg. 'strng' the code just exits after printing char: but it does not wait for me input the character. As per my understanding, I have given the size of the array large enough to store the string and if the string entered is smaller than the size of the str array, the compiler will automatically add null character at the end of the string and proceed further. Am I missing something or is there a mistake in my code. Please suggest.
Thanks.
Try removing fflush(stdin);
and put a space before %c in scanf(" %c",&inp);
First of all fflush(stdin) is wrong. Many people recommend it but it is plain and simple undefined.
The problem is caused by scanf leaving \n in the input buffer because "%s" doesn't read whitespace characters. When scanf("%c"..) is reached, it is immediately "satisfied" and fills inp with \n and calls it a day.
The problem is common enough, see these C FAQs:
Scanf interlace
Scanf problems
One (possibly dangerous) solution is to discard \n input:
while((c = getchar()) != '\n' && c != EOF)
;
Another solution might be to use fgets and parse that, or possibly read one character at a time with getc, or maybe tweak the second scamf to discard whitespace characters.
Put a space before the %c in the second scanf like this:
scanf(" %c",&inp)
And as stated by others fflush is defined only for output streams.

String reading issue using scanf

Now i read somehwere:
The scanf() conversion %[\n] will
match a newline character, while
%[^\n] will match all characters up to
a newline.
But in the following code:
#include<stdio.h>
int main() {
printf("Enter Something: ");
char name[100];
scanf("%99[help]", name);
printf("%s",name);
}
I face no problem when i enter help me as the printed word is help. However when i enter I need help it prints garbage. Please help how to fix this problem?
My target is to match the word help entered anywhere along the input, e.g.,
"This is a test, i need help in this"
Should detect help.
You need to check the result of scanf. If it fails to match, the pointer you pass in is not modified. In your specific case, name would then contain arbitrary data.
Once you check the output of scanf, you'll see it's failing to match on that string. scanf is not a regular expression parser. It will only attempt a match on the first "item" it sees on the input stream.
The match specifier %99[help] means "i want to match anything that contains the letters h, e, l, p in any order, up to 99 chars long". That's all. So it fails on the very first letter of your input ("T"), which is not in the set.
If you want to look for a string inside another string, use strstr for example. To read a whole line, if your environment has it, the easiest is to use getline.
You need the scanset to recognize all the characters you might enter. You also need to check the return from scanf() to see whether it succeeded.
#include <stdio.h>
int main()
{
printf("Enter Something: ");
char name[100];
if (scanf("%99[Indhelp ]", name) != 1)
fprintf(stderr, "scanf() failed\n");
else
printf("%s",name);
return 0;
}
That will recognize "I need help" and many other phrases. The C standard says:
If a - character is in the scanlist and is not the first, nor the
second where the first character is a ^, nor the last character, the behavior is
implementation-defined.
In many implementations, you can use a notation such as %[a-zA-Z ] to pick up a string of letters or spaces. However, that is implementation-defined behaviour. That means it could do anything the implementation chooses, but the implementation must document what it does mean.
The reliable way to write the scanset is:
%[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ]
Of course, that leaves you with some issues around punctuation, not to mention accented characters; you can add both to the scanset if you wish.

Resources