Searching for a match in a structure array - c

I've been at this mess for a while and I still haven't figured out where I'm going wrong with it, totally knifing myself if it's something ridiculous like a pointer.
Task shown: Trying to fill a structure array with student ID, name, last name, date of birth, and grades.. Then search by a matching ID that's given to the user.
I'd highly appreciate any help related to this subject, I've been seriously stuck at it for a while. Also I apologize in advance for the french parts
// Part 1
struct Date{
int day;
int month;
int year;
};
// Part 2
struct Student{
int ID;
char name[20];
char lastname[20];
struct Date DOB;
int notes[J];
};
// Part 3
void FillStudentList(struct Student E){
int i;
printf("\nInsert ID: ");
scanf("%d", &E.ID);
printf("Insert name: ");
scanf("%s", &E.name);
printf("Insert last name: ");
scanf("%s", &E.lastname);
printf("Insert date of birth: ");
scanf("%d %d %d", &E.DOB.day, &E.DOB.month, &E.DOB.year);
printf("Insert notes: ");
for(i=0; i<J; i++)
scanf("%d", &E.Notes[i]);
}
// Part 4
void ShowByNb(int Nb, struct Student E[], int NbStudents){
int j, i;
for(i=0; i<NbStudents; i++){
if (E[i].ID== Nb){
printf("\nID: %d", E[i].ID);
printf("\nName: %s", E[i].name);
printf("\nLast Name: %s", E[i].lastname);
printf("\nDate Of Birth: %s-%s-%s", E[i].DOB.day, E[i].DOB.month, E[i].DOB.year);
printf("\nNotes: ");
for(j=0; j<J; j++){
printf("%d", E[i].Notes[j]);
}
}
else
printf("\nInvalid Student!\n");
}
}
// Part 5
void main(){
int i, x;
struct Student E[N];
for(i=0; i<N; i++){
printf("\n\nStudent #%d", i+1);
FillStudentList(E[i]);
}
printf("\n\nSearch student by NB: ");
scanf("%d", &x);
ShowByNb(x, E, N);
}

