I am writing the following program for my Programming Fundamentals Class (C Programming). My IDE is giving me a compile error for the declaration of 'student' as referenced in the lines where user input is read. It is also giving me an error on ISO C standards for nested functions in the letter_grade function. Any help would greatly be appreciated.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define MAX 20
char letter_grade(float a, float b, float c);
int main(void)
{
char temp_name[MAX];
int count=0, last, temp;
struct student {
char f_name[MAX];
char l_name[MAX];
float test1;
float test2;
float test3;
};
printf("Please enter the student's last name (Enter ZZZ to exit): ");
gets(temp_name);
while (strncmp(temp_name, "ZZZ\0", 4))
{
strncpy(student[count].l_name, temp_name, MAX+1);
printf("Please enter the students first name: ");
scanf("%s", &student[count].f_name);
getchar();
printf("Enter the first test score: ");
scanf("%f", &student[count].test1);
printf("Enter the second test score: ");
scanf("%f", &student[count].test2);
printf("Enter the third test score: ");
scanf("%f", &student[count].test3);
printf("\nPlease enter the student's last name (Enter ZZZ to exit): ");
gets(temp_name);
count++;
}
last = count;
temp = last + 1;
printf("\t\t\tStudent Grade Report");
for (last;last>=0;last--){
printf("%s, ", student[last].l_name);
printf("%s ", student[last].f_name);
printf("\t\t Grade: %c\n\n ", letter_grade(student[last].test1, student[last].test2, student[last].test2));
// printf("Test Grade: %c\n", letter_grade(85,88,82));
return 0;
}
char letter_grade(float *a, float *b, float *c)
{
float sum = *a+*b+*c;
if (sum >= 270.0f)
return 'A';
if (sum>= 240.0f && sum <270.0f)
return 'B';
if (sum>= 210.0f && sum <240.0f)
return 'C';
if (sum>= 180.0f && sum <210.0f)
return 'D';
if (sum < 180.0f)
return 'F';
}
You nowhere declared an array or a pointer with name student. The name was not declared. Thus the code where you are refering the name like this statement
strncpy(student[count].l_name, temp_name, MAX+1);
^^^^^^^
is invalid.
What is "student"? Where is it declared?
You only declared type struct student but it is not the same as an object with name student.
Also in this loop
for (last;last>=0;last--){
printf("%s, ", student[last].l_name);
printf("%s ", student[last].f_name);
printf("\t\t Grade: %c\n\n ", letter_grade(student[last].test1, student[last].test2, student[last].test2));
there is absent the closing brace.
Applying all the comments and correcting other problems in the posted code there were many results in:
#include <stdio.h>
#include <string.h>
#define MAX_NAME_LEN (20)
#define MAX_STUDENTS (100)
// define the student struc
struct student
{
char f_name[ MAX_NAME_LEN ];
char l_name[ MAX_NAME_LEN ];
float test1;
float test2;
float test3;
};
char letter_grade(float a, float b, float c);
int main(void)
{
// define an array of 100 instances of the student struct
struct student students[ MAX_STUDENTS ];
printf("Please enter the student's last name (Enter ZZZ to exit): ");
int count=0;
while( count < MAX_STUDENTS && scanf( " %19s", students[count].l_name) && strcmp( students[count].l_name, "ZZZ" ) )
{
printf("Please enter the students first name: ");
scanf(" %19s", students[count].f_name);
printf("Enter the first test score: ");
scanf("%f", &students[count].test1);
printf("Enter the second test score: ");
scanf("%f", &students[count].test2);
printf("Enter the third test score: ");
scanf("%f", &students[count].test3);
count++;
printf("\nPlease enter the student's last name (Enter ZZZ to exit): ");
} // end while
printf("\t\t\tStudent Grade Report");
for ( ; count>=0; count--)
{
printf("%s, ", students[count].l_name);
printf("%s ", students[count].f_name);
printf("\t\t Grade: %c\n\n ",
letter_grade( students[count].test1,
students[count].test2,
students[count].test2));
} // end for
} // end function: main
char letter_grade(float a, float b, float c)
{
float sum = a+b+c;
char grade;
if( sum >= 270.f) grade = 'A';
else if (sum>= 240.0f) grade = 'B';
else if (sum>= 210.0f) grade = 'C';
else if (sum>= 180.0f) grade = 'D';
else grade = 'F';
return grade;
} // end function: letter_grade
You can compare the posted code to the above answer to spot where there were problems in the posted code.
Do not #include header files those contents are not used.
A passed value to a function does not become a pointer in the parameter list of the called function.
In any if then else sequence, there is no need to re-test for previously eliminated values
The posted code nested one function inside another, That is not valid C code, although can be allowed with the gcc compiler extension.
There is no need for a return statement from main() if the returned value is 0.
On any non void function, ALL paths through the code must lead to a return value; statement.
The posted code failed to declare any instance of the struct student structure. And certainly did not declare an array of those struct instances, as is needed when multiple students being processed.
The posted code (and this answer) will fail if any first or last name is greater than or equal to 20 characters.
This answer does not check for failures of the call to scanf() but for reliability, such checking for each must be performed. Similar to:
if( 1 != scanf( " %19s", students[count].l_name) )
{
perror( "scanf failed" );
exit( EXIT_FAILURE ); // `exit()` and `EXIT_FAILURE` found in stdlib.h
}
// implied else, scanf successful
The while() statement in the main() function is very 'busy' for clarity, the call to strcmp() could be extracted and placed in a following statement similar to:
while(...)
{
if( !strcmp( students[count].l_name, "ZZZ" ) {
{
break;
}
...
In general, never trust the input from a user. That is why the returned value (not the parameter value) from each call to scanf() needs to be checked.
As a simplification, rather than hardcoding the MAX LENGTH modifier in the calls to scanf() with a %s format specifier, can use the following changes:
#define MAX_NAME_LEN (19)
...
struct student
{
char f_name[ MAX_NAME_LEN+1 ];
char l_name[ MAX_NAME_LEN+1 ];
float test1;
float test2;
float test3;
};
....
&& scanf(" %" MAX_NAME_LEN "s", students[count].l_name) &&
....
scanf(" %" NAX_NAME_LEN "s", students[count].f_name);
Related
This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 1 year ago.
I have written a program which makes use of array of structures in order to maintain a sort of "database" program with different options that can be used to manipulate the "database".
The program has 4 modes of operation, if the user enters:
'i' data can be inserted into the "database".
's' searches the "database" for a part with a part number of a item.
'u' updates something in the database based on the part number of a item.
'p' prints the whole "database".
Here is the code which is made of 3 files:
database.h:
#ifndef DATABASE
#define DATABASE
struct db
{
int part_number;
char *part_name;
int part_quantity;
};
extern struct db database[50];
extern void insert(int i);
extern int search(int i);
extern int update(int i);
extern int print(int i);
#endif
database.c
#include <string.h>
#include <stdio.h>
#include "database.h"
struct db database[50];
void insert(int i)
{
char name_of_part[21], c;
printf("%p\n", &database[i].part_name);
printf("\n");
printf("Enter a part number: ");
scanf("%d", &database[i].part_number);
while((c = getchar()) != '\n' && c != EOF); // flush stdin
printf("Enter a part name: ");
fgets(name_of_part, 20, stdin);
printf("Enter quantity of part: ");
scanf("%d", &database[i].part_quantity);
database[i].part_name = name_of_part;
printf("\n");
}
int search(int i)
{
int input;
printf("\n");
printf("Enter a part number: ");
scanf("%d", &input);
for (int j = 0; j <= i; j++)
{
if (database[j].part_number == input)
{
printf("Part name: %s\n", database[j].part_name);
printf("Quantity on hand: %d\n", database[j].part_quantity);
return 0;
}
}
printf("Part not found.\n");
}
int update(int i)
{
int input, quantity;
printf("\n");
printf("Enter part number: ");
scanf("%d", &input);
for (int j = 0; j <= i; j++)
{
if (database[j].part_number == input)
{
printf("Enter part quantity: ");
scanf("%d", &quantity);
database[j].part_quantity = quantity;
return 0;
}
}
printf("Part number not found.");
}
int print(int i)
{
for (int j = 0; j < i; j++)
{
printf("Part number: %d\n Part name: %s\n Part quantity: %d\n", database[j].part_number, database[j].part_name,database[j].part_quantity);
}
}
main.c
#include <stdio.h>
#include <string.h>
#include "database.h"
int main()
{
int i = 0;
char code;
while (1)
{
printf("Enter a function code: ");
scanf(" %c", &code);
switch (code)
{
case 'i':
insert(i);
i += 1;
break;
case 's':
search(i);
break;
case 'u':
update(i);
break;
case 'p':
print(i);
break;
}
}
return 0;
}
The problem i have is that when i insert into the "database", the name in each structure gets overwritten. for example:
Enter a function code: i
Enter a part number: 111
Enter a part name: 111
Enter quantity of part: 111
Enter a function code: i
Enter a part number: 222
Enter a part name: 222
Enter quantity of part: 222
Enter a function code: p
Part number: 111
Part name: 222
Part quantity: 111
Part number: 222
Part name: 222
Part quantity: 222
Enter a function code:
As you can see first i insert something new in the "database", take note of the "Part name" which is "111".
Next i insert something else into the database
this time the "Part name" is "222".
Lastly i print the whole "database" what i am confused about is why the part name has now overlapped. but why is this? all the other members such as the part_number and part_quantity remain intact in both insert operations so why does char *part_name stay the same ? and how do i fix this ?
You have the part_name member declared as a char * and you assign to it the address of a local array in the insert function. When the function returns, that array goes out of scope and the stored pointer becomes invalid. Subsequently trying to use that pointer triggers undefined behavior.
Change part_name to be an array:
struct db
{
int part_number;
char part_name[21];
int part_quantity;
};
And write directly to that:
printf("Enter a part name: ");
fgets(database[i].part_name, 21, stdin);
The line
database[i].part_name = name_of_part;
is bad. This is assigning a pointer to the non-static local variable. The variable ends its life on returning from the function and dereferencing pointers pointing to that is illegal.
Instaed of this, you have to copy the string. If you system supports strdup(), it can be done like this:
database[i].part_name = strdup(name_of_part);
If strdup() is not supported or you want to stick to the standard, you dan do like this:
database[i].part_name = malloc(strlen(name_of_part) + 1); /* +1 for ther terminating null-character */
if (database[i].part_name != NULL)
{
strcpy(database[i].part_name, name_of_part);
}
Add #include <stdlib.h> to use malloc().
I am revising my basic C to prepare for the upcoming quiz, when i was writing a function to simply take a character input and store it into a struct and print it out again. There is no issue with the compiling whatsoever but i kept getting logical issue. How do i fix this?
#include <stdio.h>
struct player
{
char letter;
int age;
double avg;
};
int main()
{
struct player P1;
char name;
int age;
double avg;
printf("Enter age: ");
scanf("%d", &age);
printf("Enter avg: ");
scanf("%lf", &avg);
printf("Enter name: ");
scanf("%s", &name);
P1.letter= name;
P1.avg = avg;
P1.age = age;
printf("\n Age is: %d \n", P1.age);
printf("Avg is: %lf", P1.avg);
printf(" \n Name is: %c \n", P1.letter);
return 0;
}
If i put in '1' for int, output would be "Age is: 0'
you are trying to get name, age and avg. of the player. so to store name , you should declare an array not a character. and for assigning the name to structure variable use strcpy().(direct assignment not works). OR if you taking only a single character as a name then write scanf like this:
scanf("%c", &name);
check below code, it will help you,
#include <stdio.h>
struct player
{
char letter[10];
int age;
double avg;
};
int main()
{
struct player P1;
char name[10];
int age;
double avg;
printf("Enter age: ");
scanf("%d", &age);
printf("Enter avg: ");
scanf("%lf", &avg);
printf("Enter name: ");
scanf("%s", &name);
strcpy(P1.letter,name);
P1.avg = avg;
P1.age = age;
printf("\n Age is: %d \n", P1.age);
printf("Avg is: %lf", P1.avg);
printf(" \n Name is: %s \n", P1.letter);
return 0;
}
You are using a character data type for entering a string, "char name" which is leading you to undefined behavior.
Instead of that you declare a character array like this "char name[10]" and then read name. but while assigning you have to take care that you can not assign directly you have to use strcpy like this.
strcpy(p1.letter,name) (Here letter is also character array)
Two quick suggestions:
1) Unless you are certain the name buffer will be populated only by short names, (9 or less characters), pick a more reasonable size for the buffer, such as:
char name[100];
This will also require lengthening the member letter in your struct.
2) when using scanf() to read in variables, the address of the variable being read is passed as the 2nd argument. For variables such as int a; or float b; you must use the address of operator: & as a prefix to the variable. But because the variable name of a C string points to the first character in the array, it already is the address of that variable. So you do not need the explicit & operator when reading a C string into the scanf() function. The return value of the function should also be used to determine if the call was successful. Change the following line as shown:
scanf("%s", &name);
int count = scanf("%s", name);//note: use return value of function
// remove & ^
if(count < 0)
{
//handle error
}
I cooked a code for a program that asks the user to fill in information about a person (ReadDate/ReadPerson), then it asks for the range of people the user wants to print, and the function prints these people. (PrintRange)
I don't understand why the program is not working; it's stuck on the point when it should print the person... it's means there is probably a problem in either PrintPerson or PrintDate, or in the way I am calling these functions.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int day, month, year;
} Date;
typedef struct{
char *first_name, *last_name;
int id;
Date birthday;
} Person;
void ReadDate(Date *a)
{
printf("Enter the day: ");
scanf("%d", &a->day);
printf("Enter the month (1-12): ");
scanf("%d", &a->month);
printf("Enter the year: ");
scanf("%d", &a->year);
}
void ReadPerson(Person *b)
{
char temp_first_name[21];
char temp_last_name[21];
printf("Enter the first name: ");
gets(temp_first_name);
b->first_name = (char*)malloc(strlen(temp_first_name)+1);
strcpy(b->first_name,temp_first_name);
//need to check malloc (later)
printf("Enter the last name: ");
gets(temp_last_name);
b->last_name = (char*)malloc(strlen(temp_last_name)+1);
strcpy(b->last_name, temp_last_name);
//need to check malloc (later)
printf("Enter the id number: ");
scanf("%d",&b->id);
printf("Enter the birthday:\n");
ReadDate(&b->birthday);
}
int ReadAllDate (Person *b)
{
//Person* b;
int count=1;
char choice;
printf("Would you like to enter a person?(y,n)\n");
choice = getchar();
while(choice == 'y')
{
b = (Person*)malloc(1 * sizeof(Person));
getchar();
ReadPerson(b);
printf("Done!\n");
count++;
getchar();
printf("Would you like to add a person?(y,n)\n");
choice = getchar();
}
count--;
printf("The number of entered persons is %d\nBye\n", count);
return count;
}
void PrintPerson(Person b)
{
printf("%s %s %d\n", b.first_name, b.last_name, b.id);
}
void PrintDate(Date a)
{
printf("%d // %d // %d\n",a.day,a.month,a.year);
}
void PrintRange(Person *b,int count,int ind1,int ind2)
{
int i;
if (ind1<0 || ind1>ind2 || ind2>count)
{
printf("error! you slip out from the limits of the array.\n");
}
else
{
for (i=ind1; i<=ind2; i++)
{
PrintPerson(*(b+i));
PrintDate((b+i)->birthday);
}
}
}
int main(int argc, const char * argv[])
{
Person* b;
int count;
int ind1, ind2;
count = ReadAllDate(b);
printf("insert the first index (the smaller): ");
scanf("%d", &ind1);
printf("insert the second index (the bigger): ");
scanf("%d", &ind2);
PrintRange(b, count, ind1, ind2);
}
The problem is that nowhere you are actually creating an array of Person objects. The function ReadAllDate() never changes the value of the variable b in main(). Instead, for every person you read in, it allocates memory for it, and stores the pointer to that Person in the local variable b in ReadAllDate(). Every time it does it, it forgets the previous value of b.
In main(), the value of b is unitinialized all the time. When you are trying to print persons, it will most likely crash or print garbage.
I see other issues with your code:
Don't use gets(), always use fgets(). The former can write past the end of the buffer you are providing.
Don't do malloc(strlen(...))+strcpy(), use strdup().
Start with count = 0, that way you don't need the count-- in ReadAllDate(). As a computer programmer, it's best to count from zero instead of one.
Write b[i] instead of *(b+i), and b[i].birthday instead of (b+i)->birthday.
hello im trying to work with a struct of students but everytime i ask the input of grade the program stop running and i dont know why. im using Turbo C++ 4.0. if i use grades as int the program doesnt stop but when i use them as float the program stop running. please any help heres the code:
#include<conio.h>
#include<stdio.h>
#define num 2
struct student {
char name[50];
float cal1;
float cal2;
float prom;
} est[num];
int main () {
int i=0;
clrscr();
for(i=0;i<=num;i++) {
printf("\nName of student[%d]:",i);
scanf("%s",&est[i].name);
printf("\nGrade #1 [%d]:",i);
scanf("%f",&est[i].cal1);
printf("\nGrade #2 [%d]:",i);
scanf("%f",&est[i].cal2);
}
for(i=0;i<=num;i++) {
printf("\nStudent [%d]:",i);
printf("\nName: ");
printf("%s",est[i].name);
printf("\nGrade #1: ");
printf("%f",est[i].cal1);
printf("\nGrade #2: ");
printf("%f",est[i].cal2);
}
getch();
return 0;
}
You define:
#define num 2
struct student { … } est[num];
and you loop on:
for (i = 0; i <= num; i++)
{
…scanning code…
}
This is a buffer overflow. It attempts to read 3 students worth of data, with the third student's data going into the space after the space allocated for est. This is a buffer overflow and leads to undefined behaviour; anything can happen and it is OK.
In C, get used to using the idiomatic for loop:
for (i = 0; i < limit; i++)
In the code that reads data, you need to check that the scanf() calls succeed:
printf("\nName of student[%d]:",i);
if (scanf("%s", est[i].name) != 1) // Note no & for strings
…handle error…
printf("\nGrade #1 [%d]:",i);
if (scanf("%f", &est[i].cal1) != 1)
…handle error…
printf("\nGrade #2 [%d]:",i);
if (scanf("%f", &est[i].cal2) != 1)
…handle error…
The printing loop should not attempt to print more entries than were actually read, which might be less than num if there was an error. Obviously, it needs to be in the idiomatic form too, but you should really be using:
int j;
for (j = 0; j < i; j++)
or something similar so if only 1 entry was read, you only print that one entry.
here is an example of the code that
cleanly compiles, links, runs
I did not use conio.h as it is non-standard
(and not available on my machine)
this code still needs the error checking for returned value from scanf added
#include <stdio.h>
//#include <conio.h>
#include <stdlib.h> // system()
#define num (2)
struct student
{
char name[50];
float cal1;
float cal2;
float prom; // only one ';'
};
// separated definition, above, from declaration, below
struct student est[num];
int main ()
{
int i=0;
system( "cls" );
//clrscr();
for(i=0;i<num;i++) // note correction to for statement
{
printf("\nName of student[%d]:",i);
scanf(" %49s", est[i].name); // note correction to format string
// and using array
// as degraded into pointer
// otherwise
// unknown where trying to place data
// added vertical spacing for readability
printf("\nGrade #1 [%d]:",i);
scanf("%f", &est[i].cal1);
// added vertical spacing for readability
printf("\nGrade #2 [%d]:",i);
scanf("%f", &est[i].cal2);
}
for(i=0;i<num;i++) // note correction to 'for' statement
{
printf("\nStudent [%d]:",i);
printf("\nName: ");
printf("%s",est[i].name);
printf("\nGrade #1: ");
printf("%f",est[i].cal1);
printf("\nGrade #2: ");
printf("%f",est[i].cal2);
}
getchar(); // this will input the final newline, so will exit immediately
//getch();
return 0;
} // end function: main
Ok so I got this thing going here.
I keep getting a few errors.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <cstdio>
//functions called
int get_lmt();
int get_total_trash();
void print_output(int, int);
//why is it void?
int main(void)
{
char hauler[100];
int t_trash=0, lmt=0;
printf("Hello \n What is your name: ");
fflush(stdin);
scanf("%s", &hauler);
t_trash = get_total_trash();
lmt = get_lmt();
printf("Name: %s\n", &hauler);
print_output(lmt, t_trash);
system("pause");
return 0;
}
int get_total_trash()
{
char yn = 'y';
int t_trash = 0, trash=0;
while (yn != 'n')
{
printf("What is your trash: ");
fflush(stdin);
scanf("%i", &trash);
t_trash = trash + t_trash;
printf("Do you have more trash tons? (y or n): ");
fflush(stdin);
scanf("%c", &yn);
}
return t_trash;
}
int get_lmt()
{
int lmt = 0;
printf("What was last months trash: ");
fflush(stdin);
scanf("%i", &lmt);
return lmt;
}
void print_output(int lmt, int t_trash)
{
float rate = 350.00, charge;
int sum=0, total=0;
if (lmt > t_trash)
{
printf("Total trash tons: %i\n", &t_trash);
printf("Last month's trash: %i\n", &lmt);
printf("Rate: $ %.2f\n", &rate);
}
else
{
printf("What is your tonnage rate: ");
fflush(stdin);
scanf("%.2f\n", &charge);
sum = t_trash - lmt;
total = sum * charge;
rate = rate + total;
printf("Total trash tons: %i\n", &t_trash);
printf("Last month's trash: %i\n", &lmt);
printf("Rate: $ %.2f\n", &rate);
}
}
Now what it should be doing is, The main should be calling the functions on screen as needed.
Now i did all of this with cout cin and it works fine no problems. But when I run this (this is modified to the printf and scanf) it says:
OK UPDATE: Got a ton of it to work. Just one more thing and I should be good. The outcome will not go as expected.
Instead of an output of
last months trash: 100 (asked at the end of the loop)
trash tonnage: 50 (accumulated in the loop)
rate: 350.00 (float variable)
(this is if last month trash was > this month.)
I get just bad numbers all around. It makes no mathematical sense.
Other then that it works fine.
Does the code the the last function look wrong to you guys?
Lots of problems with this code. Lots of them.
1) print_output defintiion takes in a char[100] (char*), print_output declatation takes a char
2) When you pass hauler into print_output, you are passing in hauler[100] (a char, and one pass the end of the array to boot)
3) printf("Name: %s\n", &hauler); hauler is of type char[100] (char*), so &hauler is char**.
there is probably more.