'fgets' runs after 'printf' - c

I'm slowly learning C. I read this page about input and output dealing with strings here: http://www.cprogramming.com/tutorial/c/lesson9.html
In the last code example, fgets is used to get and assign the input to a variable to the char array name. I tried implementing something similar in my own program.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
/* This is my very first C program! */
bool test=true;
/* Function Prototypes */
int mult(int x, int y);
/* Structures */
struct Person {
int age;
char name[256];
};
/* Complicated Array ;P */
struct Person *FirstPeriod[22];
char FakeString[100];
void PracticeStrings()
{
int i;
fgets(FirstPeriod[0]->name, 256, stdin);
for (i=0;i<256;i++)
{
if (FirstPeriod[0]->name[i]=='\n')
FirstPeriod[0]->name[i]='\0';
}
printf("\n\nHello Student 0: %s",FirstPeriod[0]->name);
}
int main()
{
struct Person DadeLamkins;
DadeLamkins.age=16;
int numb;
int x;
int *numb_address=&numb;
numb_address=malloc(sizeof(*numb_address));
FirstPeriod[0]=&DadeLamkins;
if (true)
printf("-__- \n\n");
printf("Please enter a number: ");
scanf("%d", &numb);
switch (numb) {
case 0:
printf("Dude, 0 is lame...\n");
break;
case 7:
printf("Dude, 7 is my favorite number!\n");
break;
default:
printf("You entered %d\n", numb);
break;
}
for (x=0;x<numb+1;x++) {
printf("\n::# %d",mult(x,2));
}
printf("\n\n%d",numb_address);
free(numb_address);
numb_address=0;
PracticeStrings();
getchar();
return 0;
}
int mult (int x, int y)
{
return x*y;
}
The PracticeStrings function on line 26 is the issue currently. When I compile, it displays Hello Student 0: before accepting the input (from fgets). I'm using Code::Blocks to compile.
Any help would be appreciated!
Edit...
Hahaha, yes, I understand that my program is inefficient and very silly. As you can tell, it doesn't really accomplish much. It is mostly just something to shove what I'm currently learning and try to apply things without actually rewriting the code examples (what do I learn if I copy word for word?). Anyways, thanks for the help! I guess that does make sense! It is too bad that my tutorials didn't mention that, I'm sure it is something that just takes a little bit of a higher understanding. I'm sure that the tutorial writer didn't expect anyone to mix the functions in the way I did.
Thanks a ton guys! Hopefully I can get used to this. I've done lots of scripting and plenty in the .net languages, hopefully I can add C to this list :)

