C - Duplication of Printf when an array is involved - c

I hope this isn't too basic of a question for stack overflow. But I have a query which is trying to determine the amount of grades in an array, and then ask for user input of each of those grades. It looks like this:
#include <stdio.h>
int main (void)
{
int size;
printf ("Enter The Amount Of Grades In Your Array: ");
scanf("%i", &size);/*Stores Amount Of Grades In The Array*/
char myGrades[size];
int i;
for (i = 0; i < size; ++i)
{
printf ("Enter the grade:");
scanf ("%c",&myGrades[i]);
}
return 0;
}
I expect the first line after int i to read "Enter The Grade:" but instead it looks like "Enter The Grade:""Enter The Grade:"
I don't understand why it says enter the grade the second time without first asking for my input on the first "enter the grade". Any suggestions would be much appreciated!

Your first scanf is leaving the \n behind, and then automatically reading it again the next time as if you'd pressed enter (so the newline is stored in your array). You can get around this by using " %c" instead. The space will get rid of any newlines or spaces before the character you want.

Related

Read user input twice in a for-loop using fgets and scanf [duplicate]

This question already has answers here:
fgets doesn't work after scanf [duplicate]
(7 answers)
Closed 1 year ago.
CODE:
#include<stdio.h>
#include<stdlib.h>
int main(){
struct mobile{
char N[10];
int ram, pixel, price;
}B[5];
int min;
char trash;
for(int i = 0; i < 5; i++){
printf("Enter Mobile Name: ");
fgets(B[i].N, sizeof(B[i].N), stdin);
printf("Enter features (ram/camera pixels/price): ");
scanf("%d%d%d", &B[i].ram, &B[i].pixel, &B[i].price);
printf("\n");
}
}
The program is not accepting value for name of mobile second time. It prints Enter mobile name but don't take value then print Enter features and ask for value. I tried adding a second scanf above printf("\n"); but didn't work. Help please. Thanks.
Remove \n from buffer
scanf leaves a newline in the buffer, which is then read by fgets. The other problem is, that you aren't dividing the user input using a delimiter so I would put a space or a slash between the type specifiers %d:
scanf("%d/%d/%d\n", &B[i].ram, &B[i].pixel, &B[i].price);
The input should then be something like this:
Enter specs (ram/pixels/price): 8/12/500
The trailing character \n is now being read, but it isn't stored in any variable.
Remove \n from fgets() input
This doesn't cause your problem, but I would also remove the trailing \n from the fgets() input, because it's probably not supposed to be part of the phone's name.
#include <string.h>
fgets(B[i].N, sizeof(B[i].N), stdin);
B[i].N[strcspn(B[i].N, "\n")] = '\0';

C scanf not working for multi word input

