Compiler error when trying to print from struct - c

My assignment is to, using structs, get input of info on employees, and output their pay.
It appears to run properly until I get to the end and try to printf() the calculated results. The compiler tells me [Error] request for member '*' in something not a structure or union. (Replace * with ID, name, grossPay, netPay.)
Sorry if it's been asked; I'm still new to structs/pointers/etc, so I suspect it's a simple mistake. It's just not jumping out at me. I looked through some of the previous questions but many are situation-specific.
// Matt Posey - PP #20
#include <stdio.h>
struct employee
{
char ID[6];
char name[20];
float hours;
float payRate;
float grossPay;
float netPay;
};
int main()
{
int j, i = 0;
int employees;
printf("This program computes pay.\n");
printf("\nNumber of employees: ");
scanf("%d", &employees);
fseek(stdin,0,SEEK_END);
// Get data
for (i = 0; i < employees; i++)
{
j = i;
struct employee j;
printf("\nFor employee %d:", i+1);
printf("\nID: ");
gets(j.ID);
fseek(stdin,0,SEEK_END);
printf("Name: ");
gets(j.name);
fseek(stdin,0,SEEK_END);
printf("Pay rate: ");
scanf("%f", &j.payRate);
fseek(stdin,0,SEEK_END);
printf("Hours worked: ");
scanf("%f", &j.hours);
fseek(stdin,0,SEEK_END);
j.grossPay = j.hours * j.payRate;
if (j.hours > 40)
{
printf("Overtime!");
float OT = (j.hours - 40) * (j.payRate * 0.5);
j.grossPay += OT;
}
j.netPay = j.grossPay * 0.75;
}
// Output data
printf("\n\nID | Name | Gross Pay | Net Pay");
printf("\n------ | -------------------- | --------- | -------");
for (i = 0; i < employees; i++)
{
j = i;
printf("\n%c | %c | $%7.2f | $%7.2f", j.ID, j.name, j.grossPay, j.netPay);
}
return 0;
}

Several issues with the question code...
1)
// Get data
for (i = 0; i < employees; i++)
{
j = i;
struct employee j;
The variable j is only visible inside the scope (ie braces) where it is declared. Fix this by moving it to `main()''s scope:
int main()
{
int j, i = 0;
int employees;
struct employee j;
Of course, this causes another problem it that there is already an `int j' defined. Get rid of that:
int main()
{
int i = 0;
int employees;
struct employee j;
2) Next, you need j to be an array that can hold all the employees. Unfortunately, you don't know (at compile time) how many employees the user will require. So, just make a pointer to allocate some memory to later:
int main()
{
int i = 0;
int employees;
struct employee *j=NULL;
Let the user indicate how many employees, then allocate sufficient memory for the array:
printf("\nNumber of employees: ");
scanf("%d", &employees);
fseek(stdin,0,SEEK_END);
j = malloc(employees * sizeof(*j));
if(NULL == j)
{
fprintf(stdout, "malloc() failed.\n");
goto CLEANUP;
}
Then, put a 'goto label' just before the return statement:
CLEANUP:
return 0;
}
In order to use the malloc() function, you will have to include another header:
#include <stdio.h>
#include <stdlib.h> /* Added for 'malloc()' */
3) Now get rid of the j=i; thing:
// Get data
for (i = 0; i < employees; i++)
{
printf("\nFor employee %d:", i+1);
4) Now, everywhere j is referenced, reference it like an array:
printf("\nID: ");
gets(j[i].ID);
fseek(stdin,0,SEEK_END);
printf("Name: ");
gets(j[i].name);
fseek(stdin,0,SEEK_END);
printf("Pay rate: ");
scanf("%f", &j[i].payRate);
fseek(stdin,0,SEEK_END);
printf("Hours worked: ");
scanf("%f", &j[i].hours);
fseek(stdin,0,SEEK_END);
j[i].grossPay = j[i].hours * j[i].payRate;
if (j[i].hours > 40)
{
printf("Overtime!");
float OT = (j[i].hours - 40) * (j[i].payRate * 0.5);
j[i].grossPay += OT;
}
j[i].netPay = j[i].grossPay * 0.75;
And here too:
printf("\n%c | %c | $%7.2f | $%7.2f", j[i].ID, j[i].name, j[i].grossPay, j[i].netPay);
5) Get rid of the j = i; in main():
for (i = 0; i < employees; i++)
{
printf("\n%c | %c | $%7.2f | $%7.2f", j[i].ID, j[i].name, j[i].grossPay, j[i].netPay);
}
6) Fix the printf() format string. It should be printing strings, not characters:
printf("\n%s | %s | $%7.2f | $%7.2f", j[i].ID, j[i].name, j[i].grossPay, j[i].netPay);
Now the code is functional.
However, there is still some of the code that is risky. For example, fgets() should be used (instead of gets()) [as indicated by chris & McLovin], etc.
printf("\nID: ");
fgets(j[i].ID, sizeof(j[i].ID), stdin);
fseek(stdin,0,SEEK_END);
printf("Name: ");
fgets(j[i].name, sizeof(j[i].name), stdin);
And the report would be cleaner if there was an ending newline:
printf("\n");
CLEANUP:
return 0;
}
And as indicated by Ed Heal, this line is not needed:
fseek(stdin,0,SEEK_END);
SPOILER

