pointer of struct and pointer inside that struct - c

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]) );

Related

Wrong int values using struct and arrays [duplicate]

This question already has answers here:
What will happen if '&' is not put in a 'scanf' statement?
(6 answers)
Closed 4 years ago.
Hello I have a problem with integer. This is my code:
#include <stdio.h>
#include <stdlib.h>
struct data
{
char name[50];
int grade[1];
};
int main()
{
struct data persons[30];
int n = 3;
int i;
for(i=0;i<n;i++)
{
printf("Type person name nr: [%d] ",i+1);
scanf("%s",persons[i].name);
printf("Type grade: (from 1 to 6) ");
scanf("%d",persons[i].grade);
}
for(i=0;i<n;i++)
{
printf("Name [%d]: %s\n",i+1,persons[i].name);
printf("Grade [%d]: %d\n",i+1,persons[i].grade);
}
return 0;
}
And when I type some names and grades the output isn't correct:
This is my output
You are using an array for a single grade, when a standard int is enough.
struct data
{
char name[50];
int grade;
};
And then you also need to pass the reference of the int to scanf using an &.
scanf("%d", &persons[i].grade);
The corrected version of your program:
#include <stdio.h>
#include <stdlib.h>
struct data {
char name[50];
int grade; // In you case, to store one integer value just use int varibale because it seems more logical.
};
int main() {
struct data persons[30];
int n = 3;
int i;
for (i = 0; i < n; i++) {
printf("Type person name nr: [%d] ", i + 1);
scanf("%s", persons[i].name);
printf("Type grade: (from 1 to 6) ");
scanf("%d", &persons[i].grade); // To fill member of structure you may use '&' sign because scanf gets address.
}
for (i = 0; i < n; i++) {
printf("Name [%d]: %s\n", i + 1, persons[i].name);
printf("Grade [%d]: %d\n", i + 1, persons[i].grade);
}
return 0;
}
Also, keep in mind that compiler not always tell you that something is going to be wrong, in most cases using special flags (some of them I mentioned in the comment) for compiler can give you more information.
It's worth to note that current IDEs highlight obvious errors and really speed up your development process.
It's because grade is an array, so you need to do .grade[0]when writing or reading data to / from it, like so:
scanf("%d",persons[i].grade[0]);
...
printf("Grade [%d]: %d\n",i+1,persons[i].grade[0]);
you have to replace
printf("Grade [%d]: %d\n",i+1,persons[i].grade);
by
printf("Grade [%d]: %d\n",i+1,persons[i].grade[0]);
in the scanf you do scanf("%d",persons[i].grade); so because grade is a vector you give its address, but in the printf you have to specify the index else you print the address of the vector
However to use a vector is useless because it contains only one element, better to directly use an int for grade, and of course in that case you have to give &persons[i].grade for the scanf and persons[i].grade for
the printf
Execution :
Type person name nr: [1] a
Type grade: (from 1 to 6) 1
Type person name nr: [2] b
Type grade: (from 1 to 6) 2
Type person name nr: [3] c
Type grade: (from 1 to 6) 3
Name [1]: a
Grade [1]: 1
Name [2]: b
Grade [2]: 2
Name [3]: c
Grade [3]: 3

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);

Searching for a match in a structure array

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){
....
}

Array of Structures in C. not linked list

