I have problem with reading input with blank spaces - c

I made this function to get input:
void entrada_dados(Time* time, int i){
scanf("%s %d %d", time[i].nome, &time[i].gols_marcados, &time[i].gols_sofridos);
};
The input is in this form:
2
Campinense
23
12
ABC
30
13
The main is:
int main(void) {
int n = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++){
entrada_dados(time, i);
}
....
My problem is when the team name have some space like to "São Paulo". I have tried some forms to solve, but no one solved my problem.
I tried:
void entrada_dados(Time* time, int i){
fscanf(stdin, "%[^\n] %d %d", time[i].nome, &time[i].gols_marcados, &time[i].gols_sofridos);
};
and:
void entrada_dados(Time* time, int i){
fgets(time[i].nome, 100, stdin);
scanf("%d", &time[i].gols_marcados);
scanf("%d", &time[i].gols_sofridos);
}
but in the first case the output have nothing, and second case the output miss some cases. Someone can help me to understand this problem?
Edit 1:
The definition of .name is:
typedef struct Time{
char nome[100];
int gols_marcados;
int gols_sofridos;
} Time;
Edit 2:
Solution:
One way to solve it:
Try two fscanfs fscanf(stdin, " %[^\n]", time[i].nome);
fscanf(stdin, "%d %d", &time[i].gols_marcados, &time[i].gols_sofridos);
Thank you guys.

Because you have to handle strings with spaces, it's better to use fgets for those.
But mixing fgets and scanf doesn't work too well. We can replace scanf with fgets followed by sscanf.
To decode numbers, we can use strtol or sscanf
We take advantage of the fact that each element/member of Time appears on a separate line in the input file, so we can do fgets for every line. This simplifies the code and makes error checking easier.
Here is the refactored code. It is annotated.
I didn't do this, but, if these sequences are done a lot, we can combine some of these sequences in helper functions to reduce some code replication (e.g. a function that combines the fgets followed by the sscanf)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Time {
char nome[100];
int gols_marcados;
int gols_sofridos;
} Time;
// RETURNS: 1=valid, 0=syntax error
int
entrada_dados(Time *timelist, int i)
{
char buf[100];
char *cp;
Time *tim = &timelist[i];
int valid = 0;
do {
// get name
if (fgets(tim->nome,sizeof(tim->nome),stdin) == NULL)
break;
// strip newline
tim->nome[strcspn(tim->nome,"\n")] = 0;
// get number using strtol
if (fgets(buf,sizeof(buf),stdin) == NULL)
break;
tim->gols_marcados = strtol(buf,&cp,10);
if (*cp != '\n')
break;
// get number using sscanf
if (fgets(buf,sizeof(buf),stdin) == NULL)
break;
if (sscanf(buf,"%d",&tim->gols_sofridos) != 1)
break;
// all input is okay
valid = 1;
} while (0);
return valid;
};
int
main(void)
{
int n = 0;
#if 0
scanf("%d", &n);
#else
char buf[100];
if (fgets(buf,sizeof(buf),stdin) == NULL)
exit(1);
sscanf(buf,"%d",&n);
#endif
// allocate sufficient space
Time *timelist = malloc(sizeof(*timelist) * n);
// read in data
int valid = 0;
for (int i = 0; i < n; i++) {
valid = entrada_dados(timelist, i);
if (! valid)
break;
}
// show the data
if (valid) {
for (int i = 0; i < n; i++) {
Time *tim = &timelist[i];
printf("nome='%s' gols_marcados=%d gols_sofridos=%d\n",
tim->nome,tim->gols_marcados,tim->gols_sofridos);
}
}
return 0;
}
Here is the program input:
3
Campinense
23
12
ABC
30
13
São Paulo
17
82
Here is the program output:
nome='Campinense' gols_marcados=23 gols_sofridos=12
nome='ABC' gols_marcados=30 gols_sofridos=13
nome='São Paulo' gols_marcados=17 gols_sofridos=82

Related

Scanning different data types in C