You have used a name "name of a variable" twice.
First you say there's an int called j, then you stay there is a struct employee called j. Rename one or the other.
int j, i = 0;
(and much later)
j = i;
struct employee j;

Related

Printing out values in an array not working as expected

I was tasked with inputting student information based on a given struct, where each field of information is to be typed in one line, separated by a space, then the student id is sorted incrementally, and then print out the information, each student on a new line. The problem is while I thought my code was good, the print part keeps giving fractured results and overall just not printing out the correct values. Where should I fix this?
Here's my code:
#include <stdio.h>
typedef struct
{
char id[8];
int year;
}student;
int main() {
student std[100];
int i, j, num, tmp;
printf("So sinh vien:\n");
scanf("%d", &num);
printf("Nhap thong tin sinh vien:\n");
for(i=0; i <= num; i++)
{
scanf("%c %d\n", &std[i].id, &std[i].year);
}
for(i=0; i < num; i++)
{
for (j=1; j< num; j++)
{
if (std[i].id > std[j].id)
{
tmp = *std[i].id
*std[i].id = *std[j].id;
*std[j].id = tmp;
}
}
}
for(i=0; i < num; i++)
{
printf("%c ", std[i].id);
printf("%d\n", std[i].year);
}
return 0;
}
My output is
So sinh vien:
3
Nhap thong tin sinh vien:
12324521 2003
12341552 2002
12357263 2001
Σ 12324521
≡ 3
ⁿ 2341552
Check the return value of scanf() otherwise you may be operating on uninitialized variables.
Check that num less than the 100 records you allocated for student, or even better use a vla along with a check to avoid large input from smashing the stack.
You input num then read num+1 records but later you only print num records.
As you read a character with "%c" the first input with be the \n from the previous scanf().
The struct contains a char id[8] but you only read a single character into it. Read a string instead.
In sort you use > to compare the first letter of id. You probably want to use strcmp() to compare strings.
In sort section you use a int tmp for storing a character of id (which is ok) but then you write an int which is no good.
In sort you only swap the ids. You probably want to swap the entire record not just the ids.
It seems to be an exchange sort. Use a function, and also at least for me the algorithm didn't work as the inner loop variable should start at j=i+1 not 1.
In your print char id[8] as a single char instead of string.
Moved print functionality to a function. This allows you, for instance, to print the students before and after the sort() during debugging.
Minimizing scope of variables (i and j are now loop local, tmp is only used in the swap() function). This makes code easier to reason about.
#include <stdio.h>
#include <string.h>
#define ID_LEN 7
#define str(s) str2(s)
#define str2(s) #s
typedef struct {
char id[ID_LEN+1];
int year;
} student;
void swap(student *a, student *b) {
student tmp = *a;
*a = *b;
*b = tmp;
}
void print(size_t num, student std[num]) {
for(size_t i=0; i < num; i++)
printf("%s %d\n", std[i].id, std[i].year);
}
// exchange sort
void sort(size_t num, student std[num]) {
for(size_t i=0; i < num - 1; i++)
for (size_t j=i+1; j < num ; j++)
if(strcmp(std[i].id, std[j].id) > 0)
swap(&std[i], &std[j]);
}
int main() {
printf("So sinh vien:\n");
size_t num;
if(scanf("%zu", &num) != 1) {
printf("scanf() failed\n)");
return 1;
}
if(num > NUM_MAX) {
printf("Too many students\n");
return 1;
}
student std[num];
printf("Nhap thong tin sinh vien:\n");
for(size_t i=0; i < num; i++)
if(scanf("%" str(ID_LEN) "s %d", std[i].id, &std[i].year) != 2) {
printf("scanf() failed\n");
return 1;
}
sort(num, std);
print(num, std);
}
and here is an example run:
So sinh vien:
3
Nhap thong tin sinh vien:
aaa 1
zzz 2
bbb 3
aaa 1
bbb 3
zzz 2
printf("%c ", std[i].id);
should be
printf("%s ", std[i].id);
%c means a single char.