I have this code.
#include <stdio.h>
struct name
{
int age;
char fullname[20];
};
struct name names[20];
int main()
{
int n,i;
printf("Count of names:\n");
scanf("%d",&n);
for (i = 0; i < n; i++)
{
printf("Name %d : ",i);
scanf("%[^\n]s",names[i].fullname);
}
return 0;
}
And when i execute :
rupam#linux ~ $ ./a.out
Count of names:
5
Name 0 : Name 1 : Name 2 : Name 3 : Name 4 :
rupam#linux ~ $
It don't wait for user input. Somehow the scanf is not working.
Well, if i use
scanf("%s",names[i].fullname);
It works for single word inputs.
What am i doing wrong here ?
So lets see what happens with the input here. First, you call scanf("%d" to read an integer. Assuming you enter something like 5Enter, the scanf call will read digits and convert them to an integer. Since it finds at least one digit, it will succeed, reading that digit and leaving the \n from the Enter to be read.
Now you go into the loop, where you call scanf("%[^\n]s" which attempts to read one or more non-newline characters followed by a newline, then attempts to read an s. Since the next character of input is a newline, this immediately fails (reading nothing), but you don't check the return value of scanf, so you don't notice. You then loop attempting to read more, which will fail again.
So what you need to do is ignore the newline. The easiest way is probably to just use a space in the format, which causes scanf to read and ignore whitespace, until it finds a non-whitespace character; change your second scanf to:
scanf(" %19[^\n]", names[i].fullname);
Note some additional changes here. We got rid of the spurious s as you don't particularly want to match an s after the name. We also added a limit of 19 characters to avoid overflowing the fullname array (19 characters max + 1 for the terminating NULL byte).
Use getchar() after printf in for loop:
#include <stdio.h>
struct name
{
int age;
char fullname[20];
};
struct name names[20];
int main()
{
int n,i;
printf("Count of names:\n");
scanf("%d",&n);
for (i = 0; i < n; i++)
{
printf("Name %d : ",i);
getchar();//getchar here
scanf("%[^\n]s",names[i].fullname);
}
return 0;
}
If you may work with files with Windows line-ending in the future (redirecting files to stdin), then instead of using one getchar() as suggested by #jahan you can use
if(getchar()=='\r') getchar();
This can increase the portability of your code.

How to limit the input on a 2D array so it won't blow up?

I have a small program, where i say the number of lines and columns of a array I want to input, then input info to fill that array with data. What it does next it's not important so ill just omit that part of the code and put (...) in it.
int main (){
int nl, nc,i,j,z,n;
scanf ("%d %d\n", &nl,&nc);
char matrix [nl] [nc];
for (i=0;i<nl;i++)
for (j=0;j<nc;j++)
scanf(" %c",&matrix[i][j]);
scanf("%d",&n);
int s[n*2];
for (z=0;z<n*2;z++)
scanf("%d",&s[z]);
int y=0;
char s2[n];
for (z=0;z<n*2;z+=2){
s2[y]=matrix [(s[z])-1][(s[z+1])-1];
y++;
}
for (z=0;z<n;z++)
printf ("%c", s2[z]);
return 0;
}
My problem is, that it this blows up if input more chars than I should. For example if my input is:
2 3
ABC
DEF
This works just fine.
But if I put:
2 3
ABC
DEFF
It give me a segmentation fold and stops the program. Keep in mind that I have a space before the "%c" in scanf so it's ignoring the "\n" and spaces I put in the input.
What can I do to stop that extra chars in the array from blowing up?
scanf("%d",&n);
int s[n*2];
This code tries to scan and convert whatever is left in the input after reading the matrix. If the input is not numeric, as will be the case if you enter more letters than the matrix should contain, the conversion will fail and n will remain uninitialized. Then int s[n*2]; is undefined because n is indeterminate.
If you want to ignore some characters in the input, you need to do so explicitly. You also better check return values of all functions that take user input, and verify that the values read are sensible.
Ok i figured out that the problem with it was input going to the buffer. To solve this i cleared the buffer before the next input using:
while (getchar() != '\n');
Your problem is filling the array over that size.
You get your input character by character and if you enter character more than your array size the program will stopped or has been logical error,
So you can use getche() and check the array constraint.
You can edit your code as follow:
int main (){
int nl, nc,i,j;
scanf ("%d %d\n", &nl,&nc);
char matrix [nl] [nc];
for (i=0;i<nl;i++)
for (j=0;j<nc;j++)
matrix[i][j]=getche();
(...)
return 0;
}
Use %s instead of %c and remove the inner loop. So the code will be something like this:
for(i=0; i<nl; i++)
{
scanf("%s", &matrix[i]);
}

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.

C Programming data input error

I'm writing this to get student information (full name, id and gpa for the last 3 trimester, so I used structures and a for loop to plug in the information however, after 1st excution of the for loop (which means at student 2) my 1st and 2nd input are shown on screen together. How could I prevent this from happening in a simple and easy way to understand? ( P.S: I already tried to put getchar(); at the end of the for loop and it worked, however; I'm not supposed to use it 'cause we haven't learnt in class)
The part of the c program where my error happens:
#include <stdio.h>
struct Student {
char name[30];
int id;
float gpa[3];
};
float averageGPA ( struct Student [] );
int main()
{
int i;
float average;
struct Student studentlist[10];
i=0;
for (i; i<10; i++)
{
printf("\nEnter the Student %d full name: ", i+1);
fgets(studentlist[i].name, 30, stdin);
printf("Enter the Student %d ID: ", i+1);
scanf("\n %d", &studentlist[i].id);
printf("Enter the Student %d GPA for the 1st trimester: ", i+1);
scanf("%f", &studentlist[i].gpa[0]);
printf("Enter the Student %d GPA for the 2nd trimester: ", i+1);
scanf("%f", &studentlist[i].gpa[1]);
printf("Enter the Student %d GPA for the 3rd trimester: ", i+1);
scanf("%f", &studentlist[i].gpa[2]);
}
average = averageGPA(studentlist);
printf("\n\nThe average GPA is %.2f", average);
return 0;
}
float averageGPA (struct Student studentlist[])
{
int i;
float total = 0.0, average = 0.0;
for (i=0; i<10; i++)
{
total = studentlist[i].gpa[0] + studentlist[i].gpa[1] + studentlist[i].gpa[2];
}
average = total / 30 ;
return average;
}
Computer output:
Enter the Student 1 full name: mm
Enter the Student 1 ID: 12
Enter the Student 1 GPA for the 1st trimester: 3
Enter the Student 1 GPA for the 2nd trimester: 4
Enter the Student 1 GPA for the 3rd trimester: 3
Enter the Student 2 full name: Enter the Student 2 ID: <<<<< Here is the problem!!
Try eating the newline after the last scanf:
scanf("%f ", &studentlist[i].gpa[2]);
^
This is very much like your getchar solution. It's actually superior to getchar, since it only discards whitespace.
But you have to use getchar() to discard the newline character that is still in the input buffer after your last scanf("%f"), which according to given format converts a float and leave in the buffer all other chars.
If you can't use getchar(), use another fgets() at the end of the loop.. but of course getchar() would be better
Edit for explanation: whenever you type on your keyboard characters go in a input buffer waiting to be processed by your application. getchar() just "consumes" one character from this buffer (returning it), waiting for a valid char if the buffer is empty. scanf("%f") only "consumes" characters resulting in a float. So, when you type "5.12<enter>", scanf reads and removes from buffer "5.12" leaving "<enter>". So the next fgets() already finds a newline in the buffer and returns immediately; that's why you should use getchar(): ignoring its returning value you successfully discard "<enter>" from the buffer. Finally, please note that if in the buffer there is only "<enter>", scanf("%f") discards it (since it cannot be converted in a float) and waits for another input blocking application.
One last note: input stream is buffered by your OS default policy, in the sense that application does not receive any character until you type "<enter>".
Use scanf in following way to read the student name:
scanf(" %[^\n]",studentlist[i].name);
The first space in the format specifier is important. It negates the newline from previous input. The format, by the way, instructs to read until a newline (\n) is encountered.
[Edit: Adding explanation on request]
The format specifier for accepting a string is %s. But it allows you to enter non-whitespace characters only. The alternative way is to specify the characters that are acceptable (or not acceptable, based on the scenario) within square brackets.
Within square brackets, you can specify individual characters, or ranges, or combination of these. To specify characters to be excluded, precede with a caret (^) symbol.
So, %[a-z] would mean any character between a and z (both included) will be accepted
In your case, we need every character other than the newline to be accepted. So we come up with the specifier %[^\n]
You will get more info on these specifiers from the web. Here's one link for convenience: http://beej.us/guide/bgc/output/html/multipage/scanf.html
The space in the beginning actually 'consumes' any preceding white space left over from previous input. You can refer the answer here for a detailed explanation: scanf: "%[^\n]" skips the 2nd input but " %[^\n]" does not. why?
I would just say no to scanf(). Use fgets() for all input fields and convert to numeric with atoi() and atof().

Resources