I want to write a program, at first I input a number N, then I want to get the name (can consist of multiple words) and price of N items one by one. Example:
3
item a // the name can consist of multiple words
25.00
item b
12.50
item c
8.12
Next I want to process this data, however i got stuck on the scanning part. my code looks like this:
#include <stdio.h>
int main(){
int n;
char name[50];
int price;
scanf("%d\n", &n);
for(int i = 0; i < n; i++){
scanf("%s\n%d",name,&price);
printf("%s , %d", name, price);
}
printf("end");
}
This works for a single word item, but if the item has a space in it will not continue scanning. I tried using the gets() function, however I still don't have the right result. the code:
for(int i = 0; i < n; i++){
gets(name);
scanf("%d\n",&price);
printf("%s , %d\n", name, price);
}
printf("end");
returns:
3 // Input 3 items
item a // name of first item
1 // price of item 1
item b // name of item 2
item a , 1 // the print of the first item
2 // price of item 2
item c // name of item 3
item b , 2 // print of item 2
3 // price of item 3
word // no clue where this new input came from
end // end of scanning
My question is, how would I go about correctly scanning an input such as this? I also tried changing the scan function into while((c = getchar()) != '\n');, but got the same result...
Mixing gets(), scanf() is bad as scanf() tends to leave the trailing '\n' in stdin.
Using gets() is bad.
scanf("%s", ...) is not useful for reading a line of info with spaces meant to be saved.
how would I go about correctly scanning an input such as this?
A simple alternative is to read each line into a string and then parse the string.
#include <stdio.h>
int main() {
char line[100];
int n;
fgets(line, sizeof line, stdin);
sscanf(line, "%d", &n);
for(int i = 0; i < n; i++){
char name[50];
// int price;
double price;
fgets(line, sizeof line, stdin);
sscanf(line, " %49[^\n]", name);
fgets(line, sizeof line, stdin);
// sscanf(line, "%d", &price);
sscanf(line, "%lf", &price);
printf("%s , %.2f\n", name, price);
}
printf("end");
}
Advanced: Better code would check the return values of fgets(), sscanf(). Maybe replace sscanf(line, "%lf",... with strtod().
I think you could probably figure out what's happening here pretty easily if you added some more output. Let's try shall we?
Also, first of all you're really looking for a double input - not an integer. With an integer, your scan function won't match properly based on what you're looking for. But let's add some more output!
#include <stdio.h>
int main()
{
int n;
char name[50];
double price;
printf("Enter count: ");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
printf("%s\n", "Please type a name followed by a newline followed by a number and then press enter:");
scanf("%s\n%lf", name, &price);
printf("%s , %lf", name, price);
}
return 0;
}
So I think what was happening in your initial attempt was a combination of things. Mostly that you were possibly pressing enter after the output from the first iteration? That will break the scanf call - since it isn't expecting to start with a \n but it is immediately expecting you to enter a name.
Second, I don't know the number you entered in the first iteration, because you didn't supply the output of it while still using scanf - so I have nothing other than speculation. You possibly used an integer on the first go, and subsequently on the remaining iterations you chose to use decimals? Again, this is only a guess.
Sometimes it is easier to just write your own functions with error checking. Below is a suggestion. You may also want to check that the numbers are non-negative.
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
void ReadLine(char result[], int resultLen)
{
int ch, i;
assert(resultLen > 0);
i = 0;
ch = getchar();
while ((ch != '\n') && (ch != EOF)) {
if (i < resultLen - 1) {
result[i] = ch;
i++;
}
ch = getchar();
}
result[i] = '\0';
}
void ReadInteger(int *i)
{
int ch, count;
count = scanf("%d", i);
if (count == 1) {
do {
ch = getchar();
} while (isspace(ch) && (ch != '\n'));
} else {
fprintf(stderr, "invalid input, integer expected\n");
exit(EXIT_FAILURE);
}
}
void ReadReal(double *x)
{
int ch, count;
count = scanf("%lf", x);
if (count == 1) {
do {
ch = getchar();
} while (isspace(ch) && (ch != '\n'));
} else {
fprintf(stderr, "invalid input, real number expected\n");
exit(EXIT_FAILURE);
}
}
int main(void)
{
char name[50];
int n;
double price;
ReadInteger(&n);
for (int i = 0; i < n; i++) {
ReadLine(name, sizeof name);
ReadReal(&price);
printf("%s, %.2f\n", name, price);
}
return 0;
}
As chux said in the comments of this answer: "All scan specifiers, except %c, %[, %n consumes leading white-spaces." So you don't need to account for them.
scanf("%s%d",name,&price);
And looking at your input, you should use float or double for the price.
scanf("%s%lf",name,&price);
Note that this works only if items are made of one word. If they can be of two or more words, you'd better use fgets
EDIT: for items made of more words you should use fgets
fgets(name, 50, stdin);
scanf("%lf",&price);
Replace your for loop with this:
for (int i = 0; i < n; i++) {
scanf(" %[^\n]\n%d", name, &price);
printf("%s , %d\n", name, price);
}
The first space skips leading spaces, and the [^\n] allows you to get more than one word as string input.