How to find percent from a loop and return a float

I'm stuck on trying to figure out how to take a multiple candidate data from a loop and figure out a winner from them by stating their name, ID, and total percent of votes within the same function. I also need to return the winning candidates ID from the function. For example: candidate 1 - is named Stevens with ID 13.07 and total votes of 1500, candidate 2 - is named George with ID 17.49 and total votes of 2000. I need to output the winner which is George with ID 17.49 and his percent of the total 3500 votes. This is what I have so far but I'm new to programming and have no idea how to figure this out. Any help would be greatly appreciated!
float CandidateData(int N, int X) {
char candName[21];
int i;
double candID;
int candVotes;
int voteSum;
int j = 0;
double max = 0;
double first;
for (i = 0; i < N; i++) { //N is the number of candidates
printf("Enter candidates name (20 characters max): ");
scanf("%s", &candName);
printf("Candidate name: %s\n\n", candName);
printf("Enter candidate ID (float 01.01-52.99): ");
candID = CandidateID(52.99);
printf("Candidate ID is: %g\n\n", candID);
printf("Enter %d precinct votes (int 1-1000): ", X);
voteSum = 0;
for (j = 0; j < X; j++) { //X is number of precincts
candVotes = NumberOfCandidatesAndPrecincts(1000);
printf("Precinct #%d = %d\n", j + 1, candVotes);
voteSum = voteSum + candVotes;
}
printf("Total candidate votes = %d\n", voteSum);
printf("Average votes for county = %d\n\n", voteSum / X);
if (voteSum > max) {
max = voteSum;
}
}
printf("The winning candidate is %s with ID %g with %d% of total votes", candName, candID, )
return (candID);
}
I see few mistakes in your code.
First of all, it should be :
scanf("%s", candName);
not
scanf("%s", &candName);
Because candName is already the address of the first element of the array.
Another issue, suppose a user types Whoever President for candName. Then try this:
printf("Candidate name: %s\n\n", candName);
You will see that only Whoever is printed because scanf("%s",candName) takes input until a white space comes. It can be a blank space (' '), new line (\n) or tab (\t).
Instead, I strongly suggest you to use fgets.
fgets (candName, 21, stdin);
where 21 is the maximum buffer length that you want to have.
Now, you can print candName with printf and observe that fgets puts extra new line ('\n') at the end of your string. You can easily remove it by:
if ((strlen(candName) > 0) && (candName[strlen (candName) - 1] == '\n')){
candName[strlen (candName) - 1] = '\0';}
Keep in mind that using fgets and scanf together is problematic because scanf function leaves \n in the input buffer, after fgets reads input from buffer, you will encounter unexpected results. Use getchar(); after each scanf. It consumes \n. The problem disappears!
The next mistake you made is return_type of CandidateData function. Its return_type is float but type of candID variable is double so make a change for just one of them. In your task, it is sufficient to use float type for candID.
There are also some typos in the last printf function. It should be:
printf("The winning candidate is %s with ID %f with %d of total votes", candName, candID, voteSum);
Let's come to your question. To store the candidate who takes maximum vote, you can declare a struct and fill related fields when number of votes of a candidate exceeds current max value.
I add the final code:
#include <stdio.h>
#include <string.h>
struct President{
char candName[21];
float candID;
int candVotes;
};
float CandidateData(int N, int X) {
struct President winnerCandidate = {.candVotes = 0};
char candName[21];
float candID;
int candVotes;
int voteSum;
int i,j;
for (i = 0; i < N; i++) { //N is the number of candidates
printf("Enter candidates name (20 characters max): ");
fgets (candName, 21, stdin);
if ((strlen(candName) > 0) && (candName[strlen (candName) - 1] == '\n')){
candName[strlen (candName) - 1] = '\0';}
printf("Candidate name: %s\n", candName);
printf("Enter candidate ID (float 01.01-52.99): ");
scanf("%f",&candID);
getchar();
printf("Candidate ID is: %.2f\n", candID);
voteSum = 0;
printf("Enter %d precinct votes (int 1-1000):\n", X);
for (j = 1; j <= X; j++) { //X is number of precincts
scanf("%d",&candVotes);
getchar();
printf("Precinct #%d = %d\n", j , candVotes);
voteSum = voteSum + candVotes;
}
printf("Total candidate votes = %d\n", voteSum);
printf("Average votes for county = %.3f\n\n", voteSum/(float)X);
if(voteSum > winnerCandidate.candVotes){
winnerCandidate.candVotes = voteSum;
winnerCandidate.candID = candID;
strcpy(winnerCandidate.candName,candName);
}
}
printf("The winning candidate is %s with ID %.2f with %d of total votes", winnerCandidate.candName, winnerCandidate.candID, winnerCandidate.candVotes);
return winnerCandidate.candID;
}
int main(){
float winner_candID = CandidateData(3,2);
printf("\nWinner Candidate ID is: %.3f",winner_candID);
return 0;
}
If you have any question, let me know!