I am having trouble making an array of structures. I want to store data regarding multiple students and take input using the execution of the program. Then output the memory address of persons name with highest marks.
I tried getting to know the answers on similar issues on site, to no help.
The code I have written is
the struct
struct student{
char name;
int marks;
};
and the function is
int num,max = 0,i;
printf("Number of students?\n");
scanf("%d", &num);
struct student* students = (struct student*)malloc (num* (sizeof(struct student)));
for (int x = 0; x < num; x++)
{
printf("Enter Name\n");
scanf("%c" , &students[x].name);
printf("Enter Marks\n");
scanf ("%d" , &students[x].marks);
}
for (i = 1; i < num; i++)
{
if (students[max].marks<students[i].marks)
{
max = i;
}
}
printf("The Memory Add for %c is %p\n", students[max].name , &students[max].name );
It is a part of menu driven program. It goes into a weird loop after line 5 in function code. And i can't create a doubly linked list for the same.
Edit 1
These are the changes i made to struct and func
struct student{
char name[20];
int marks;
};
void memadd(){
int num,max = 0,i, mark;
printf("Number of students?\n");
scanf("%d", &num);
struct student* students = (struct student*)malloc (num* (sizeof(struct student)));
for (int x = 0; x < num; x++)
{
printf("Enter Name\n");
scanf("%s" , &students[x].name);
printf("Enter Marks\n");
scanf ("%d" , &mark);
students[x].marks = mark;
}
for (i = 1; i < num; i++)
{
if (students[max].marks<students[i].marks)
{
max = i;
}
}
printf("The Memory Add for %s is %p\n", students[max].name , &students[max].name );
It is giving an array at input of the name. "format specifies type 'char ' but the argument has
type 'char ()[20]'"
How do I make the format to be char * [20]?
Edit 2
The final working code after correcting the char name to being a character array
And issue with scanning of names.
struct student{
char name[20];
int marks;
};
int num,max = 0,i, mark;
printf("Number of students?\n");
scanf("%d", &num);
struct student* students = (struct student*)malloc (num* (sizeof(struct student)));
for (int x = 0; x < num; x++)
{
printf("Enter Name\n");
scanf("%19s" , students[x].name);
printf("Enter Marks\n");
scanf ("%d" , &mark);
students[x].marks = mark;
}
for (i = 1; i < num; i++)
{
if (students[max].marks<students[i].marks)
{
max = i;
}
}
printf("The Memory Add for %s is %p\n", students[max].name , &students[max].name );
However, what if I wish to print the address in Hex numbers? or the one that am getting is hex already.?
Because I got an output of The Memory Add for XYZ is 0x7fb340c03928
The problem is with the student name being a char and
scanf("%c" , &students[x].name);
What happens is, you read in the number of students with
scanf("%d", &num);
Now you have read num, but there is still a newline in the input buffer.
Then you try to read a character with %c, but this reads the remaining newline.
When you change the student's name to a character array, e.g.
struct student{
char name[20];
int marks;
};
and read the name with
scanf("%19s" , students[x].name);
it will skip the remaining whitespace/newline and read the name as it should.

C : program to calculate GPA for students

Whenever I insert 2 or more students, the program gives the same gpa from the first student. I insert for both every time, and how can I display the max gpa and who got it?
#include <stdio.h>
FILE *f;
struct student
{
char name[20];
int id;
int n;
float sum;
float gpa;
} s[100];
float FUN_GPA(int n);
int main ()
{
int m,i,x,b;
float max=0;
s[i].sum=0;
printf("Please Enter Number Of Students : ");
scanf("%d",&m);
for(i=0;i<m;i++)
{
printf("\nStudent %d : \n",i+1);
printf("Name : ");
scanf("%s",&s[i].name);
printf("ID : ");
scanf("%d",&s[i].id);
printf("Number Of Courses : ");
scanf("%d",&s[i].n);
}
printf("\nEnter Student Marks");
for(i=0;i<m;i++)
{
printf("\n\n\t\t\t......[ Student %d ]......\n",i+1);
for(x=0;x<s[i].n;x++)
{
printf("Course %d Mark : ",x+1);
scanf("%d",&b);
s[i].sum+=b;
}
printf("\nSum Of The Courses Marks = %3.f",s[i].sum);
printf("\nGPA For Student %d = %f",i+1,FUN_GPA(s[i].gpa));
}
if (s[i].gpa>max)
max=s[i].gpa;
printf("\n\nHighest GPA is done by Student %d with GPA = %f",i,max);
{
if((f=fopen("d:\\STUDENTS.txt","w"))==NULL)
printf("\ncant open file ");
// if((f=fopen("d:\\STUDENTS.txt","r"))==NULL)
// printf("\ncant open file ");
fprintf(f,"Name : %s\t ID : %d\t GPA = %f \n",s[i].name,s[i].id,s[i].gpa);
fclose(f);
}
}
float FUN_GPA(int i)
{
s[i].gpa=0;
s[i].gpa=s[i].sum/s[i].n;
return s[i].gpa;
}
Replace FUN_GPA(s[i].gpa) by FUN_GPA(i).
Put this inside the loop; not much use having it outside:
if (s[i].gpa>max)
max=s[i].gpa;
The same applies to this initializer, by the way:
s[i].sum=0;
In general, do not use variable i outside the loop; this is bad practice and in your particular case, totally wrong!
i is not the index of the best performing student; it is not even a correct index once the loop ends, since it refers to the array element immediately following the last registered student. Please introduce a new variable to keep track of the index of the best performer so far. Instead of i, use this new variable in the lines to follow:
fprintf(f,"Name : %s\t ID : %d\t GPA = %f \n",s[i].name,s[i].id,s[i].gpa);
Same here; do not forget to add 1 like you did everywhere else already!
printf("\n\nHighest GPA is done by Student %d with GPA = %f",i,max);
General advice: use descriptive names. i is OK afaic; s and n are not so great, m, x and b would have been good for 50 lashes from my old teachers for sure!
This needs to be in a for loop (you're only checking one as it is currently written):
if (s[i].gpa>max)
max=s[i].gpa;
You'll probably also want to keep track of which i had the max.
So something like:
int iwithmax;
for ( i = 0 ; i < m ; i++) {
if (s[i].gpa > max) {
max = s[i].gpa;
iwithmax = i;
}
}
and change print statement accordingly:
printf("\n\nHighest GPA is done by Student %d with GPA = %f",iwithmax,max);

Resources