Reading in a list - c

I've to code a program that reads in a list of student's names and ids and sort them based on first name, last name, and id. But there are currently two problem with my code.
#include <stdio.h>
int main() {
char firstName[200][21], lastName[200][51];
unsigned short id[200]; // used short to decrease memory usage
int i;
for (i=0; i<200; ++i) {
printf("Enter first name of student %d: ",i+1);
getchar(); // FIX to consume enter
fgets(firstName[i],21,stdin);
printf("Enter last name of student %d: ",i+1);
fgets(firstName[i],21,stdin);
printf("Enter student number of student %d: ",i+1);
scanf("%hu",&id[i]);
printf("You've entered %s %s with ID %hu",firstName[i],lastName[i],id[i]);
}
// other functions to do after reading in the data is successfully done
}
Reading in the values must be stopped if students reach 200 or if the user enters EOF.
Student's First Name or Last Name might consist of multiple parts (something like "john john" so I used fgets instead of scanf and %s to read in the word which comes after space as well but it fails and only last name is stored.
Could you tell me how to stop the loop with EOF and read in the first and last name correctly? Thanks.

for checking the EOF , you can use function:
feof(FILE*) // if it returns 1 then it is EOF reached.
you can use it like the below snippet :
if (feof(fp) == 1)
break;
and the 2nd problem :
printf("Enter last name of student %d: ",i+1);
fgets(firstName[i],21,stdin); // this is incorrect.
use 'lastname' instead of 'firstname'. It should be like this :
fgets(lastName[i],21,stdin);
in this way you are overwriting the value of firstname

Related

C: Loop only prints the last index

I am new to C, so excuse me for asking a seemingly easy question. but I have a loop which loops depending on the user, and inside the loops it asks for a name and an age, however when I go to print, it only prints the last entry and not all the entries I want.
#include <stdio.h>
int main()
{
int size,age;
char name [30];
printf("How long to loop for: ");
scanf("%d", &size);
for (int i=0; i<size; i++)
{
printf("Enter first name: ");
scanf("%s", name);
printf("Enter %s's age: ",name);
scanf("%d",&age);
printf("name: %s, age: %d\n", name,age);
}
return 0;
}
Right now your name and age variables will only hold the last input they received, thats why you're program only prints the last index. You need an array of int as well as an array of char [] to "hold" each input they receive, otherwise those inputs get lost and you only get input for the last index.
your variables should be initialized like:
int size;
printf("Enter size: ");
scanf("%d", &size);
int age [size];
char name[size][30];
in order to get user input and print each entry you will need to access each index by looping through the array size.
to access each index:
age[i]
name[i]
Please Note: using scanf to get a string from user input is generally bad, as it can cause problems if you happen to use a space(such as inputting your full name for example) in your input, and it can cause a buffer overflow if your string is longer than the buffer. Instead you can use fgets, but for your question it isn't necessary, just something to considered in the future in case you want to have spaces in your inputs.
Are you sure that the first scanf actually reads a number.
You want the following to check
if (scanf(" %d", &size) != 1) { // Note space - Eats white space/new lines
printf("Error - invalid size\nExiting\n");
return -1;
}
Prevent buffer overruns
Use:
scanf(" %29s", name); // See above
See point 1 for age
I think this will solve your problems
Okay so if I am understanding you correctly, you are looping through the for loop size number of times and each time you are setting the contents of the variables age and name. It sounds like you are expecting each iteration through the loop to save your entered instance of age and name but this is not the case.
Since you only have one age and one name variable they are going to store whatever the most recently taken input was. So this means whatever was entered on the last loop is what was last written into the variables name and age.
If you then try to print the contents of those variables you are going to see whatever was most recently entered into those variables. you would need more than one name and more than one age variable to write into if you were trying to save multiple entries.
Okay so Anthony, maybe you need to try a little bit of review when it comes to allocating memory. So when we declare the variable
int age;
we are telling the compiler to allocate enough memory to store one single integer that we will call 'age' in our program. since we only asked for enough memory to store one integer, every time you scanf() into the age variable, the single integer is written into that space.
What you want is to store a new integer every time you do another run through your for loop. So, you could declare an array of integers as follows.
int age[20];
Now we have asked the compiler to allocate enough space to store 20 different integers. there will an integer in position age[0] and another integer in age[1] and another in age[2] so on. So now you could use a loop to index through your array and store each entered age from stdin into a different position in the array as follows
for(int i=0; i<20; i++)
{
printf("Please enter your age: ");
scanf("%i", &age[i]);
}
So this loop starts with i=0 and so enters the input from stdin to age[0], the next iteration through the loop has i=1 and so enters the stdin input to age[1] and so on.
Hopefully this clarifies things a bit more?
A major fault is that your printfs will not be displayed as they are buffered.
You need a fflush after them
i.e.
printf("How long to loop for: ");
fflush(stdout);
And
printf("Enter first name: ");
fflush(stdout);
etc...

How to use int in array?