The edited code below, I believe, achieves your goal. The main problem (other than reading/printing 'int's with '%s' was how you pass your structure to your functions. It is necessary to pass the structure by reference so that its values can be seen outside of the FillStudentList function; see this link.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define N 2
#define J 2
// Part 1
struct Dat{
int jour;
int mois;
int annee;
};
// Part 2
struct Etudiant{
int numero;
char nom[20];
char prenom[20];
struct Dat DDN;
int Notes[J];
};
// Part 3
/* Modified this so that a pointer to the struct is passed instead of a copy of the struct */
void FillStudentList(struct Etudiant *E){
int i;
printf("\nInsert ID: ");
scanf("%d", &E->numero);
printf("Insert name: ");
scanf("%s", E->nom);
printf("Insert last name: ");
scanf("%s", E->prenom);
printf("Insert date of birth: ");
/* These are integers. Do not read with %s */
scanf("%d %d %d", &E->DDN.jour, &E->DDN.mois, &E->DDN.annee);
printf("Insert notes: ");
for(i=0; i<J; i++)
scanf("%d", &E->Notes[i]);
}
// Part 4
void ShowByNb(int Nb, struct Etudiant E[]){
/* Don't redefine N == NbEtudiants making it seem that N is variable */
int j, i;
for(i=0; i<N; i++){
if (E[i].numero == Nb){
printf("\nID: %d", E[i].numero);
printf("\nName: %s", E[i].nom);
printf("\nLast Name: %s", E[i].prenom);
/* Again, can't print integers with %s */
printf("\nDate Of Birth: %d-%d-%d", E[i].DDN.jour, E[i].DDN.mois, E[i].DDN.annee);
printf("\nLes notes: ");
for(j=0; j<J; j++){
printf("%d ", E[i].Notes[j]);
}
return;
}
/* Your previous else would print invalid student every time you ran through the loop even
* if the student number was valid for a later student.
*/
}
/* Only print this if student was not found in any of the N Student structures */
printf("\nInvalid Student!\n");
}
// Part 5
void main(){
setbuf(stdout, NULL);
int i, x;
struct Etudiant E[N];
for(i=0; i<N; i++){
printf("\n\nStudent #%d", i+1);
FillStudentList(&E[i]);
}
printf("\n\nSearch student by NB: ");
scanf("%d", &x);
ShowByNb(x, E);
}
Input
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2
Output
Student #1
Insert ID: 1
Insert name: 1
Insert last name: 1
Insert date of birth: 1
1
1
Insert notes: 1
1
Student #2
Insert ID: 2
Insert name: 2
Insert last name: 2
Insert date of birth: 2
2
2
Insert notes: 2
2
Search student by NB: 2
ID: 2
Name: 2
Last Name: 2
Date Of Birth: 2-2-2
Les notes: 2 2

classic mistake: passing parameter by value instead of by reference:
void FillStudentList(struct Student E){
.....
}
What happens here is that a local copy of your structure is created on the stack, populated with whatever the input is and destroyed when the function exits.
Generally in C, even if you don't want to modify the structure, you pass struct parameters by pointer; if you pass them by value each member of the structure is copied on to the stack...which is a waste of time an memory.
So changing the function prototype (and the code to work with the new signature) should fix the issue:
void FillStudentList(struct Student *E){
....
}

Related

pointer of struct and pointer inside that struct

I have a problem in which there is a struct that will hold the name, age and student id. I have to take an input from the user and make that number of structs without using any array notation. And then each of the struct's parameters should be taken input from the user and printed at the same time. It is like creating a database of students.
The struct is:
typedef struct
{
char *name;
char *std_id;
int age;
} student;
So my input would be like :
Number of students: 3
Name of the student1: Bro
std_id of the student1: 46845
age of the student1: 18
Name of the student2: kim
std_id of the student2: 46867
age of the student2: 19
Name of the student3: Sean
std_id of the student3: 46862
age of the student3: 18
And the output would be like:
Name of the student1 is: Bro
std_id of the student1 is: 46845
age of the student1 is: 18
Name of the student2 is: kim
std_id of the student2 is: 46867
age of the student2 is: 19
Name of the student3 is: Sean
std_id of the student3 is: 46862
age of the student3 is: 18
The main problem is we can't use any array in this problem.
What I tried coding the problem by searching the internet is this code:
#include<stdio.h>
#include<string.h>
typedef struct
{
char *name;
char *std_id;
int age;
} students;
int main()
{
int num;
printf("Type the number of students:");
scanf("%d", &num);
students* ptr = malloc(num * sizeof(*ptr));
if(ptr == NULL)
{
printf("memory not free!");
return 0;
}
for(int i=0; i<num; i++)
{
printf("\nGive the name of the std %d:", i+1);
(ptr+i)->name = malloc(sizeof(char)*20);
if((ptr+i)->name == NULL)
{
printf("memory not free!");
return 0;
}
scanf("%s", (ptr+i)->name);
printf("Give the std_id of the std %d:", i+1);
(ptr+i)->std_id = malloc(sizeof(char)*10);
if((ptr+i)->std_id == NULL)
{
printf("memory not free!");
return 0;
}
scanf("%s", (ptr+i)->std_id);
printf("Give the age of std %d:", i+1);
scanf("%d", (ptr+i)->age);
}
for(int i=0; i<num; i++)
{
printf("\nThe name of the std %d: %s", i+1, (ptr+i)->name);
printf("\nThe std_id of the std %d: %s", i+1, (ptr+i)->std_id);
printf("\nThe age of the std %d: %d", i+1, (ptr+i)->age);
}
return 0;
}
Using this code, this is what my console looks like:
Type the number of students:3
Give the name of the std 1:Sean
Give the std_id of the std 1:45
Give the age of std 1:23
Process returned -1073741819 (0xC0000005) execution time : 23.131 s
Press any key to continue.
Here I am trying to first run the code for name variable. If that runs correctly, I'll implement the other variables like name variable. But when I run this code the the program exits after taking just one input. I just can not figure out the problem by my own. Any help on how to tackle this problem will be highly appreciated.
students* ptr = malloc((sizeof(int) + sizeof(char) * 50) * num);
This doesn't make any sense at all and I don't even understand what you are trying to do. If you wish to allocate an array of structs then you have to do:
students* ptr = malloc(num * sizeof(*ptr));
or equivalent:
students* ptr = malloc( sizeof(students[num]) );

How to use Structures to print this output in C program?

Output Should be:
Please enter employee's id: 1
Please enter your full name: Jane Doe
Please enter employee's salary: 98500.9718
Employee 1 is set successfully
Please enter employee's id: 2
Please enter your full name: John Doe
Please enter employee's salary: 96500.8723
Employee 2 is set successfully
Employee 1
Name - Jane Doe
Salary - 98500.97
Employee 2
Name - John Doe
Salary - 96500.87`
My Code:
#include <stdio.h>
#include <string.h>
#define SIZE 2
struct Employee
{
int id;
char fullName[32];
double salary;
};
void setEmployee(struct Employee *);
void getFullName(char *);
void getId(int *);
void setSalary(double *);
void printEmployee(const struct Employee *);
void flushKeyboard()
{
while (getchar() != '\n');
}
int main(void)
{
struct Employee Employees[SIZE];
int i = 0;
for (i = 0;i < SIZE;i++)
{
setEmployee(Employees);
}
for (i = 0;i < SIZE;i++) {
printEmployee(Employees);
}
return 0;
}
void setEmployee(struct Employee *employee1)
{
getId(&employee1->id);
getFullName(&employee1->fullName);
setSalary(&employee1->salary);
printf("Employee %d is set successfully\n\n", (employee1->id));
}
void getFullName(char *name1)
{
printf("Please enter your full name: ");
scanf(" %31[^\n]", name1);
flushKeyboard();
}
void getId(int *identity)
{
printf("Please enter employee's id: ");
scanf("%d", &identity);
}
void setSalary(double *salary)
{
printf("Please enter employee's salary: ");
scanf("%lf", salary);
}
void printEmployee(const struct Employee *final)
{
printf("Employee: %d\n", final->id);
printf("Name: %s\n", final->fullName);
printf("Salary: %.2lf\n\n", final->salary);
}
After running this whole code, my output only shows the values that the user enters for the second for loop.
So the values will be the same. The employee number, Name and salary will be same instead of giving me 2 seperate values that user enters.
My question is why does it keep giving me same value?
I would use a for loop but i am not allowed to use a for loop for some reason.
for (i = 0;i < SIZE;i++) { printEmployee(Employees); }
Here you have forgotten to use your counting variable->
for (i = 0;i < SIZE;i++) { printEmployee(&Employees[i]); }
What happens when you pass the whole array like that is, that the array decayes to a pointer to the first element in the array which is fine for the function because it expects a pointer to an Employee struct. But then it only prints the first enployee in the array.

Sorting an incrementing list in C

I am trying to create a list of employees and sort the list based on age each time I add a new employee. The problem I am having is that only a list of 1 employee is "sorted". If I add another employee suddenly all of the ages become 0. Here is my code:
#include <stdio.h>
#include <string.h>
#include "employee.h"
int i = 0;
unsigned int employee_get_num (struct employee* list)
{
unsigned int i;
for (i=0; list[i].name[0]; i++);
return i;
}
void employee_sort (struct employee* list)
{
int n = i;
int I, j;
int tmp;
printf("There are %d employees\n", n);
for(I=0; I<n; I++)
printf("Age: %d\n", list[i-1].age);
for(I=0; I<(n-1); I++)
for(j=0; j<n-I-1; j++)
if(list[j].age > list[j+1].age){
tmp = list[j].age;
list[j].age = list[j+1].age;
list[j+1].age = tmp;
}
printf("Sorted list:\n");
for(I=0; I<n; I++)
printf("%d\n", list[i-1].age); // only printing zeros for some reason
}
void employee_add (struct employee* list)
{
i = i+1; // i is global, keeps track of employees
char first[128];
char last[128];
char space[] = " ";
printf ("First Name: ");
scanf ("%s", first);
printf("Last Name: ");
scanf ("%s", last);
// Concatenate first and last name into one string
strcpy(list[i-1].name, first);
strcat(list[i-1].name, space);
strcat(list[i-1].name, last);
printf (" Age: ");
scanf("%u", &(list->age));
printf ("Wage: ");
scanf("%u", &(list->wage));
employee_sort(&list[i-1]);
}
I think that I might not be increasing correctly.
Header file:
#ifndef _employee_h_
#define _employee_h_
struct employee {
char name[128];
unsigned int age;
unsigned int wage;
};
unsigned int employee_get_num (struct employee* list);
void employee_print (struct employee* e);
void employee_print_all (struct employee* list);
void employee_sort (struct employee* array);
void employee_add (struct employee* list);
void employee_delete (struct employee* list);
#endif
main() (in menu.c)
int main (unsigned int argc, char** argv)
{
struct employee list[MAX];
unsigned int running = 1;
/* Set all bits in the employee array to zero */
memset (list, 0, MAX*sizeof(struct employee));
while (running) {
switch (print_menu()) {
case OPTION_ADD:
employee_add(list);
break;
case OPTION_DEL:
employee_delete(list);
break;
case OPTION_LIST:
employee_print_all(list);
break;
case OPTION_QUIT:
running = 0;
break;
};
}
return 0;
}
I left out the rest of menu.c because it only prints the menu which you'll see below.
The output should look like:
[1] Add New Employee
[2] Delete an Employee
[3] List All by Age (Acending)
[4] Quit
------------------------
Selection: 1
First Name: Bob
Last Name: Smith
Age: 40
Wage: 60000
There are 1 employees
Age: 40
Sorted list:
40
[1] Add New Employee
[2] Delete an Employee
[3] List All by Age (Acending)
[4] Quit
------------------------
Selection: 1
First Name: John
Last Name: Connor
Age: 35
Wage: 62000
There are 2 employees
Age: 40
Age: 35
Sorted list:
35
40
I added some extra print statements just to show what it is supposed to be doing.
I'm also worried that it is only going to sort the age and not the rest of the information
Firstly in employee_add when calling employee_sort you are passing the last struct element. Pass the first employee. Change last line in employee_add to
employee_sort(list);
Next problem
If I add another employee suddenly all of the ages become 0
No it doesn't. In employee_sort in the for loop before sorting, change it to
printf("There are %d employees\n", n);
for(I=0; I<n; I++)
printf("Age: %d\n", list[I].age);
Next
While taking age and wage input change it to
scanf("%u", &(list[i-1].age));
scanf("%u", &(list[i-1].wage));
I'm also worried that it is only going to sort the age and not the rest of the information
Yes you are only sorting age, you should sort whole struct based on age.
for(I=0; I<(n-1); I++)
for(j=0; j<n-I-1; j++)
if(list[j].age > list[j+1].age){
tmp = list[j];
list[j] = list[j+1];
list[j+1] = tmp;
}
And the final problem of printing sorted list
printf("Sorted list:\n");
for(I=0; I<n; I++)
printf("%d\n", list[I].age);
PS Note the list[I] in every printf and not list[i+1]
Edit
Instead of sorting it yourself, you can use qsort biult in function in stdlib.h header file.
Implementation: You will need to define a comparator function as you dont have a traditional array to sort
Just define a function
int comparator(const struct employee *p, const struct employee *q)
{
int l = p->age;
int r = q->age;
return (l - r);
}
And then where you sort the list call qsort like this
qsort(list,i,sizeof(list[0]),comparator);

C: Array of Structs (Input into int array within array of structs)

Hi I have to create a database that stores students number, name and also stores an array of course marks (1-N) in C Programming Language.
Everything worked until I started coding for the array of course marks. Then every time I compiled the code it kept crashing as soon as it asked to input the course marks.
Can you please tell me where I'm going wrong in my programming for this task? I have attached it to this message.
The program worked for inputting the name, student number, however I could not get the program to input array of marks. I have asked how many course marks to be entered and then used a for loop within the "void insert(void)" function to keep inputting the course marks into the array *marks. I am referring specifically to lines 24 to 30 in my programming code.
Always at this point the program kept crashing and I could not proceed further to enter more names or print the stored student details.
I think there is a problem with this part:
for (i= 0; i < num_marks; i++)
{
printf("Enter Course Mark: \n");
scanf("%d", &(list[num_students].marks[num_marks]));
}
Anyway here is the full code:
#include <stdio.h>
#include <string.h>
struct student{
int number;
char name[10];
int marks[5];
};
struct student list[10];
int num_students = 0;
int num_marks = 0;
int *p;
void insert(void)
{
int student_number;
int i;
printf("Enter number: \n");
scanf("%d", &list[num_students].number);
printf("Enter NAME: \n");
scanf("%s", &list[num_students].name);
printf("Enter NO of courses: \n");
scanf("%d", num_marks);
for (i= 0; i < num_marks; i++)
{
printf("Enter Course Mark: \n" );
scanf("%d", &(list[num_students].marks[num_marks]));
}
num_students++; // HOW DO WE INPUT ARRAY MARKS??? MARK1: , MARK2: , MARK3 ,
}
void printtest(void)
{
int i;
for (i=0; i < num_students; i++)
{
printf("Name: \n");
puts(list[i].name);
printf("Number: %d \n", list[i].number);
printf("Mark: %d /100 \n", list[i].marks);
printf("\n");
}
}
int main(void)
{
int code;
int opt1;
int courses, i, k, j, counter;
for (;;){
printf("Enter operation code: \n");
printf("(1) ADD NEW STUDENT DETAILS: \n");
printf("(2) DISPLAY REPORT OF ALL STUDENTS: \n");
scanf(" %d", &code);
switch (code){
case 1 :
insert();
break;
case 2 :
printtest();
break;
default:
printf("Illegal code\n");
printf("\n");
}
}
}
Apart from what others pointed out, I'd like to draw your attention towards the following:
void insert(void)
{
int student_number;
int i;
printf("Enter number: \n");
scanf("%d", &list[num_students].number);
printf("Enter NAME: \n");
scanf("%s", &list[num_students].name);
printf("Enter NO of courses: \n");
scanf("%d", num_marks);
for (i= 0; i < num_marks; i++)
{
printf("Enter Course Mark: \n" );
scanf("%d", &(list[num_students].marks[num_marks]));
}
num_students++;
}
void printtest(void)
{
int i;
for (i=0; i < num_students; i++)
{
printf("Name: \n");
puts(list[i].name);
printf("Number: %d \n", list[i].number);
printf("Mark: %d /100 \n", list[i].marks);
printf("\n");
}
}
There are three problematic statements:
scanf("%s", &list[num_students].name); This is why beginners should use compilers with all warnings enabled.
printf("Mark: %d /100 \n", list[i].marks); What did you declare marks as in the first place?
scanf("%d", num_marks); Seems like you put & operator where not needed and ignore where needed. Read your textbook before asking a question next time.
Seems like you're having a tough time understanding the concept of arrays and pointers. Read your text book thoroughly before venturing into the world of pointers. If you don't use them correctly, even compiler can't help you.
Also, even if I don't expect your program to have a robust input mechanism, at least array bounds checking is expected. Learn good habits from the beginning. They'll save a lot of your time while debugging later.
Seems to be an error in:
for (i= 0; i < num_marks; i++)
{
printf("Enter Course Mark: \n" );
scanf("%d", &(list[num_students].marks[num_marks]));
}
The crash is probably because num_marks as index indexes beyond the array. Change to:
for (i= 0; i < num_marks; i++)
{
printf("Enter Course Mark: \n" );
scanf("%d", &(list[num_students].marks[i]));
}

Data Structures/Records

My current program looks like this. This program should ask 5 records of a person and display them.
#include<stdio.h>
struct rec {
char name[100],address[100];
double age,mobileno;
}x;
main()
{
int i;
clrscr();
for(i=1;i<=5;i++)
{
printf("Enter Your Name: ");
scanf("%s",&x.name);
printf("Enter Your Age: ");
scanf("%lf",&x.age);
printf("Enter Your Address: ");
scanf("%s",&x.address);
printf("Enter Your Mobile No.: ");
scanf("%lf",&x.mobileno);
}
printf("\n\nThe Information has been added");
printf("\n\nNAME AGE ADDRESS MOBILE NUMBER");
for(i=1;i<=5;i++)
{
printf("\n%s %.0lf %s %.0lf",x.name,x.age,x.address,x.mobileno);
}
getch();
}
I have a problem in displaying the 5 different record. How do I display the five records in one printf?
You simply need a collection of structures to save the data into, currently you're just overwriting the data each time. There are a lot of ways to do this, but you could do something like use a static array, for example:
struct rec {
char name[100],address[100];
double age,mobileno;
};
int main() {
struct rec records[5];
for(i=0;i<5;i++) // <-- note this is 0 to 4, not 1 to 5
{
printf("Enter Your Name: ");
scanf("%s",records[i].name); // <-- don't add the & for the string input
Same for the printf() further down:
for(i=0; i<5; i++)
{
printf("Name is: %s\n", records[i].name);

Resources