It is because when you read the number:
scanf("%d", &numb);
stdin still has \n left in the buffer. So when you call PracticeStrings() and subsequently:
fgets(FirstPeriod[0]->name, 256, stdin);
You read \n and end up with
FirstPeriod[0]->name[i] == '\0';
Further, as you are learning, learn to validate :)
I.e.:
if ((foo = malloc(blah)) == NULL) {
... err ...
And even more critical:
if (scanf(..) != number_of_items_i_want) {
... did not get a number, or what ever I wanted ...
etc.

I think your issue is due to the behavior of your console, and your scanf() call.
The default setting for your console is probably line buffering. That means that nothing you type on your terminal is sent to stdin until after you have hit the enter key.
However, your call to scanf() (in main()) is only grabbing the integer that you've typed - not the trailing carriage return. Your carriage return is still sitting, unread, in stdin until the fgets() call in line 26.
One way around that is to get scanf() to consume the trailing carriage return too:
scanf("%d%*c", &numb);
Which reads the integer from stdin into &numb, and reads (and discards) an extra character.
This all hilights one of the big problems with the use of scanf(), which is how to make it cope in the event that you get a string that you weren't expecting.
A safer way is to use a combination of fgets() and sscanf(). The former will let you read a string from a file (as you've done), and the latter will run a formatting string over it.
eg.
char temp[20];
fgets(temp, 20, stdin);
sscanf(temp, "%d", &numb);

Related

How to fix infinite loops when user enters wrong data type in scanf()?

C beginner here. For the program below, whenever the user inputs a character or a string it enters an infinite loop. How would you fix this while still using scanf? And what would be the better methods of writing this program rather than using scanf? Thanks to those who will answer.
#include <stdio.h>
#include <ctype.h>
int main() {
int rounds = 5;
do {
printf("Preferred number of rounds per game. ENTER NUMBERS ONLY: ");
scanf("%d", &rounds);
} while(isdigit(rounds) == 0);
return 0;
}
Using 'scanf' require the input to be formatted. Scanf has very limited ability to handle bad input. The common solution will be to use fgets/sscanf, following the structure below:
char buff[256] ;
int rounds = 0 ;
while ( fgets(buff, sizeof(buff), stdin) ) {
if ( sscanf(buff, "%d", &rounds) == 1 ) {
// additional verification here
break ;
} ;
} ;
// Use rounds here ...
The fgets/sscanf will allow recovery from parsing error - the bad input line will be ignored. Depending on requirement, this might be accepted solution.
I'd say there are just two "fixes".
Retain the scanf call(s), warts and all. Carefully refrain from typing non-digits when scanf is expecting digits.
Abandon scanf and use something else. We've just been discussing this tactic over at this new question.
Once you're using scanf, it's always tempting to try to "fix" it, so there's potentially a third answer lurking here, explaining how to do better, more user-friendly, more error-tolerant input while still using scanf. In my opinion, however, this is a fool's errand, a waste of time. The easy, obvious fixes for scanf's many deficiencies are themselves imperfect and have further deficiencies. You will probably spend more time trying to fix a scanf-using program than you would have spent rewriting it to not use scanf -- and you'll get overall better results (not to mention a cleaner program) with the non-scanf-using rewrite anyway.
Change
scanf("%d", &rounds);
To
int ret;
if ((ret = scanf(" %d", &rounds)) != 1) { // Skip over white space as well
if (ret == EOF) break;
scanf("%*[^\n\r]"); // Consume the rest of the line
}
If you really like scanf, you can use getch to discard non-numeric input:
int rounds = MIN_INT;
while (scanf("%d", &rounds)) != 1)
if (getc() == EOF) /* discard a rubbish character */
break; // or other error-handling return
// rounds is only valid if we did not break, when its value should be MIN_INT.
// but you might need another indicator
C beginner here as well. Like you, I use scanf, and it can be problematic sometimes.
I've had your same problem and tried to solve it with scanf and basic stuff before finding a better solution.
I've tried different solution from here but I continue to have the same problems again and again, like if I type:
a number followed by a character (e.g. 123a), the result is a valid number (which i don't want); the result is '123'.
a string of numbers and chars that begin with a number (e.g. 1a2b3), the result is still a valid number which is '1'.
a char at the beginning (e.g. a123) can generate infinite loop.
... and so on... I've tried do...while, only while, for... nothing.
The only solution I have found to prompt the user until he/she writes only numbers is the following, but...
NOTE: if the user type a space, the program considers only the part before it, e.g. '12 3', only 12 is considered, 3 doesn't exist... unless you want use an infinite loop like I did so, in this case, you can enter multiple numbers, check them and run your program on them all at once. e.g.: '12 23 34 45' ...
NOTE 2: this is a very basic beginner solution, I am learning, and this is just what I found with what I know. Can't do any better right now and, as I said, I didn't find any other solution that I liked the output.
NOTE 3: I use the counter to sum up all the inputs that are not numbers and store the value if it finds one. If I don't use this solution I'll end up in the case where if the first character is a number but the rest aren't, it's still valid (e.g.: '12w3' is 12, which I don't want)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
while (1) // try also multiple inputs separated by space
{
char str[10]; // should be enough for short strings/numbers (?!)
int strlength, num, counter;
do
{
printf("Enter a number: ");
scanf("%s", str);
strlength = strlen(str);
counter = 0;
for (int i = 0; i < strlength; i++)
{
if (!isdigit(str[i]))
counter++;
}
if (counter != 0)
printf("%s is not a number.\n", str);
} while (counter != 0);
num = atoi(str);
printf("%d is a number. Well done!\n\n", num);
}
}
You can also put it in a function and away from the main().

Why am I not able to enter desired number of inputs?

The problem is about taking input of strings x number of times using an array of pointers. x is the value entered by the user. I wrote the following code for the same. But the program is taking only x-1 inputs.
I have inserted fflush(stdin) because I think the scanf is consuming an enter first but I don't know from where.
I have tried using gets but with no use.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
//code to take input in an array of pointers
int x,i,j,length;
char ch[50],*t;
printf("How many names you want to sort:\n");
scanf("%d",&x);
char *names[x];
char *p;
printf("Enter the names:\n");
for(i=0;i<x;i++)
{
fflush(stdin);
scanf("%[^\n]s",ch);
length = strlen(ch);
p = (char *)malloc((length+1) * sizeof(char));
strcpy(p,ch);
names[i] = p;
}
return 0;
}
Why bother with complex format strings if you don't have to? Use fgets.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void err(const char * msg) {
fprintf(stderr, msg);
exit(1);
}
int main()
{
int x,i;
char ch[50];
printf("How many names you want to sort:\n");
if(!fgets(ch, 50, stdin)) err("Error reading line");
if(sscanf(ch, "%d",&x) != 1) err("Could not read integer");
// Better than using VLA
char **names = malloc(x*sizeof(*names));
if(!names) err("Error allocating names");
printf("Enter the names:\n");
for(i=0;i<x;i++) {
if(!fgets(ch, 50, stdin)) err("Error reading line");
ch[strcspn(ch, "\n")] = 0; // Remove newline
if(!(names[i] = strdup(ch))) err("Error duplicating string");
}
for(int i=0; i<x; i++)
printf("name %d: %s\n", i, names[i]);
}
Whenever a function has a return value that may indicate an error you should ALWAYS check it, and here that is the case for malloc, fgets, strdup and sscanf and. Read the documentation to find out what it actually returns to see how to check for errors. sscanf returns the number of successful assignments, and the other three returns a pointer which is NULL on failure.
You wrote in the comments that you are learning from the book "Let us C". A better fitting title would be "How to not code C". I've had a quick look at it and, it is really really bad. Apart from teaching very outdated C, it also teaches very bad habits in general, and many of the things you can read is completely WRONG. Actually, the majority of questions about C can be traced to that book, or at least could have. Two prime examples is that it consistently avoids very important stuff, such as error checking functions like scanf and malloc. I have not read every line, but I think it does not even mention how to error check scanf even once. It also uses the function gets which is not only deprecated but completely removed from newer C standards because it is so dangerous. It also says that you can modify a string literal, which is undefined behavior in C.

C language getchar() and putchar()

I'm a new C language learner and I have a problem below, I tried to print name out but it did not print. This is what I tried:
#include <stdio.h>
#include <ctype.h>
int main()
{
char name;
int len = 0;
printf("Enter the user name: ");
name = getchar();
while (name != '\n')
{
len++;
name = getchar();
}
printf("char = %d\n", len);
printf("name = ");
putchar(name);
return (0);
}
output:
Enter the user name: abcd
len = 4
name =
it should print out name = abcd.
I appreciate that and thank you!
getchar() and putchar() can only handle a single character at a time.
Since you need to store a string which is basically a sequence of characters, you need to declare name as a character array.
You can't use putchar() to print a string. Try puts() or printf().
And add a \0 character to denote the end of string when you encounter the '\n' at which point you stop reading.
char name[20];
int len = 0;
printf("Enter the user name: ");
name[len] = getchar();
while (name[len] != '\n')
{
name[++len] = getchar();
}
name[++len]='\0';
If putchar() must be used to print the string, you have the length of the string in len. Make a loop with a variable i=0 and keep iterating as long as i<len while incrementing i by 1
for(i=0; i<len; ++i)
{
putchar(name[i]);
}
You might want to do some error checking to ensure that getchar() worked properly. It will return EOF on error.
And name should be big enough to hold the input string.
getchar() and putchar() handles only single character.
getchar()-
is an input function. It is used to read one character at a time from console input (generally keyboard).
Ex:
char c=getchar();
putchar()-
is an output function. It is used to display one character at a time onto console output (generally monitor). It accepts one argument of character type. Ex:
char c;
putchar(c);
you should use gets() and puts() to work with strings or you can use printf() and scanf()
Learn about the concept of array in C first.
Use scanf() and printf() like below:
#include <stdio.h>
int main(){
char name[20];
printf("Enter the name: ");
scanf("%s", name);
printf("Name: %s", name);
return 0;
}
This is how you can take input and print using getchar() and putchar().
#include <stdio.h>
int main(void)
{
int name;
printf("Enter the user name: ");
while ((name = getchar()) != EOF)
putchar(name);
return 0;
}
I hope this helps. :)
You may need to learn more about programming and about data structures. I would recommend SICP, an excellent and freely available introduction to programming (which is not about C).
You need to learn more of C. Notably about arrays (but they have limitations, I leave you to find out which ones), perhaps struct, pointers, C dynamic memory allocation. That should take you a few weeks, and you need to read several books (and also some reference material like here, perhaps glance also into the specification of C11, i.e. n1570).
(ask yourself what would or should happen if the user of your program entered a name of 50 letters, or even a million ones; and what about "wrong" input, e.g. digits or punctuation? think about what a name really is inside a computer)
Since you are required to only use getchar and putchar, you need to read carefully their specification. Be aware that stdio is often buffering. Perhaps you'll need to use fflush.
Then you could read a name into some data structure (I leave you to find out which ones), and you could read one character at a time using getchar to fill that data structure. Likewise you could output that data structure one character at a time using putchar.
Of course you'll use some control flow primitives (probably some kind of looping).
We won't do your homework.
Don't forget to enable all warnings and debug info in your compiler (e.g. compile with gcc -Wall -Wextra -g if using GCC....). Read documentation about your compiler (e.g. look into the Invoking GCC chapter). Of course, learn how to use the debugger (gdb, see Debugging with GDB)
You are the one starting to learn C programming. Be persevering, it takes some time (weeks or months of work). Read a few books, look into the source code of existing software in C (e.g. free software on github).
PS. For experts on C, doing your homework is trivial; however you should learn by yourself - the purpose of the homework is to teach you something - and if you copy a solution from elsewhere you won't learn anything