ADD elements of an array with a given condition

There is an array of n students( stu[n]).If gender is boy then my code adds
for boy b, 2nd,4th,6th,........even position elements of array and
for girl g, 1st,3rd,5th....odd position elements of array.
1> Gender of boys denoted by b.
2> Gender of girls denoted by g.
Input info>>
The 1st line contains n, denoting the number of students in the class, hence the number of elements in the array.
Each of the subsequent lines contains the marks of n students .
The last line contains gender b/g;
Output info>>
The output should contain the sum of all the alternate elements of marks as explained above.
#include <stdio.h>
int main() {
int n,i;
scanf("%d",&n);//n denotes number of students.
int stu[n],sum=0;
for(i=1;i<=n;++i)
scanf("%d",&stu[i]);//for accepting input in array.
char gen;
scanf("%s",&gen);//for accepting input gender b/g.
for(i=1;i<=n;i++){
if(gen=='g' && i%2!=0){ //girl g adds alternate odd position elements.
sum=sum+stu[i];
printf("%d",sum);
}
else if(gen=='b' && i%2==0){ //boy b adds alternate even position elements.
sum=sum+stu[i];
printf("%d",sum);
}
}
//code
return 0;
}
Sample Input
3
3
2
5
b
Sample Output
8
explanation>>
marks=[3,2,5] and gender = b so it will add 3+5(even position 0,2 alternate elements). If gender in place of b is g then it will produce output = 2.
My code is shows output of 0 in all test cases.
You have the major problem in
int n,i;
int stu[n],sum=0;
here, n being a uninitialized local scoped variable with automatic storage, the initial value is indeterminate.
Now, since the address of the variable was never taken and it has a type that can have trap representation, attempt to use the value (int stu[n]) will invoke undefined behavior.
You need to scan in the value into n first, then use that to define the VLA stu. Something like
int n,i;
scanf("%d",&n);//n denotes number of students.
// **Note: please check for errors in input with scanf return value.**
int stu[n],sum=0; // here, n has the scanned value.
That said,
char gen;
scanf("%s",&gen);
is also horribly wrong, you want to scan in a char, not a string, and with the address of a plain char variable, %s conversion specification would be UB, again. You should use %c and discard any whitespaces which is present in buffer altogether.
You're making things more complicated than they need to be. Here is how you can possibly do:
#include <stdio.h>
int main(void)
{
int mark;
int b = 0;
int g = 0;
char students_marks[5];
for (int i=0; i<5; i++) {
scanf("%d", &mark);
students_marks[i] = mark;
}
for (int i=0; i<5; i++) {
if (i%2 == 0) b += students_marks[i];
if (i%2 == 1) g += students_marks[i];
}
printf("Boys: %d\nGirls: %d\n", b, g);
return 0;
}
You should probably not use an array, and just ignore the first data point. It is (probably) easier to use a linked list. Or maybe just use two lists, alternating the inputs between them. And I would definitely not use scanf. If you are new to C, do NOT waste your time learning the foibles of the scanf format string language. The only time scanf is ever useful is in introductory courses where instructors incorrectly believe that you will be able to get input more quickly than if you spend time learning other methods. But in fact you will end up burning more time learning when to use spaces in the format string that you saved by not learning fread. After your introduction to C, you will (almost) never use scanf. Also, it seems like a horrible design to put the discriminant at the end of the input. The values to be summed (the gender) should be given as a command line argument. That said, you could just do:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
FILE *
xfopen(const char *path, const char *mode)
{
FILE *rv;
if( (rv = fopen(path, mode)) == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return rv;
}
int
main(int argc, char **argv)
{
int i;
int size; /* Should probably be size_t. Skipping that for now. */
FILE *in = argc > 1 ? xfopen(argv[1], "r") : stdin;
int sum = 0;
if( fscanf(in, "%d", &size) != 1 || size <= 0 ) {
fprintf( stderr, "invalid input\n" );
exit(EXIT_FAILURE);
}
int grades[size];
for( i = 0; i < size; i++ ) {
if(fscanf(in, "%d", grades + i) != 1) {
fprintf( stderr, "invalid input on line %d\n", i );
exit(EXIT_FAILURE);
}
}
char gender;
if(fscanf(in, " %c", &gender) != 1) {
fprintf( stderr, "invalid input on line %d\n", i );
exit(EXIT_FAILURE);
}
if(strchr("bBgG", gender) == NULL) {
fprintf( stderr, "invalid gender: %c\n", gender);
exit(EXIT_FAILURE);
}
for( i = tolower(gender) == 'b'; i < size; i += 2 ) {
sum += grades[i];
}
printf("sum: %d\n", sum);
}
Hmm… i changed your code a Little bit and hope this runs as described.
int main() {
int n, index, sum=0;
int* stu;
scanf("%d", &n); // input number of studens
if(n>0)
stu = malloc(n*sizeof(int)); // allocate memory
else
return 0;
for(index=0;index<n;index++)
scanf("%d", &stu[index]);
char gen;
scanf("%c", &gen);
for(index=0; index<n; index++){
if(gen=='g' && index%2!=0) {
sum += stu[index];
printf("%d", sum);
} else if(gen=='b' && index%2==0) {
sum += stu[index];
printf("%d", sum);
}
}
return 0;
}

Newbie here. C function problem during execution

Edit: Since I understand that I need to provide more info to make it clear for you guys, I added the main function and the getchoice and also two images of the program running. My problem is that after entering the endword, I want to see the menu first and then make a choice, whereas it prompts me to give an input without showing the menu.
This function is part of a bigger program, but this is where a problem occurs.
It reads words inputed, places them into an array, until the keyword ****END is entered. However, when this keyword is entered, it doesn't go immediatelly in the specified if clause (you will see that in the code). I'm a newbie and it could be something really obvious, but any help is greatly appreciated.
#include <string.h>
#define M 50
#define N 15
void getText(char a[M][N])
{
int i, j;
char temp[N];
for (i = 0; i < 50; i++) {
for (j = 0; j < 15; j++) {
if (i == 49 && j == 14) {
printf("Maximum length of text reached.\n");
}
scanf("%s\n", temp);
if (strcmp(temp, "****END") == 0) {
printf("You entered the endkey.\n");
return;
}
strcpy(a[i], temp);
}
}
}
int main(){
int input;
while(1){
input = getChoice();
if(input == 1){
getText(text);
}
else if(input == 2){
getDictionary();
}
else if(input == 3){
correctText();
}
else if(input == 4){
saveText();
}
else if(input == 5){
getStats();
}
else if(input == 6){
break;
}
}
return 0;
}
int getChoice(){
int temp;
printf("Choose function:\n1: Enter text\n2: Enter dictionary\n3: Correct text\n4: Save text\n5: Get text statistics\n6: Exit program\n");
scanf("%d", &temp);
return temp;
}
Entered the endword and now it waits for input instead of showing the menu.
I inputed 2 for the second program function, then it showed the menu and proceeded to function 2.
Apart from the unnecessary double-nested loop, this line
scanf("%s\n", temp);
should be
scanf("%s", temp);
Usually, you should not try to match trailing whitespace with scanf, and the format specifier %s automatically filters out leading whitespace (but note that %c does not).
There are other faults and the code presented was originally incomplete, but notably the input length for %s must be restricted to prevent buffer overflow.
#include <stddef.h> // size_t
#include <ctype.h> // isspace()
#include <stdio.h> // scanf(), puts()
#include <string.h> // strcmp()
// see https://stackoverflow.com/questions/2653214/stringification-of-a-macro-value
#define STRINGIFY(x) #x
#define STRING(x) STRINGIFY(x)
#define LINES 50
#define COLS 15
char const *end = "****END";
// throw away everything until a newline is found
void clear(FILE *stream)
{
int ch;
while ((ch = getc(stream)) != EOF && ch != '\n');
}
size_t getText(char dst[LINES][COLS + 1])
{
size_t i = 0;
for (; i < LINES; i++) {
char temp[COLS + 1] = { 0 };
scanf("%" STRING(COLS) "s", temp); // "%15s" at runtime.
int ch;
// if the next character is not whitespace ...
if ((ch = getchar()) != EOF && !isspace(ch)) {
puts("Warning: Input too long, was truncated!");
clear(stdin);
}
if (strcmp(temp, end) == 0) {
puts("You entered the endkey.");
return i;
}
strcpy(dst[i], temp);
}
return i;
}
int main(void)
{
// COLS + 1 ... we need space for the terminating newline character.
char foo[LINES][COLS + 1];
size_t n = getText(foo);
for (size_t i = 0; i < n; ++i)
puts(foo[i]);
}
The %s conversion specifier should never be used without specifying a width to limit the characters that get stored:
char foo[10];
scanf("%9s");

Input to array of strings won't show?

I'm in C and I'm supposed to have an input of numbers (don't know how many) formatted into one column without storing them into an array of integers. I can't figure out why my code won't read the input and out put it. Please help.
#include <stdio.h>
#include <stdlib.h>
int main() {
int i;
char *nums[400];
for (i=0; i<nums; i++) {
scanf(nums[i]);
printf( "%.*s", 3, nums[i] );
}
return 0;
}
You have an array of 400 pointers, but you've never initialized them. Instead, you could declare a 2-dimension array:
char nums[400][4];
Then you're trying to use nums as a limit to the for loop. What you actually want is the number of elements in nums, which is sizeof(nums)/sizeof(nums[0]); or you could define a macro that specifies the size of the array.
Next, you left out the format string argument to scanf().
#include <stdio.h>
#include <stdlib.h>
#declare SIZE 400
int main()
{
int i;
char *nums[SIZE][4];
for(i=0; i<SIZE; i++){
scanf("%3s", nums[i]);
printf( "%.*s", 3, nums[i] );
}
return 0;
}
As Baramar correctly and thoroughly explained your main problems, I think I might have a different understanding of your problem. You want a given string of number, e.g.: 2134567896543245678 and print it out in a single column, neatly formated in rows of three digits each like that:
213
456
789
654
324
567
8
without an intermittent array of integers.
That could be done like e.g.: this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 512
int main()
{
int res;
// for the scanf input, set all to '\0'
char buffer[BUFFER_SIZE + 1] = { '\0' }, *idx;
size_t len, i;
// restrict max-size to BUFFER_SIZE
res = scanf("%512s", buffer);
if (res != 1) {
exit(EXIT_FAILURE);
} else {
if (strcmp(buffer, "exit") == 0) {
exit(EXIT_SUCCESS);
}
// TODO: check if the buffer contains all digits
len = strlen(buffer);
idx = buffer;
for (i = len; i >= 3; i -= 3, idx += 3) {
printf("%.3s\n", idx);
}
// last entries, if any
if (*idx != '\0') {
printf("%s\n", idx);
}
}
exit(EXIT_SUCCESS);
}
If you get actual integers in a row like e.g.: 12 3123 23478 34 5456 567456 567 678 you can use something like that:
EDIT
After the comment by the OP to use floating points I changed the code to accept input of the form:
24722.319352 51433.662233
56087.991042 49357.684934 67875.375848 68421.563197
54521.615295
22744.470483
38097.001461 80878.250982
92131.575748 7217.137271
20750.671365 7620.695008 37118.391541 28655.609469 46885.110202 87114.202312
46462.577299
20557.716648
And the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 400
int main()
{
int res;
int i = 0, m;
// input and two temporary variables
double in, in1, in2;
for (m = 0; m < MAXNUM; m++) {
res = scanf("%lf", &in);
if (res != 1) {
break;
} else {
switch (i) {
case 0:
// set value of first temporary variable to input
in1 = in;
// increment indicator indicating position in output row
i++;
break;
case 1:
in2 = in;
i++;
break;
case 2:
// print the three numbers and a newline
fprintf(stdout, "%f %f %f\n", in1, in2, in);
// reset counter
i = 0;
break;
}
}
}
// if there are still numbers, print them
if (i != 0) {
if (i == 1) {
fprintf(stdout, "%f\n", in1);
} else {
fprintf(stdout, "%f %f\n", in1, in2);
}
}
exit(EXIT_SUCCESS);
}
Try it out with
$ gcc-4.9 -O3 -g3 -W -Wall -Wextra -std=c11 sc.c -o sc
$ ./sc < floatin
24722.319352 51433.662233 56087.991042
49357.684934 67875.375848 68421.563197
54521.615295 22744.470483 38097.001461
80878.250982 92131.575748 7217.137271
20750.671365 7620.695008 37118.391541
28655.609469 46885.110202 87114.202312
46462.577299 20557.716648
If you enter less than 400 entries you need to end with EOF which can be triggered in most Unix shells with ctrl+d or set an entry to end the entries like e.g.: -1 if all you have is positive numbers and check for it to break out of the loop. If you submit a file like in the example above it works automatically.

The difference between fgets() and scanf()

This is my code. I didnt want to use scanf() to read the name and I tried using fgets() but after I put the first name and age, the second and third time my program runs the for loop it doesnt take age .
#include <stdio.h>
#include <string.h>
struct student
{
char name[15];
int age;
};
int main()
{
int i;
struct student s[A];
for (i = 0 ; i < A ; i++)
{
printf("enter the names and age\n");
fgets(s[i].name, 10, stdin);
scanf("%d", &s[i].age);
}
printf("\n\n");
for (i = 0 ; i < A ; i++)
{
printf("%s\t%d\n", s[i].name, s[i].age);
}
return 0;
}
It doesnt work, why?
But when I replace fgets with
scanf("%s%d",s[i].name,&s[i].age);
It works fine
The difference between fgets() and scanf()
fgets(...) typically reads until receiving a '\n'
scanf("%d", ...) typically:
1. Reads and discards leading white-space.
2. Reads numeric input (sign,digits) until scanning a non-digit.
3. Non-digit is put back into stdin for the next input function.
Example:
JohnEnter
"John\n" is read by fgets() into s[0].name.
21Enter
21 is read by scanf("%d",...) into s[0].age. '\n' put back into stdin
"\n" is read by fgets() into s[1].name.
M
"M" is read by scanf("%d",...), nothing is put in s[1].age. 'M' put back into stdin.
aryEnter
"Mary\n" is read by fgets() into s[2].name.
19Enter
19 is read by scanf("%d",...) into s[2].age. '\n' put back into stdin
"\n" is read by fgets() into s[3].name.
Alternative: To read 2 lines, call fgets() twice, then parse:
int Scan_student(struct student *dest) {
char buffer[2][80];
dest->name[0] = '\0';
dest->age[0] = -1;
printf("enter the names and age\n");
for (int i=0; i<2; i++) {
if (fgets(buffer[i], sizeof buffer[i], stdin) == NULL) {
return EOF; // stdin was closed, no more input (or input error)
}
buffer[i][strcspn(buffer[i], "\r\n")] = '\0'; // lop off potential trailing \n
}
// parse the 2 buffers: MANY options here - something simple for now.
if (sscanf(buffer[0], " %14[-'A-Za-z ]", dest->name) != 1) {
return 0;
}
if (sscanf(buffer[1], "%d", &dest->age) != 1) {
return 0;
}
return 1;
}
int i;
struct student st[3];
for (i = 0 ; i < sizeof(st) / sizeof(st[0]) ; i++) {
if (Scan_student(&st[i]) != 1) break;
}
If you input both the name and the age in a single line, then that's the normal behavior because fgets() will read the whole line until 9 bytes (in your case) are read or a '\n' is found.
You need one of the two, for instance you could only use fgets() like this
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[100];
int age;
};
int main()
{
int i;
struct student s[1];
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
{
char number[100];
char *unconverted;
printf("Name > ");
fgets(s[i].name, sizeof(s[i].name), stdin);
if ((unconverted = strchr(s[i].name, '\n')) != NULL)
*unconverted = '\0'; // Remove the trailing '\n'
printf("Age > ");
fgets(number, sizeof(number), stdin);
s[i].age = strtol(number, &unconverted, 10);
if ((*unconverted != '\0') && (*unconverted != '\n'))
s[i].age = -1; // Invalid value indicating input error
}
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
printf("Name: %s\nAge : %d\n", s[i].name, s[i].age);
return 0;
}
Or scanf() only
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[100];
int age;
};
int main()
{
int i;
struct student s[1];
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
{
printf("Name Age > ");
if (scanf("%99s%d", s[i].name, &s[i].age) != 2)
{
fprintf(stderr, "input error\n");
s[i].name[0] = '\0';
s[i].age = -1;
}
}
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
printf("Name: %s\nAge : %d\n", s[i].name, s[i].age);
return 0;
}
and you can then input both name and age in a single line.
The fgets() method is better because you don't need to deal with the '\n' that scanf() doesn't pick up from stdin. A combination would work if you are careful to force the user to input the values in separate lines.
To be honest fgets() isn't required here as you've specified to read from stdin you should simply use gets() this reads from stdin by default. If your moving between a scanf() statement and a gets() statement you should use fflush(stdin) to clear out the input stream, example below:
scanf("%99s", s[i].name);
fflush(stdin);
gets(s[i].age);
In general your better sticking with either scanf() or gets() and not combining them.

Resources