i create a really simple coding and it got no errors but when it run, i cant put input in the 'age' side.
#include <stdio.h>
#include <conio.h>
struct baby
{
char name[2][30];
char sex[2][7];
char birthday[2][12];
};
struct parents
{
char nama[2][30];
int age[2];
};
struct momdad
{
struct parents father;
struct parents mother;
};
struct momdad info;
struct baby newborn;
int main()
{
int i;
for(i=0;i<2;i++)
{
printf("\nEnter baby's name %d: ",i+1);
gets(newborn.name[i]);
printf("Enter baby's sex %d (Female/Male): ",i+1);
gets(newborn.sex[i]);
printf("Enter baby's birthday %d (dd/mm/yyyy): ",i+1);
gets(newborn.birthday[i]);
printf("Enter father's name %d: ",i+1);
gets(info.father.nama[i]);
printf("Enter father's age %d: ",i+1);
gets(info.father.age[i]);
printf("Enter mother's name %d: ",i+1);
gets(info.mother.nama[i]);
printf("Enter mother's age %d: ",i+1);
gets(info.mother.age[i]);
}
printf("\n\n\tNEW BORN BABY IN KUANTAN HOSPITAL");
printf("\n\n===============================================");
for(i=0;i<2;i++)
{
printf("\n\nBaby name: %s",newborn.name[i]);
printf("\nSex: %s",newborn.sex[i]);
printf("\nBirthday: %s",newborn.birthday[i]);
printf("\n\nFather name: %s",info.father.nama[i]);
printf("\nFather age: %s",info.father.age[i]);
printf("\n\nMother name: %s",info.mother.nama[i]);
printf("\nMother age: %s",info.mother.age[i]);
printf("\n\n----------------------------------------------");
}
getch();
}
this is my declaration that i think is wrong but i dont know how.
int age[2];
and the input will be putting in here
printf("Enter father's age %d: ",i+1);
gets(info.father.age[i]);
n in here
printf("Enter mother's age %d: ",i+1);
gets(info.mother.age[i]);
i'm still new in programming sorry for asking this simple question
Never use gets(). It cannot be used safely, and as of 2011 it's been removed from the language.
In a comment, you mention calling fflush(stdin);. The behavior of fflush is undefined for input streams. Some implementations define the behavior, but depending on that will make your program non-portable -- and you don't need it anyway.
The simplest way to read input data is to use scanf(), but that has some of its own problems. For example, if you use scanf("%d", &n); and type 123, it will consume the 123 and leave anything following it (such as a newline) waiting to be read.
A better way to read input is to use fgets to read a line of text, then sscanf to parse the data from the input line. It re
Here's an example:
#define MAX_LEN 200
char line[MAX_LEN];
int num;
printf("Enter an integer: ");
fflush(stdout);
if (fgets(line, MAX_LEN, stdin) == NULL) {
fprintf(stderr, "Error reading line\n");
exit(EXIT_FAILURE);
}
if (sscanf(line, "%d", &num) != 1) {
fprintf(stderr, "Error parsing integer from line\n");
exit(EXIT_FAILURE);
}
printf("The number is %d\n", num);
I call fflush(stdout) after the first printf to ensure that the prompt actually appears. stdout can be line-buffered, meaning that output won't appear until you've printed an entire line. The fflush isn't always necessary, but it's a good idea.
The fgets call reads a full line of input or MAX_LEN characters if the line is longer than that. (gets has no way to specify the maximum input size, so no matter how big your target array is, it can always read more and clobber random memory.) fgets returns a null pointer if there was a problem, and I check for that.
sscanf is similar to scanf, but it reads data from a string in memory, not from standard input. (There's also fscanf, which reads from a specified file.) It returns the number of items that it successfully scanned, so a value other than 1 would indicate an error.
I suggest reading the documentation for all these functions; I haven't covered everything they do. In fact, you should read the documentation for any standard library function you use.

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().

Storing values in struct objects using c and a do-while loop

I'm trying to store a few values in a struct object and I want to repeat the prompt until the user types in "yes". I want to use a do-while loop for that. I'm already failing with the read-in of the first "last name". When I type in something, the program just stops (no error). I don't even use the do-while, since I'm not sure if it will work with my while() condition.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
struct employeelist
{
char last[6];
char first[6];
int pnumber;
int salary;
};
int main()
{
struct employeelist employee[5];
char check;
//do
//{
printf("Hello. Please type in the last name, the first name, the personal number and the salary of your employees.\n");
printf("Last name: ");
scanf("%c", employee[1].last);
printf("First name: ");
scanf("%c", employee[1].first);
printf("Personal number: ");
scanf("%d", &employee[1].pnumber);
printf("Salary: ");
scanf("%d", &employee[1].salary);
printf("You have more employess (yes/no)?: ");
scanf("%c", &check);
//}while (scanf("yes"));
return 0;
}
Use %s as your format specifier if you're trying to get a string. You might also want to limit its length to 5, since that's how much space you have for last and first. So that would be %5s. Also, 5 characters is pretty short for a name.
Another comment: arrays in C are zero-based, so employee[1] is the second employeelist in your array. If you want to do this in a loop with an incrementing index, start at 0.
Hi when you read char array you must use scanf("%s", employee[1].last); %s but not %c
What do you think this code does?
scanf("%c", ....
%c indicates that scanf should only read ONE character.
One letter is not going to get you an entire name.
You need to switch to %s for starters.
First of all the first index to work
with will be '0',not 1.
wrong identifier for string,it
should be %s.
If you just want to iterate by
asking y/n then just change the
display message from yes/no to y/n
and also change that strange while
condition to check=='y'||check=='Y'.
The code will actually not work
after 5 iterations because you
initialized only 5 structures of
that type.Why don't you add that in
the loop?

Resources