Is it possible to use scanf("%d" &i) and use the first number inputted only, and nothing else?

First off, I am not familiar with c at all. It would be great if you treated me like a total beginner, which I am.
So, the problem I have is that I don't seem to be able to make it so that the program only takes the information of one number, uses it, then disregards any other information.
At the moment I have something similar to this:
#include <stdio.h>
#include <string.h>
int main(){
int i, ret;
char c, type;
do
{
printf("Convert ASCII # to character\n");
printf("q: Quit.\n");
scanf("%c", &type);
/* I use the " if(type== 'n'); " a number of times. */
/* I left the others out to simplify what my problem is. */
if(type=='1'){
printf("ASCII NUMBER -> CHAR \n");
printf("\t Please input one ASCII code \n");
int ret = scanf("%d", &i);
/* My aim here is to get the amount of integers the user inputs,*/
/* and use that to categorize, but I think I am failing to do so. */
if(ret==1){
printf("\t The character for ASCII code %d is -> '%c' \n\n", i, i);
break;
}
else{
printf("Please input one number./n/n");
break;
}
}
}
while(type=='q');
return 0;
/* A problem I face a lot is where the program would terminate*/
/* even when the while conditions weren't met. */
}
I hope you could understand what I'm trying to do by looking at the code above.
Any help would be greatly appreciated!
the program ends because of the character [enter] left in the input buffer.
You give input value for type then for i and press [enter]. this [enter] is a character left in the input buffer which will be read by next
scanf("%c",type);
so the loop exits. Therefore use getchar() after
int ret = scanf("%d", &i);
To clear the input buffer. and the loop will not end unexpectedly.
Make these changes,
printf("\t Please input one ASCII code \n");
int ret = scanf("%d", &i);
getchar(); //this will read the [enter] character in input buffer
/* My aim here is to get the amount of integers the user inputs,*/
/* and use that to categorize, but I think I am failing to do so. */
if(ret==1){
In general, I find it better to use fgets() (alternatively, if you are using C99, gets_s() -- although I still prefer fgets() for maximum portability to older compiler environments) for all user-based input, then if necessary use sscanf(), strtol(), and the like to convert the string into other data types, as this will read data by line in a way that is buffer-safe and you won't have to worry about things left in the input buffer. This is especially true for user-based input which is never well-formed (due to typos, etc). scanf() really only works well when reading from well-formed input files.
See the comp.lang.c FAQ which describes some of the problems that often occur when using scanf() in detail, including the problem you are seeing above, where inputs seem to be getting skipped:
http://c-faq.com/stdio/scanfprobs.html
http://c-faq.com/stdio/scanfhang.html
http://c-faq.com/stdio/scanfinterlace.html
http://c-faq.com/stdio/scanfjam.html
To find out more about any C standard library function, at a linux command prompt (or Google) type: man 3 fgets and so on.
fgets: http://linux.die.net/man/3/fgets
sscanf: http://linux.die.net/man/3/sscanf
strtol: http://linux.die.net/man/3/strtol
Example:
char buffer[256], type;
fgets( buffer, sizeof(buffer), stdin );
if( sscanf( buffer, "%c", &type ) == 1 ) {
// Was able to read a char from the buffer, now you can use it.
}
else {
// Wasn't able to read a char from the buffer. handle it if required.
}

Why does scanf get stuck in an infinite loop on invalid input? [duplicate]

This question already has answers here:
Why is scanf() causing infinite loop in this code?
(16 answers)
Closed 9 years ago.
In line 5 I read an integer and isint is getting 1 if it reads an integer or 0 if it's not an integer. If isint is 0 I have a loop asking user to give an integer and I read until the user gives an integer. I try this code giving a character instead of an integer but I have an infinite loop. The program just doesn't wait to give a new input. What's wrong with my code?
#include <stdio.h>
int main(void) {
int arg1;
//int arg2;
int attacknum = 1;
int isint = 1;
//printf("Insert argument attacks and press 0 when you have done this.\n");
printf("Attack %d\n", attacknum);
attacknum++;
printf("Give attacking argument:");
isint = scanf("%d", &arg1); //line 5
while(isint == 0){
printf("You did not enter a number. Please enter an argument's number\n");
isint = scanf("%d", &arg1);
printf("is int is %d\n", isint);
}
return 0;
}
As others have mentioned, if scanf can't parse the input, it leaves it unscanned.
Generally scanf is a poor choice for interactive input because of this kind of behavior, and because it doesn't match the line-at-a-time interface experienced by the user.
You are better off reading one line into a buffer using fgets. Then parse that line using sscanf. If you don't like the input, throw the whole line away and read another one.
Something like this:
#include <stdio.h>
int main(void)
{
char line[256];
int arg1;
int isint;
while (1) {
printf("Give attacking argument:");
fgets(line, sizeof line, stdin);
isint = sscanf(line, "%d",&arg1);
if (isint) break;
printf("You did not enter a number.Please enter an argument's number\n");
}
printf("Thanks for entering %d\n", arg1);
return 0;
}
(For production code you'll want to handle long lines, check return codes, also check for trailing garbage after the number, etc.)
Actually, an even better approach would be to not use scanf if you just want to read an integer, and instead use strtol. That gives you a handy pointer to the character just after the number, and you can check that it's whitespace or nul.
When scanf is confronted with a non-digit it will not consume any input and return that zero integers were read. The non-digit will stay in the input for the next call to scanf that will behave the same as the first call, etc.
In answer to your question below. You could use fgetc to parse at least one character, but this will give the error messages for every character already typed. Typically I think you want to skip until a newline. To this end you could use fgets as suggested by poolie. Or you could add the following after scanf.
int ch;
if (isint == 0)
while ((ch = fgetc(stdin)) != EOF && ch != '\n')
{
/* Skip characters */
}
P.S: In your case it is probably better to put it just before the first printf in the loop.

Resources