Why is there no output at the end? [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed yesterday.
The community is reviewing whether to reopen this question as of 19 hours ago.
Improve this question
Here is a part of the program:
17 #include<stdio.h>
18
19 struct Student
20 {
21 int number;
22 char name[15];
23 }student1,student2,student3,student4;
24
25 void input_name();
26
27 void input_name()
28 {
29 int h,i,j,k;
30 printf("********************************\n");
31 printf("* Enter student information *\n");
32 printf("********************************\n");
33 printf("Please enter the student number of the first student: ");
34 scanf("%d",&student1.number);
35 printf("Please enter the first student's name: ");
36 while(1)
37 {
38 for(h=0;h<15;h++)
39 {
40 scanf("%c",&student1.name[h]);
41 if(student1.name[h]==13)
42 {
43 student1.name[h]='\0';
44 break;
45 }
46 }
47 }
48 printf("Please enter the student number of the second student: \n");
49 scanf("%d",&student2.number);
50 printf("Please enter the second student's name: \n");
51 while(1)
52 {
53 for(i=0;i<15;i++)
54 {
55 scanf("%c",&student2.name[i]);
56 if(student2.name[i]==13)
57 {
58 student2.name[i]='\0';
59 break;
60 }
61 }
62 }
Lines 33 to 47 can be executed, but lines 48 to 62 can't be executed. When I press the Enter key, I keep breaking lines. So, I want to ask why the latter part can't be implemented, and which link in the middle has a problem?

The first loop (lines 36-47) has the following problems:
You are not taking into account that line 34 left a newline character on the input stream, so the first character read in line 40 will be this leftover newline character. It is also possible that other characters were left on the input stream. For example, if the user entered 6abc on line 34, then scanf on line 34 will only consume the 6, but leave abc\n on the input stream.
The break statement will only break out of the innermost loop, but not the outer loop.
If the user enters at least 15 characters (not including the newline character), then the string you write will not be null-terminated and your program will not consume all characters of the line of user input.
The second loop (lines 51-62) has the same problems.
In order to solve issue #1, you should discard the remainder of the line, including the newline character, for example like this:
//discard all leftover characters up to the newline character
scanf( "%*[^\n]" );
//discard the newline character itself
scanf( "%*c" );
Or like this:
int c;
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
To solve issue #2, you should remove the outer while(1) loop.
To solve issue #3, you should exit the program with an error message, instead of continuing the program.
Here is the fixed code:
#include <stdio.h>
#include <stdlib.h>
struct Student
{
int number;
char name[15];
} student1, student2, student3, student4;
int main( void )
{
printf( "********************************\n" );
printf( "* Enter student information *\n" );
printf( "********************************\n" );
//first student
printf( "Please enter the student number of the first student: " );
scanf( "%d", &student1.number );
//discard remainder of line
scanf( "%*[^\n]" );
scanf( "%*c" );
printf( "Please enter the first student's name: " );
for( int h = 0; ; h++ )
{
if ( h == 15 )
{
printf( "Input is too long for input buffer!\n" );
exit( EXIT_FAILURE );
}
scanf( "%c", &student1.name[h] );
if( student1.name[h] == '\n' )
{
student1.name[h] = '\0';
break;
}
}
//second student
printf( "Please enter the student number of the second student: " );
scanf( "%d", &student2.number );
//discard remainder of line
scanf( "%*[^\n]" );
scanf( "%*c" );
printf( "Please enter the second student's name: " );
for( int h = 0; ; h++ )
{
if ( h == 15 )
{
printf( "Input is too long for input buffer!\n" );
exit( EXIT_FAILURE );
}
scanf( "%c", &student2.name[h] );
if( student2.name[h] == '\n' )
{
student2.name[h] = '\0';
break;
}
}
//print back the information
printf( "\nYou entered the following information:\n\n" );
printf( "Student 1:\n" );
printf( "Number: %d\n", student1.number );
printf( "Name: %s\n", student1.name );
printf( "\n" );
printf( "Student 2:\n" );
printf( "Number: %d\n", student2.number );
printf( "Name: %s\n", student2.name );
printf( "\n" );
}
This program has the following behavior:
********************************
* Enter student information *
********************************
Please enter the student number of the first student: 67
Please enter the first student's name: Mike
Please enter the student number of the second student: 78
Please enter the second student's name: Jimmy
You entered the following information:
Student 1:
Number: 67
Name: Mike
Student 2:
Number: 78
Name: Jimmy
Note however that your code has a lot of code duplication, and it will get worse if you add the code for the third and fourth students. Therefore, it would be better to handle all students in a loop, by creating an additional outer loop:
#include <stdio.h>
#include <stdlib.h>
#define NUM_STUDENTS 4
#define MAX_NAME_LENGTH 15
struct Student
{
int number;
char name[MAX_NAME_LENGTH];
};
int main( void )
{
struct Student students[NUM_STUDENTS];
static const char *numeral_adjectives[] =
{
"zeroth", "first", "second", "third", "fourth",
"fifth", "sixth", "seventh", "eighth", "ninth"
};
printf( "********************************\n" );
printf( "* Enter student information *\n" );
printf( "********************************\n" );
for ( int i = 0; i < NUM_STUDENTS; i++ )
{
printf(
"Please enter the student number of the %s student: ",
numeral_adjectives[i+1]
);
scanf( "%d", &students[i].number );
//discard remainder of line
scanf( "%*[^\n]" );
scanf( "%*c" );
printf(
"Please enter the %s student's name: ",
numeral_adjectives[i+1]
);
for( int j = 0; ; j++ )
{
if ( j == MAX_NAME_LENGTH )
{
printf( "Input is too long for input buffer!\n" );
exit( EXIT_FAILURE );
}
scanf( "%c", &students[i].name[j] );
if( students[i].name[j] == '\n' )
{
students[i].name[j] = '\0';
break;
}
}
}
//print back the information
printf( "\nYou entered the following information:\n\n" );
for ( int i = 0; i < NUM_STUDENTS; i++ )
{
printf( "Student %d:\n", i+1 );
printf( "Number: %d\n", students[i].number );
printf( "Name: %s\n", students[i].name );
printf( "\n" );
}
}
This program has the following behavior:
********************************
* Enter student information *
********************************
Please enter the student number of the first student: 67
Please enter the first student's name: Mike
Please enter the student number of the second student: 78
Please enter the first student's name: Jimmy
Please enter the student number of the third student: 105
Please enter the first student's name: Jane
Please enter the student number of the fourth student: 112
Please enter the first student's name: Bob
You entered the following information:
Student 1:
Number: 67
Name: Mike
Student 2:
Number: 78
Name: Jimmy
Student 3:
Number: 105
Name: Jane
Student 4:
Number: 112
Name: Bob
Note that when dealing with line-based user input, it is generally better to use fgets instead of scanf. In contrast to scanf, fgets will always read an entire line at once, unless it is unable to do so, due to the size of the supplied memory buffer not being large enough.
That way, you won't have the problem of scanf reading partial lines whose leftovers you must discard.
Here is an example program which uses fgets instead of scanf:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_STUDENTS 4
#define MAX_NAME_LENGTH 15
struct Student
{
int number;
char name[MAX_NAME_LENGTH];
};
int main( void )
{
struct Student students[NUM_STUDENTS];
static const char *numeral_adjectives[] =
{
"zeroth", "first", "second", "third", "fourth",
"fifth", "sixth", "seventh", "eighth", "ninth"
};
printf( "********************************\n" );
printf( "* Enter student information *\n" );
printf( "********************************\n" );
for ( int i = 0; i < NUM_STUDENTS; i++ )
{
char input[200];
char *p;
//prompt user for student's number
printf(
"Please enter the student number of the %s student: ",
numeral_adjectives[i+1]
);
//read exactly one line of input
fgets( input, sizeof input, stdin );
//convert input string to a number
students[i].number = strtol( input, NULL, 10 );
//prompt user for student's name
printf(
"Please enter the %s student's name: ",
numeral_adjectives[i+1]
);
//attempt to read exactly one line of input
fgets( students[i].name, sizeof students[i].name, stdin );
//attempt to find newline character in input
p = strchr( students[i].name, '\n' );
//verify that the newline character is present,
//because otherwise, we must assume that the input
//was too long to fit into the memory buffer
if ( p == NULL )
{
printf( "Input is too long for input buffer!\n" );
exit( EXIT_FAILURE );
}
//remove the newline character by overwriting it
//with a null character
*p = '\0';
}
//print back the information
printf( "\nYou entered the following information:\n\n" );
for ( int i = 0; i < NUM_STUDENTS; i++ )
{
printf( "Student %d:\n", i+1 );
printf( "Number: %d\n", students[i].number );
printf( "Name: %s\n", students[i].name );
printf( "\n" );
}
}

It seems that the code you provided is missing the closing curly brace for the input_name function, but based on the code you provided, the issue with the second input loop (lines 51-62) is that it goes into an infinite loop waiting for input.
The reason for the infinite loop is that the scanf function in line 49 reads the integer input for the student's number, but it leaves the newline character (\n) in the input buffer. Then, when the loop in lines 51-62 starts, the first scanf call in line 55 immediately reads the newline character, which is not a valid character for the student's name, and the loop continues indefinitely.
To fix this, you can add a space before the %d format specifier in line 49, which will consume any remaining whitespace characters in the input buffer before reading the integer. You can do the same for the scanf call in line 55 before reading the character for the name. Here's the modified code:
48 printf("请输入第二个学生的学号:\n");
49 scanf("%d", &student2.number);
50 printf("请输入第二个学生的姓名:\n");
51 while (1)
52 {
53 int nameComplete = 0; // add flag variable
54 for (i = 0; i < 15; i++)
55 {
56 scanf(" %c", &student2.name[i]);
57 if (student2.name[i] == 13)
58 {
59 student2.name[i] = '\0';
60 nameComplete = 1; // set flag when name is complete
61 break;
62 }
}
if (nameComplete) break; // break out of both loops
}
With these changes, the program should be able to read the student information for both students and continue executing the rest of the code.

Related

Why does the number 10 get output in each iteration and how can I fix this?

I have a for loop, which I want to get the input from the user and print the associated ascii value. But it only asks for the user input in the second iteration, which is followed and preceded by the output 10. I tried to get rid of new-line characters, but it still prints out 10.
#include <stdio.h>
int main(void){
int number;
printf("Enter the number:");
scanf("%i", &number);
for( ; number > 0; number--){
char character;
printf("Give a char: \n");
scanf("%c", &character);
printf("The associated ascii value is %i \n", character);
}
return 0;
}
Maybe simpler (though using scanf() for user input is not recommended)
scanf(" %c", &character);
// ^ skip otional leading whitespace
Your whole program using fgets() for user input (and my indentation, spacing, style; sorry)
#include <stdio.h> // printf(), fgets()
#include <stdlib.h> // strtol()
int main(void) {
int number;
char buffer[100]; // space enough
printf("Enter the number:");
fgets(buffer, sizeof buffer, stdin);
number = strtol(buffer, 0, 10); // error checking missing
for (; number > 0; number--) {
printf("Give a char: ");
fgets(buffer, sizeof buffer, stdin); // reuse buffer, error checking missing
if (buffer[0] != '\n') {
printf("The associated ascii value of '%c' is %i.\n", *buffer, *buffer);
}
}
return 0;
}
This should solve your problem. getchar() will read the extra newline character from buffer.
#include <stdio.h>
int main(void){
int number;
printf("Enter the number:");
scanf("%i", &number);
for( ; number > 0; number--){
char character;
printf("Give a char: ");
getchar();
scanf("%c", &character);
printf("The associated ascii value is %i \n", character);
}
return 0;
}
regarding;
scanf("%c", &character);
the first time through the loop the '\n' is input.
on all following passes through the loop, the scanf() fails, so the value in character does not change.
This is a prime example of why your code should be error checking.
for instance, to error check the call to scanf():
if( scanf("%c", &character) != 1 )
{
fprintf( stderr, "scanf for a character failed\n" );
break;
}
the 1 is because the scanf() family of functions returns the number of successful: input format conversion specifiers or EOF and it is best to assure the 'positive' status.

How do I convert this goto loop in a while loop?

I have a program that prompts the user to input three float numbers and if those numbers are not positive or not digits it prints out "Invalid number" This is the part of the program done with goto loops and I'd like to get rid of it.
float array[n][3];
int i;
for(i = 0;i<n;i++){
one:
printf( "Please enter first number: ");
scanf("%f", &array[i][0]);
while(array[i][0]<0){
printf("Invalid number: ");
goto one;
}
two:
printf("Please enter second number: ");
scanf("%f", &array[i][1]);
while(array[i][1]<0){
printf("Invalid number: ");
goto two;
}
three:
printf("Please enter third number: ");
scanf("%f", &array[i][2]);
while(array[i][1]<0){
printf("Invalid number: ");
goto three;
}
}
How do I convert loops goto one, goto two and goto three; in a while loop, or some kind of a loop?
See my changes. I modified not only the goto case:
double array[n][3];
int i, j;
char * fst[] = { "first", "second", "third" };
for( i = 0; i < n; i++ )
{
for ( j = 0; j < 3; j++ )
{
while ( 1 )
{
printf( "Please enter %s number: ", fst[j] );
scanf( "%lf", &array[i][j] );
if ( array[i][j] < 0 )
printf("Invalid number.\n");
else break;
}
}
}
Similar blocks are combined with a loop and array of words. double is better than float except in cases of very low RAM (embedded systems). goto is transformed to while loop and break. I suppose you say "invalid number" for negative numbers, not failed scanf. If the check is for failed scanf then it can be modified to if ( scanf( "%lf", &array[i][j] ) < 1 ) ....
You could convert it to do { ... } while(...);
Example:
one:
printf( "Please enter first number: ");
scanf("%f", &array[i][0]);
while(array[i][0]<0){
printf("Invalid number: ");
goto one;
}
To
do
{
printf ("Please enter first number: ");
scanf ("%f", &array[i][0]);
if (array[i][0] < 0)
{
printf ("Invalid number: ");
}
}
while (array[i][0] < 0);
Avoiding goto is generally a good idea (even though some acceptable uses of it exist). Other things to avoid:
Code repetition. (Dangerous)
Storing a value into your final data container before the value is valid. (Dangerous)
Iterating over the left-most dimension of a 2D array instead of the right-most one. (Inefficient)
One possible solution to fix all of the above:
#include <stdio.h>
float enter_float (size_t n)
{
const char* STR_NUMBER[] = { "first", "second", "third" };
float result;
printf("Please enter %s number: ", STR_NUMBER[n]);
scanf("%f", &result);
return result;
}
int main (void)
{
size_t n=3;
float array[n];
for(size_t i=0; i<n; i++)
{
float input;
while( (input = enter_float(i)) < 0.0f)
{
printf("Invalid number\n");
}
array[i] = input;
}
}
(Ideally, the code should also check the result of scanf and also make sure there's no buffer overrun by specifying how many items scanf should read.)
You could do like
for(i = 0;i<n;i++){
while(printf( "Please enter first number: ")>0 && scanf("%f", &array[i][0])==1 && array[i][0]<0 && printf("Invalid number: ") );
while(printf( "Please enter second number: ")>0 && scanf("%f", &array[i][1])==1 && array[i][1]<0 && printf("Invalid number: "));
while(printf( "Please enter third number: ")>0 && scanf("%f", &array[i][2])==1 && array[i][2]<0 && printf("Invalid number: ") );
}
Short circuit evaluation is taken advantage of here.
printf() will return the number of characters it printed which is greater than zero if it was successful.
If printf() was successful, scanf() is executed which returns the number of successful assignments. In this case, it should be 1 if it succeeded.
If both the printf() and scanf() succeeded and array[i][j] is less than zero, a printf() to display error message is done and the loop is repeated.
You could make those while loops like
while(printf( "Please enter third number: ")>0 && scanf("%f", &array[i][2])==1 && array[i][2]<0)
{
printf("Invalid number: ")
}
to make it more readable.
Edit:
If the input is not a valid number, scanf() won't read into the variable as the format specifier is %f.
This may cause problem as the invalid input will remain unconsumed in the input buffer. You need to clear your input buffer.
Something like
int ch;
while( (ch=getch())!=EOF && ch!='\n' );
maybe used to consume from input buffer till a newline. See here for more on this.
getchar() returns EOF on error. Note that getchar() returns an unsigned char converted to an int.
To include this, you may modify those while loops to be like
int ch;
while(printf( "Please enter third number: ")>0 && scanf("%f", &array[i][2])==1 && array[i][2]<0)
{
printf("Invalid number: ")
while( (ch=getch())!=EOF && ch!='\n' );
}

Loop using goto control statement, but it skips one command

I just learned C programming. Now, I am trying to perform looping
using the goto control statement, but I just faced a problem when I
use variable char.
#include <stdio.h>
char score;
int main(){
loop:
printf("Please Input Your Score : ");
scanf("%c", &score);
switch(score){
case 'A' :
printf("Nilai Anda Baik");
break;
default :
printf("Nilai Anda Salah");
goto loop;
}
return 0;
}
The problem is if I input the wrong score such as 'B', it will print "Nilai Anda Salah" and then automatically print again "Please Input Your Score: Nilai Anda Salah" one time. After that print again "Please Input Your Score: " and then I can input again the score.
I don't know why it is skipping the scanf command.
Use the following format specifier
scanf(" %c", &score);
^^^
to skip the new line characters between entered characters.
Also according to the C Standard function main without parameters shall be declared like
int main( void )
Take into account that it is a bad idea to use the goto statement. Also there is no need to declare the variable score as global.
The program can look the following way
#include <stdio.h>
int main(void)
{
char score = 'A';
do
{
printf( "Please Input Your Score : " );
scanf( " %c", &score );
switch( score )
{
case 'A' :
puts( "Nilai Anda Baik" );
break;
default :
puts( "Nilai Anda Salah" );
break;
}
} while ( score != 'A' );
return 0;
}

Creating GPA calculator in C code

I just wrote this code and I cannot get it to work - not to mention output the desired results. I am supposed to create a program that will calculate the GPA of an unknown amount of students (which I have narrowed down to a max of 25) with an unknown amount of classes respectively (also narrowed those down to a max of 10 to make my life easier).
Can anyone see what mistakes I have made and possibly push me in the right direction? I appreciate anyone's time and advice :)
My Code:
// C Program - GPA calculator for x amount of students with x amount of classes
// Program developer: Diana Wright - Novembet 22nd, 2014
#include <stdio.h>
int main(void) {
// Declare variables
int grade[5], g, class_num[9], c;
char name[24], n;
float GPA=0.0, grade_point=0.0, result=0.0;
// Input student names implying amount of students
for(n=0; n<25; n++) {
scanf(" %s", &name[n]);
printf("Please enter student names: %s.", name[n]);
// Input number of classes
for(c=0; c<10; c++) {
scanf(" %d", &class_num[c]);
printf("Please enter amount of classes (max.10): %d", class_num[c]);
// Input grades
for(g=0; g<=class_num; g++) {
scanf(" %d", &grade[g]);
printf("Please enter students' grades: %d.", grade[g]);
}
// Conversion of grades
if (grade == "A"){
grade_point = 4.0;
}
if (grade == "B"){
grade_point = 3.0;
}
if (grade == "C")
{
grade_point =2.0;
}
if (grade == "D"){
grade_point = 1.0;
}
if (grade == "F"){
grade_point = 0.0;
}
// Formula to calculate GPA
result += grade_point[g];
GPA = result/class_num[c];
}
}
// Print user input and results in a table
printf(“\n Student name \t Grades \t GPA”);
for(n=0; n<25; n++) {
printf(“ %s \t %d \t %f”, name[n], grade[g], GPA);
}
return 0;
}
My initial input:
Diana 3 A A A Edward 4 B C B A Stuart 4 A F C D Bert 2 F F
// the following implements the needed data set,
// corrects several coding errors
// has (not yet run) compiling code
EDIT: following code obsolete, see new code further down
#include <stdio.h>
#include <string.h>
struct studentGrade
{
char name[24];
char grades[10];
int class_num;
float GPA;
};
int main(void)
{
// Declare variables
struct studentGrade studentGrades[25] = {{"",{'F','F','F','F','F','F','F','F','F','F'},0,0.0F}};
int c; // index into student grades[]
int n; // student number/loop counter
float grade_point=0.0f, result=0.0f;
// Input student names implying amount of students
for(n=0; n< (sizeof( studentGrades)/sizeof(struct studentGrade)); n++)
{
result = 0.0f; // initialize for each student
printf( "please enter student name:\n ");
scanf(" %s", (char*)(studentGrades[n].name) );
printf("Student Name is: %s.", studentGrades[n].name);
printf("please enter student class count:\n");
scanf(" %d", &studentGrades[n].class_num);
printf("Student Number of classes: %d", studentGrades[n].class_num);
// Input class grades
for(c=0; c< 10; c++)
{
printf("please enter grade for class: %d", c);
scanf(" %c", &(studentGrades[n].grades[c]));
printf("student grade for class: %d is %c\n", c, studentGrades[n].grades[c]);
// following makes wild assumption that grade entered
// is 'A'...'F'
// Conversion of grades
grade_point = 0.0f; // init for each class
switch( studentGrades[n].grades[c] )
{
case 'A':
grade_point = 4.0f;
break;
case 'B':
grade_point = 3.0f;
break;
case 'C':
grade_point = 2.0f;
break;
case 'D':
grade_point = 1.0f;
break;
case 'F':
grade_point = 0.0f;
break;
default:
printf( "invalid grade entered\n");
c--; // so will properly handle loop control, etc
break;
} // end switch
result += grade_point;
// Formula to calculate GPA
result += grade_point;
} // end for each grade
studentGrades[n].GPA = result/(float)c;
} // end for each student
// Print user input and results in a table
printf("\n Student name \tGPS\n\t\tgrades\n");
for(n=0; n< (sizeof(studentGrades) / sizeof( struct studentGrade)); n++)
{
if( 0 != strlen(studentGrades[n].name) )
{
printf( " %s \tGPS: %.2f\n",
studentGrades[n].name,
studentGrades[n].GPA);
for( c=0; c< studentGrades[n].class_num; c++)
{
printf("\tclass: %d\t%c:\n", c, studentGrades[n].grades[c] );
}
}
}
return 0;
}
EDIT: New code:
cleanly compiles
properly checks for errors
uses #define statements to eliminate 'magic' numbers
cleans up the logic error of always trying to input 10 grades
allows both upper case and lower case grade entry
uses meaningful variable names
incorporates appropriate horizontal spacing for readability
and now the new code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STUDENTS 25
#define MAX_NAME_LEN 23
#define MAX_GRADES 10
#define STR_VALUE(x) STR(x)
#define STR(x) #x
struct studentGrade
{
char name[ MAX_NAME_LEN+1 ];
char grades[ MAX_GRADES ];
int class_num;
float GPA;
};
int main(void)
{
// Declare variables
struct studentGrade studentGrades[ MAX_STUDENTS ] =
{
{"",
{'F','F','F','F','F','F','F','F','F','F'}
,0,
0.0F
}
};
float result = 0.0f;
// Input student names implying amount of students
for( size_t whichStudent=0;
whichStudent < (sizeof( studentGrades)/sizeof(struct studentGrade));
whichStudent++)
{
result = 0.0f; // initialize for each student
printf( "please enter student name:\n ");
if( scanf(" %" STR_VALUE(MAX_NAME_LEN) "s",
studentGrades[ whichStudent ].name ) != 1 )
{
fprintf( stderr, "scanf for student name failed");
exit( EXIT_FAILURE );
}
// implied else, scanf for student name successful
printf("Student Name is: %s.",
studentGrades[ whichStudent ].name);
printf("please enter student class count:\n");
if( scanf(" %d", &studentGrades[ whichStudent ].class_num) != 1 )
{
fprintf( stderr, "scanf for student class count failed\n" );
exit( EXIT_FAILURE );
}
// implied else, scanf for student class count successful
printf("Student Number of classes: %d",
studentGrades[ whichStudent ].class_num);
// Input class grades
for( int whichClass=0;
whichClass < studentGrades[ whichStudent ].class_num;
whichClass++)
{
printf( "please enter grade for class: %d", whichClass );
if( scanf( " %c",
&(studentGrades[ whichStudent ].
grades[ whichClass ]) ) != 1)
{
fprintf( stderr,
"scanf for class grade %d failed\n",
whichClass );
exit( EXIT_FAILURE );
}
// implied else, scanf for class grade successful
printf( "student grade for class: %d is %d\n",
whichClass,
studentGrades[ whichStudent ].grades[ whichClass ] );
// following makes wild assumption that grade entered
// is 'A'...'F'
// Conversion of grades
float grade_point = 0.0f; // init for each class
switch( studentGrades[ whichStudent ].grades[ whichClass ] )
{
case 'A':
case 'a':
grade_point = 4.0f;
break;
case 'B':
case 'b':
grade_point = 3.0f;
break;
case 'C':
case 'c':
grade_point = 2.0f;
break;
case 'D':
case 'd':
grade_point = 1.0f;
break;
case 'F':
case 'f':
grade_point = 0.0f;
break;
default:
printf( "invalid grade entered\n");
whichClass--; // so will properly handle loop control, etc
break;
} // end switch
result += grade_point;
// Formula to calculate GPA
result += grade_point;
} // end for each grade
studentGrades[ whichStudent ].GPA =
result/(float)studentGrades[ whichStudent ].class_num;
} // end for each student
// Print user input and results in a table
printf( "\n Student name \tGPS\n\t\tgrades\n" );
for( size_t whichStudent=0;
whichStudent < (sizeof(studentGrades) / sizeof( struct studentGrade));
whichStudent++ )
{
if( 0 != strlen( studentGrades[ whichStudent ].name ) )
{
printf( " %s \tGPS: %.2f\n",
studentGrades[ whichStudent ].name,
studentGrades[ whichStudent ].GPA );
for( int whichClass=0;
whichClass < studentGrades[ whichStudent ].class_num;
whichClass++)
{
printf( "\tclass: %d\t%c:\n",
whichClass,
studentGrades[ whichStudent ].grades[ whichClass ] );
}
}
}
return 0;
}
Little rusty on this stuff, but I think there are a few strange things happening here that may not have been intended.
for(g=0; g<=class_num; g++)
Think we are looking for the inputted value that is stored at offset c, not the array.
for(c=0; c<10; c++)
I am not quite sure of the value of this loop. We should only have to get the number of classes once per student.
if (grade == "A")
Again, this didn't grab the right offset in the array. Do comparisons to char's need single quotes?
You are also going to have your print statements printing out a bunch... for example you might want to move this line outside the loop:
printf("Please enter students' grades: %d.", grade[g]);
So not to get on your case about anything whether this is or is not homework and to give credit to what laughingpine and Gopi have said already said...
There are some glaring errors in your code that will prevent you from compiling and running to have any effect. To start lets look at your declaration of variables:
// Declare variables
// You don't initialize any of your char or int non array and array variables.
int grade[5], g, class_num[9], c;
char name[24], n;
float GPA=0.0, grade_point=0.0, result=0.0; // You initialize your floating point variables.
When you initialize the compiler will designate an area of memory that these variables will reside in. If you don't then the compiler starts to make 'assumptions' on the variables you are using and will assign random memory locations to your variables. Next:
for (c = 0; c<10; c++) {
scanf(" %d", &class_num[c]); // You ask the user to enter one digit at a time for the class number
printf("Please enter amount of classes (max.10): %d", class_num[c]);
// Input grades
for (g = 0; g <= class_num; g++) // You try and make a comparison to a single variable int to an entire array which is not allowed.
{
scanf(" %d", &grade[g]);
printf("Please enter students' grades: %d.", grade[g]);
}
You cannot compare a single variable to an entire array, this line for (g = 0; g <= class_num; g++)will not compile. Another:
if (grade == "A"){
grade_point = 4.0;
}
You try to make a comparison from grade which is an int data type in your case to a string/character literal "A"which is not allowed...
result += grade_point[g]
Grade_point becomes an array here, when it was not defined this way before...
This looks like you rushed through the design process of your program. I recommend you sit down with a piece of paper and a pencil/pen and write out what it is you are trying to accomplish at each stage of asking the user for input. This will help in defining what variable data types you should be using in order to accomplish your tasks.

What is the best way to read a string?

So I'm really confused. I have to write a program in C which is basically an address book, thus I have to get multiple strings from the user (name, ID, phone etc.)
In the beginning I tried using scanf() only but it messed up sometimes with the newline character '\n'. After some googling, I ended up using scanf() for getting single chars or ints (where user answers yes or no questions, or chooses an action from a menu) and fgets() to read the fields of the address book. However, I also had to use fflush(stdin) multiple times after using scanf() which is not recommended here as I have seen. This method worked so far as intended.
So what's the optimal way to read a string from the user? Does fflush(stdin) not offer portability? This is an assignment so I have to think for portability too, since I will execute my code on another computer.
Thank you in advance.
EDIT: So here is what I've got so far. Excuse some words that are written in another language (Albanian). I believe you can understand what's going on.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void regjistrim();
void kerkim();
void modifikim();
void fshirje();
void rradhitje();
void display();
#define EMRI 50
#define MBIEMRI 50
#define ID 20
#define TEL 20
#define EMAIL 25
typedef struct addressbook
{
char emri[EMRI];
char mbiemri[MBIEMRI];
char id[ID];
char tel[TEL];
char email[EMAIL];
} addressbook;
FILE* Addressbook;
int main(void)
{
char input[2];
int choice;
printf("----------------ADDRESS BOOK----------------");
printf("\n\n\t1 - Regjistrimi i ri\n");
printf("\n\t2 - Kerkim\n");
printf("\n\t3 - Modifikim\n");
printf("\n\t4 - Fshirje\n");
printf("\n\t5 - Rradhitje\n");
printf("\n\t6 - Afishim i address book\n");
printf("\n\t0 - Exit\n");
fgets(input, 2, stdin);
sscanf(input, "%d", &choice);
while (choice < 0 || choice > 6)
{
printf("\nShtypni nje numer nga 0 - 6: \n");
fgets(input, 2, stdin);
sscanf(input, "%d", &choice);
}
switch (choice)
{
case 1:
regjistrim();
break;
case 2:
kerkim();
break;
case 3:
modifikim();
break;
case 4:
fshirje();
break;
case 5:
rradhitje();
break;
case 6:
display();
break;
case 0:
exit(0);
break;
}
return 0;
}
//Regjistron nje qytetar ne addressbook
void regjistrim()
{
char answer;
addressbook entry;
do
{
Addressbook = fopen("Addressbook.txt", "a+");
printf("\nShtypni emrin: ");
fgets(entry.emri, EMRI, stdin);
printf("\nShtypni mbiemrin: ");
fgets(entry.mbiemri, MBIEMRI, stdin);
printf("\nShtypni ID-in: ");
fgets(entry.id, ID, stdin);
printf("\nShtypni nr. telefoni: ");
fgets(entry.tel, TEL, stdin);
printf("\nShtypni email-in: ");
fgets(entry.email, EMAIL, stdin);
fprintf(Addressbook, "Emri: %sMbiemri: %sID: %sNr. telefoni: %sEmail: %s\n", entry.emri, entry.mbiemri, entry.id, entry.tel,entry.email);
fclose(Addressbook);
printf("\nShtypni y/Y neqoftese doni te regjistroni person tjeter: ");
fgets(answer, 1, stdin);
}
while(answer == 'y' || answer == 'Y');
}
With scanf, you can clear the newlines, like that. Also, I have included fgets too.
#include<stdio.h>
int main(void)
{
int i, N = 5;
char buffer[N];
printf("Enter %d characters\n", N+1);
scanf("%5s", buffer); /* MUST check comments below on this page for this! */
/* Clear trailing input */
while(getchar() != '\n')
/* discard */ ;
for(i = 0 ; i < 5 ; ++i)
printf("|%c|\n", buffer[i]);
printf("End with scanf\n\n");
/*****************************************************/
printf("Enter %d characters\n", N+1);
fgets(buffer, 5, stdin);
for(i = 0 ; i < 5 ; ++i)
printf("|%c|\n", buffer[i]);
printf("End with fgets\n\n");
return 0;
}
Also, this code demonstrates the limit you can put to every function for the input.
Source
Well "optimal" is maybe a bit subjective but I found
doing a separate function to read the number makes things
a bit easier and avoid scanf if you don't absolutely need it e.g.
int readNumber(int min, int max)
{
char number[32];
do
{
if ( fgets( number, sizeof(number), stdin ) != NULL )
{
// note that if 'number' is not a number atoi returns 0
int n = atoi(number);
if ( n>= min && n <= max )
{
return n;
}
}
printf( "please enter a valid value between %d and %d\n", min, max );
}
while ( 1 );
return -1; // never reached
}

Resources