Finding average for 2 students

I am running a program to calculate average for 2 students. I am having trouble running this. For some reason it says it cannot be found. It's my first time using Visual Studio and I am not sure if my code is the problem or the program.
Please check if there's a mistake and let me know.
#include <stdio.h>
int main(void)
{
int firstGrade1;
int sGrade1;
int tGrade1;
int fGrade1;
int TotalGrade1 = (firstGrade1 + sGrade1 + tGrade1 + fGrade1);
int AveGrade1 = (TotalGrade1 / 4);
printf("Please enter Student 1 first grade:\n");
scanf("%d", &firstGrade1);
printf("Please enter Student 1 second grade:\n");
scanf("%d", &sGrade1);
printf("Please enter Student 1 third grade:\n");
scanf("%d", &tGrade1);
printf("Please enter Student 1 fourth grade:\n");
scanf("%d", &fGrade1);
int firstGrade2;
int sGrade2;
int tGrade2;
int fGrade2;
int TotalGrade2 = (firstGrade2 + sGrade2 + tGrade2 + fGrade2);
int AveGrade2 = (TotalGrade2 / 4);
printf("Please enter Student 2 first grade:\n");
scanf("%d", &firstGrade2);
printf("Please enter Student 2 second grade:\n");
scanf("%d", &sGrade2);
printf("Please enter Student 2 third grade:\n");
scanf("%d", &tGrade2);
printf("Please enter Student 2 fourth grade:\n");
scanf("%d", &fGrade2);
printf("1. Student 1 grades:");
printf("%d", firstGrade1, sGrade1, tGrade1, fGrade1);
printf(". Average is ");
printf("%d\n", AveGrade1);
printf("2. Student 2 grades:");
printf("%d", firstGrade2, sGrade2, tGrade2, fGrade2);
printf(". Average is ");
printf("%d", AveGrade2);
system("pause");
return (0);
}
This here
int TotalGrade1 = (firstGrade1 + sGrade1 + tGrade1 + fGrade1);
Doesn't tell it that TotalGrade1 will just always be the value of those 4 variables added up. It assigns to TotalGrade1 the sum of those variables' current values. Since those are uninitialized, that's undefined behavior. Move the calculation of TotalGrade1 and AveGrade1 to after you read in those values, and likewise for TotalGrade2 and AveGrade2, of course.
Also, consider this print:
printf("%d", firstGrade1, sGrade1, tGrade1, fGrade1);
You are printing four int, why is there only one format specifier? The format string should be "%d %d %d %d".
I suggest always paying attention to your compiler's warnings. Usually your compiler should warn you about incorrect printf format strings as well as using uninitialized variables.
On a side note, you have a lot of code duplication. What if you didn't have two students and four grades, but a hundred students with ten grades each? Imagine the amount of code, and the amount of work copy/pasting the code. Instead, try something like this:
int main(void)
{
int Grade[2][4];
int AveGrade[2];
int TotalGrade[2];
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 4; j++) {
printf("Please enter Student %d j. grade:\n", i + 1, j+1);
scanf("%d", &Grade[i][j]);
}
TotalGrade[i] = 0;
for (int j = 0; j < 4; j++)
TotalGrade[i] += Grade[i][j];
AveGrade[i] = (TotalGrade[i] / 4);
}
for (int i = 0; i < 2; i++) {
printf("%d. Student %d grades:", i+1, i+1);
for (int j = 0; j < 4; j++)
printf("%d ", Grade[i][j]);
printf(". Average is ");
printf("%d\n", AveGrade[i]);
}
system("pause");
return (0);
}

Code is not working (C)

