C programming - how to stop counting if load function is break out? - c

I have a question that is needed to ask. Hope someone can help me out.
I am writing a function that prompts users for names, hours worked, and hourly rate using parameter passing, and pass by reference. If the user input "-1" in any field, break out of the function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct userdata
{
char name[20];
float hours;
float rate;
float gross;
float base;
float overtime;
float taxes;
float net;
}data;
int LoadEmployeeFromKey(data *d)
{
char name[20];
float rate, hours;
printf("Enter an employee name: ");
scanf_s("%s", name, 20);
if (strcmp(name, "-1") == 0)
return;
printf("Worked Hours: ");
scanf_s("%f", &hours);
if (hours == -1.0f)
return 1;
printf("Hourly rate: ");
scanf_s("%f", &rate);
if (rate == -1.0f)
return 1;
strcpy_s(d->name, 20, name);
d->hours = hours;
d->rate = rate;
return 1;
}
There is nothing wrong in here, this function works well. But the real problem when I work in main().
void main()
{
data employee[10];
int count = 0;
int option;
int stop = 0;
int i = 0;
FILE EmployeeFromFile[20];
FILE *File;
while (!stop)
{
puts("---Main Menu---\n");
puts("CHOOSE A FOLLOWING OPTION:");
puts("1. Add an employee info from keyboard.");
puts("2. Add employees info from a text file.");
puts("3. Print all employees info.");
puts("4. Edit an employee info.");
puts("5. Print an employee and salary.");
puts("6. Print all employees and salary.");
puts("7. Save and Quit the program.\n");
scanf_s("%d", &option);
switch (option)
{
case 1:
LoadEmployeeFromKey(&employee[count]);
Calculation(&employee[count]);
count++;
break;
Please ignore other things, when I debug, if I input "-1" in any field of (name, hours, or rate), it breaks and goes back to "Main Menu"; however, "count" is still counting (it still plus 1) leading to error output when I choose 3 -> 6. It may be a stupid question but to be honest I cannot find out where or what should I type to search to solve this problem. I am okay to see downvote but please help.
Thank you.

Your function LoadEmployeeFromKey is declared to return a value, and most of your return statements do return a value.
The problem is two-fold: First is that the function (except in one case) always return the same value, making it impossible to distinguish between the cases; The second problem is that you don't check what the function return, so it's not possible to add conditions based on that.
First of all make sure all return statements actually return a value (otherwise you will have undefined behavior). Then return one value if the input was "-1", and some other value if you fully initialized the structure. Lastly, use the returned value to check if you should increase the counter or not.
First of all, you must (and probably already) have a proper function prototype:
int LoadEmployeeFromKey(data *d);
Secondly, you have used function which returns a value before?
Lets say that the function return 1 on success, when all fields have been properly entered and initialized, and 0 otherwise, then you could use it directly in a condition:
if (LoadEmployeeFromKey(&employee[count]) == 1)
{
// All data valid
Calculation(&employee[count]);
count++;
}
If the function doesn't return 1 then just don't do anything special.

Related

Finding three leaders from arrays

Thank you for visiting this question. I know this looks like a question from a book which it totally is. I couldn't find the solution for this anywhere and I cant get one thing. Supposedly the code compare things like studs[i].score within for loop, but why it can assign the value of studs[i].score to another element of the struct like say first.score? The same goes for studs[i].name = first.name the program wont even compile. Any input matter, have been sitting with this for a week.
Have a great day!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stud {
char name[50];
float score;
};
//Please do not modify struct stud
//You are only allowed to modify inside printThreeLeaders
void printThreeLeaders(struct stud studs[], int count) { //why is count here? C arrays do not carry any size indicator, we
//must explicitly pass the number of elements in as an argument
//Please do not modify the content of studs array
struct stud first, second, third;
//Your code here
for (int i=0;i<count;i++){
if (studs[i].score>third.score){
if(studs[i].score>second.score){
if (studs[i].score>first.score){
studs[i].score=first.score;
studs[i].name=first.name;
}
}studs[i].score=second.score;
studs[i].name=second.name;
}studs[i].score=third.score;
studs[i].name=third.name;
}
//Please find the top three highest scoring students on the leaderboard
//and print out their names and scores.
//You are allowed to use string functions such as strcmp or strcpy
//Although you might not need them
//Please do not modify the following code
printf("Leader board:\n");
printf("First place: %s, %.2f\n", first.name, first.score);
printf("Second place: %s, %.2f\n", second.name, second.score);
printf("Third place: %s, %.2f\n", third.name, third.score);
}
//Please do not modify main function
int main(void) {
struct stud students[20];
int stud_count = 0;
char temp_name[50];
float grade = 0;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
while (grade != -1)
{
scanf("%s", temp_name);
students[stud_count].score = grade;
strcpy(students[stud_count].name, temp_name);
stud_count ++;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
}
if(stud_count > 2) {
printThreeLeaders(students, stud_count);
}
return 0;
}
A few issues:
You do modify the studs array with: studs[i].score=second.score;
The three variables first, second, and third are uninitialized so you have UB (undefined behavior)
You don't need to use str* functions to copy the name if you copy the whole struct.
Here is the refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stud {
char name[50];
float score;
};
// Please do not modify struct stud
// You are only allowed to modify inside printThreeLeaders
void
printThreeLeaders(struct stud studs[], int count)
{
// why is count here? C arrays do not carry any size indicator, we
// must explicitly pass the number of elements in as an argument
// Please do not modify the content of studs array
// NOTE/BUG: first/second/third are _not_ initialized
#if 0
struct stud first, second, third;
#else
struct stud first = { .score = -1 };
struct stud second = { .score = -1 };
struct stud third = { .score = -1 };
#endif
// Your code here
for (int i = 0; i < count; i++) {
const struct stud *st = &studs[i];
float score = st->score;
if (score > first.score) {
third = second;
second = first;
first = *st;
continue;
}
if (score > second.score) {
third = second;
second = *st;
continue;
}
if (score > third.score) {
third = *st;
continue;
}
}
// Please find the top three highest scoring students on the leaderboard
// and print out their names and scores.
// You are allowed to use string functions such as strcmp or strcpy
// Although you might not need them
// Please do not modify the following code
printf("Leader board:\n");
printf("First place: %s, %.2f\n", first.name, first.score);
printf("Second place: %s, %.2f\n", second.name, second.score);
printf("Third place: %s, %.2f\n", third.name, third.score);
}
// Please do not modify main function
int
main(void)
{
struct stud students[20];
int stud_count = 0;
char temp_name[50];
float grade = 0;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
while (grade != -1) {
scanf("%s", temp_name);
students[stud_count].score = grade;
strcpy(students[stud_count].name, temp_name);
stud_count++;
printf("Enter a test score(-1 to quit), or\n");
printf("Enter a grade first, then a student's name\n");
scanf("%f", &grade);
}
if (stud_count > 2) {
printThreeLeaders(students, stud_count);
}
return 0;
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
Here is the test input I used:
1 Fred
2 Bob
3 Alice
4 John
5 Mary
6 Frank
7 Abel
8 Cain
9 Peter
10 Kilroy
11 Smith
12 Jones
-1
Here is the [cleaned up] program output:
Leader board:
First place: Jones, 12.00
Second place: Smith, 11.00
Third place: Kilroy, 10.00
UPDATE:
Amazing, it does work. The problem was in initialization of first, second and third. With this edits it does work. My incorrect reasoning was that initialization happened at 'struct stud first second third'. –
JEDi455
C is all about minimalism and speed.
Initialization [of stack based variables] is not done by default for speed.
Here, for this problem, explicit initialization was needed.
But, in another problem, suppose we had (e.g.):
int x,y,z;
If we explicitly assign them values with:
/* some small blob of code unrelated to x/y/z ... */
x = funcA();
y = funcB(x);
z = funcC(x,y);
Then, we'd be cursing the compiler for wasting time by initializing them to default values, only to overwrite those values with our explicit code.
That is, if the compiler always treated:
int x,y,z;
as:
int x = 0, y = 0, z = 0;
We'd not want the compiler to "help" us in this way. That is, if we wanted the latter, we'd have written that.
C gives the programmers full control [and assumes they know what they're doing]. The compiler will try to help by flagging statements with errors or warnings, but it's often up to the programmer.

Why does my program terminate after the while loop?

The following program is supposed to ask the user how many students he wants to grade then have the user input the grades and get the average.
#include <stdio.h>
#include <stdlib.h>
struct person {
char Name[100];
int ID;
int Age;
double Score;
};
int main(void) {
setvbuf(stdout, NULL, _IONBF, 0);
int size;
printf("How many students are you grading?(Not more than 100)-->");
scanf("%d",&size);
struct person *student;
double total=0,i=0, average;
student= malloc(sizeof(struct person));
//struct person student;
printf("Enter the following information:\n");
while (i<size) {
printf("%lf\n%lf\n",total,i);
printf("\n");
printf("Name:");
scanf("%s",student->Name);
printf("ID:");
scanf("%d",&student->ID);
printf("Age:");
scanf("%d",&student->Age);
printf("Score:");
scanf("%lf",&student->Score);
total = total + student->Score;
i++;
}
The code works fine until it needs to print out the average based on user input, at which point the program terminates without giving the average nor an error message.
if(size==1){
average = total / size;
printf("Class average is %0.2lf\n", average);
}
else
{
average=total/i;
printf("Class average is %0.2lf\n", average);
}
return 0;
}
Most console programs are intended to be run from some kind of console host like windows cmd, where the output stays there and it would be annoying for user to do some additional work to end the program so they can run another command, but since you are just testing it, you should put some code at the end to wait for some user input, now there are many ways to do that like: getch(), getchar(), scanf("%*c"), system("pause") so you can try those, but some compilers do this automatically in debug mode, sometimes you just need to specify the behaviour in your IDE settings.
I think the problem you are having is that the console is closing before you can read the average.
You could add:
getchar();
Before you return 0; in int main.

Defining functions that return a char used later in the main program

I am having a lot of trouble wrapping my head around calling functions and using them in the main program again later. I have not found an answer in depth to explain why this doesn't run. I understand that parameters belong inside of the called function parentheses, but I want the user input to begin in the called program. Is this even possible? Theoretically, the function would ask the user for a year, check that it is within certain parameters, then return it to the main function where I would like to eventually be able to store it in an array. For now, can someone please show me how I would make that work in this elementary program? Thank you in advance!
#include <stdio.h>
char year_info();
int main(void)
{
int menu_selection;
char year;
printf("Please choose from the following menu: \n1. Insert a new movie\n2. Show movie\n3. List all\n4. Exit\n");
scanf("%i", &menu_selection);
switch (menu_selection)
{
case 1: year = year_info();
printf("%c", year);
break;
}
}
char year_info()
{
int year_input;
printf("\nYear: ");
scanf("%i", &year_input);
if (year_input > 2016 || year_input < 1920)
{
printf("Sorry, I do not recognize this command. Please try again.\n");
}
else
{
int year = year_input;
return year;
}
}
It doesn't run because you're passing scanf the variable, but you should pass the address of the variable, i.e. use:
scanf("%i", &something);
instead of scanf("%i", something);
Also, as others pointed out, you're mixing char and int too liberally, so it won't work as expected.
year and year_imput can't be chars because they won't hold values large enough, you'll need at least a short.
You had 2 errors.
scanf("%i", &menu_selection);
scanf("%i", &year_imput);
You need to use the & to pass the address of the variables to scanf().
Edit: However, I would have used an integer for that, because a scanf("%c", &something) will only recognize the first char you enter, and not the whole string, even if that happened you can't do if (year_imput > 2016 || year_imput < 1920) between strings, you can do that with chars, but again, they can only store one character, so I would have done your program like this.
#include <stdio.h>
int year_info();
int main() {
int menu_selection;
int year;
printf("Please choose from the following menu: \n1. Insert a new movie\n2. Show movie\n3. List all\n4. Exit\n");
scanf("%i", &menu_selection);
switch (menu_selection) {
case 1:
year = year_info();
printf("%i", year);
break;
default:
break;
}
return 0;
}
int year_info() {
int year_imput;
printf("\nYear: ");
scanf("%i", &year_imput);
if (year_imput > 2016 || year_imput < 1920) {
printf("Sorry, I do not recognize this command. Please try again.\n");
return 0;
}
else
return year_imput;
}

How do I search through a structure and display certain info after it has been entered by the user?

For my assignment I am to create a structure that allows the user to enter student info (ID, DOB, & Phone number). I have no problem doing this that is quite simple. Now I need to search through that enter info using the student ID to display that students corresponding DOB and phone number, this is the problem that I am having trouble working with. If you see any other problems with my program please let me know what is wrong and why I should change so I can learn from my mistakes.
Thank you.
#include <stdio.h>
#include <stdlib.h>
struct infoStruct
{
int studentID;
int year;
int month;
int day;
int phone;
int end;
};
int main (void)
{
int students = 0;
int infoArray [students];
struct infoStruct info;
int studentID;
int year;
int month;
int day;
int phone;
int end;
while (info.end != -1) {
students = students + 1;
printf("Enter student information (ID, day, month, year, phone)\n");
printf("Enter -1 following the phone number to end the process to continue enter 0\n");
scanf("%d %d %d %d %d %d", &info.studentID, &info.day, &info.month, &info.year, &info.phone, &info.end);
}
if (info.end = -1){
printf("You entered %d student(s)\n", students);
}
//Student Search
printf("Please enter the student ID of the student your looking for\n.");
scanf("%d", info.studentID);
printf(" DOB: %d %d %d, Phone: %d", info.month, info.day, info.year, info.phone);
}
info.end is not initialized before while (info.end != -1). Initiliaze all your variable (studentID...) and structure.
if (info.end = -1) is an assignment !
Use : if (info.end == -1) I prefer to use if (-1 == info.end) (if you had use : only = instead of == you would have get an error). (Yoda trick ^^)
And you have to use an array of struct in order to save every student (because you are continuously erasing the previous student information).
It's your homework, I won't do the work for you ;)
I'll leave most of the coding to you, as this is homework, but here is what you need to change to get this to work.
First of all, if you want to store multiple students info is going to need to be an array
static int MAX_STUDENTS = 50;
struct infoStruct info[MAX_STUDENTS];
and then you scan each student into a seperate part of the struct
scanf("%d %d %d %d %d %d", &info[students-1].studentID, &info[students-1].day, &info[students-1].month, &info[students-1].year, &info[students-1].phone, &info[students-1].end);
then you need to ensure that the end condition is checked properly (check the latest info[x].end)
It would also be wise to check you still have some room in the array before trying to add more.
with those done you are storing the students correctly.
as for searching, you need to scan the id to search into a seperate int.
then loop through the array (info[x]) and search each element's studentID against the search ID. When you have a match, print it out.
Edit:
its also worth considering storing the phone number as a "string" rather than an int, alot of phone numbers start with "0", but an int would remove the 0.
(so the phone number 012345, would become, 12345)

Taking in unique inputs in a struct array in C

I am writing a program to create a structure named 'student'. I need to input various data about a particular student. Here is my program till now.
#include<stdio.h>
#include<stdlib.h>
struct student
{
char* name;
int id;
float marks_1;
float marks_2;
};
void main()
{
int num, var_i, var_j, var_k, var_l, duplicated_id = 0;
printf("Enter number of students\n");
scanf("%d", &num);
struct student s[num];
printf("Enter the data for the students\n");
for (var_i = 0; var_i < num; var_i++)
{
var_j = var_i + 1;
printf("Enter name of student_%d\n", var_j);
scanf(" %[^\n]%*c", &s[var_i].name);
printf("Enter id of student_%d\n", var_j);
scanf("%d", &s[var_i].id);
for (var_k = 0; var_k < var_i; var_k++)
{
if (s[var_k].id == s[var_i].id)
{
printf("Duplicate Id, program will exit");
return;
}
}
printf("Enter marks(sub_1) of student_%d\n", var_j);
scanf("%d", &s[var_i].marks_1);
printf("Enter marks(sub_2) of student_%d\n", var_j);
scanf("%d", &s[var_i].marks_2);
}
}
In the following for loop I am checking all the previously entered 'id' values to check if there is a duplicate. In case of a duplicate, the program will exit.
for(var_k=0;var_k<var_i;var_k++)
{
if(s[var_k].id==s[var_i].id)
{
printf("Duplicate Id, program will exit");
return;
}
}
Now instead of exiting the program I want to prompt the user to enter a different value. This goes on till he enters a unique value. How should I do it?
Any help appreciated.
This is wrong:
scanf(" %[^\n]%*c", &s[var_i].name);
You're passing the address of the pointer member name (i.e. you're passing a char **) to scanf() which per the format string, is expecting a char* and enough memory to hold the data it subsequently reads. This is invalid, is undefined behavior, and blindly overwrites data in the s[] array. Frankly I'm amazed this doesn't seg-fault your process.
Change this:
struct student
{
char* name;
int id;
float marks_1;
float marks_2;
};
To this:
struct student
{
char name[128]; // or some other suitable size.
int id;
float marks_1;
float marks_2;
};
And change this:
scanf(" %[^\n]%*c", &s[var_i].name);
To this:
scanf(" %[^\n]%*c", s[var_i].name);
I strongly suggest a size-limiter on that scanf() call as well, but I leave that to you to discover. Read about the API here.
Just use a loop.
here is some psudocode
bool isDuplicate = false
do
{
GetInput()
isDuplicate = CheckForDuplicate()
}while(isDuplicate);

Resources