I want to calculate the wages with struct and arrays but it is not working. You will understand the exercise better when you see the code. For some reason if in Wage and Days_Worked I enter a number(100 and 2)
Wagered[i].Gross_Wage = Wagered[i].Wage * Wagered[i].Days_Worked; Won't give me 200 but something else. Generally the programm won't work and I am trying to find the reason.
#include <stdio.h>
struct User
{
char First_Name[25];
char Last_Name[25];
int Wage, Days_Worked;
int Tax;
int Wage_Booking;
int Net_Wage;
int Gross_Wage;
};
int main()
{
int i;
int Wage_Summary = 0;
struct User Wagered[1];
for(i = 0; i < 1; i++)
{
/*printf("First Name: ");
scanf("%s", &Wagered[i].First_Name);
printf("\n");
printf("Last Name: ");
scanf("%s", &Wagered[i].Last_Name);
printf("\n");*/
printf("Wage: ");
scanf("%d", &Wagered[i].Wage);
printf("\n");
printf("Days He Worked: ");
scanf("%d", &Wagered[i].Days_Worked);
printf("\n");
Wagered[i].Gross_Wage = Wagered[i].Wage * Wagered[i].Days_Worked;
Wagered[i].Wage_Booking = Wagered[i].Gross_Wage * 0.2;
Wagered[i].Tax = (Wagered[i].Gross_Wage - Wagered[i].Wage_Booking) * 0.05;
Wagered[i].Net_Wage = Wagered[i].Gross_Wage - Wagered[i].Wage_Booking - Wagered[i].Tax;
Wage_Summary += Wagered[i].Net_Wage;
}
printf("The Summary of the Gross Wages is: %d\n", Wagered[i].Gross_Wage);
return 0;
}
This statement :
printf("The Summary of the Gross Wages is: %d\n", Wagered[i].Gross_Wage);
is outside your for loop. Therefore it will be executed when i has value 1, thus accessing Wagered[1].Gross_Wage, which does not exist Wagered[1] is out of your array's bounds. Move it inside your for loop, like this :
for(i = 0; i < 1; i++)
{
.
.
.
Wagered[i].Gross_Wage = Wagered[i].Wage * Wagered[i].Days_Worked;
Wagered[i].Wage_Booking = Wagered[i].Gross_Wage * 0.2;
Wagered[i].Tax = (Wagered[i].Gross_Wage - Wagered[i].Wage_Booking) * 0.05;
Wagered[i].Net_Wage = Wagered[i].Gross_Wage - Wagered[i].Wage_Booking - Wagered[i].Tax;
Wage_Summary += Wagered[i].Net_Wage;
printf("The Summary of the Gross Wages is: %d\n", Wagered[i].Gross_Wage);
}
and you will see the correct result printed.

Arrays of Structures in C

I am a newbie with C and I am trying to run a program from my book which shows how we deal with arrays of structures.
#include<stdio.h>
#include<conio.h>
struct employee
{
int empno;
char name[30];
int basic;
int hra;
};
void main()
{
struct employee e[50];
int i, j, n;
int net[50];
float avg;
printf("Enter the number of employees: ");
scanf("%d", &n);
printf("Enter Emp. No. \tName:\tBasic\tHRA of each employee in the order.\n");
for(i=0; i<n; i++)
{
scanf("%d", &e[i].empno);
gets(e[i].name);
scanf("%d", &e[i].basic);
scanf("%d", &e[i].hra);
net[i]=e[i].basic + e[i].hra ;
avg = avg + net[i];
}
avg = avg/n;
printf("Emp. No \t Name-Netpay: ");
for(i=0; i<n; i++)
{
if(net[i]>avg)
{
printf("\t",e[i].empno);
printf("\t", e[i].name);
printf("\t", net[i]);
} } }
I also have further modules which goes on to compute the average and prints those elements whose salary + hr is more than average. However the code pasted above does not work as intended.
Now, if I enter the number of employees - Let's say 1, it only allows me to enter the empno and name and exits the loop. I am expecting it to complete at least one cycle through the loop with the value 1.
Any suggestions on this would be highly appreciated and I apologize if I am messing up anywhere. Thanks.
You need to flush the line from the input before using gets (which is deprecated btw):
#include <stdio.h>
struct employee
{
int empno;
char name[30];
int basic;
int hra;
};
int main()
{
struct employee e[50];
int i, j, n;
int net[50];
float avg;
printf("Enter the number of employees: ");
scanf("%d", &n);
printf("Enter Emp. No. \tName:\tBasic\tHRA of each employee in the order.\n");
for(i=0; i<n; i++)
{
scanf("%d", &e[i].empno);
char c;
while ((c = getchar()) != EOF && c != '\n');
gets(e[i].name);
scanf("%d", &e[i].basic);
scanf("%d", &e[i].hra);
net[i]=e[i].basic + e[i].hra ;
avg = avg + net[i];
}
return 0;
}
This is because scanf does not read the end of line (\n) but gets will and return immediately. scanf will read the name instead. Basically, it's a mess then :).

Resources