I have an assignment of dynamic allocation for an array of structs.
I'm having trouble to understand/explain why I need pointer to pointer and not like with regular array only pointer,
Maybe someone can explain?
The code as following
i added the whole code including main function.
struct Date {
int year;
int month;
int day;
};
struct Student {
char name[100];
float grades;
float points;
int id;
struct Date birth_date;
};
struct Student** get_student_data(int* number_of_student)
{
printf("how many students in your class? ");
scanf("%d", number_of_student);
struct Student** student_pointers_array = malloc(sizeof(struct Student*) * *number_of_student);
if (student_pointers_array == NULL)
return;
struct Student* student_array = malloc(sizeof(struct Student) * *number_of_student);
if (student_array == NULL)
return;
for (int i = 0; i < *number_of_student; i++)
{
printf("Enter Name\n");scanf(" %[^\n]s", &student_array[i].name);
printf("Enter Grades\n");scanf("%f", &student_array[i].grades);
printf("Enter Points\n");scanf("%f", &student_array[i].points);
printf("Enter ID\n");scanf("%d", &student_array[i].id);
printf("Enter year\n");scanf("%d", &student_array[i].birth_date.year);
printf("Enter month\n");scanf("%d", &student_array[i].birth_date.month);
printf("Enter day\n");scanf("%d", &student_array[i].birth_date.day);
student_pointers_array[i] = &student_array[i];
}
return student_pointers_array;
}
void print_student_data(struct Student** student_data, int number_of_student)
{
for (int i = 0; i < number_of_student; i++)
{
printf("name: %s\n", student_data[i]->name);
printf("average: %f\n", student_data[i]->grades);
printf("academic points: %f\n", student_data[i]->points);
printf("ID: %d\n", student_data[i]->id);
printf("birth year: %d\n", student_data[i]->birth_date.year);
printf("birth month: %d\n", student_data[i]->birth_date.month);
printf("birth day: %d\n", student_data[i]->birth_date.day);
}
}
void main()
{
int number_of_student = 0;
struct Student** student_data = get_student_data(&number_of_student);
if (student_data == NULL)
return;
print_student_data(student_data, number_of_student);
free(student_data);
}
You don't need to use struct Student ** — you can use a single level of pointers, like this:
#include <stdio.h>
#include <stdlib.h>
struct Date
{
int year;
int month;
int day;
};
struct Student
{
char name[100];
float grades;
float points;
int id;
struct Date birth_date;
};
static
struct Student *get_student_data(int *number_of_student)
{
printf("how many students in your class? ");
scanf("%d", number_of_student);
struct Student *student_array = malloc(sizeof(struct Student) * *number_of_student);
if (student_array == NULL)
return NULL;
for (int i = 0; i < *number_of_student; i++)
{
printf("Enter Name\n");
scanf(" %[^\n]s", student_array[i].name);
printf("Enter Grades\n");
scanf("%f", &student_array[i].grades);
printf("Enter Points\n");
scanf("%f", &student_array[i].points);
printf("Enter ID\n");
scanf("%d", &student_array[i].id);
printf("Enter year\n");
scanf("%d", &student_array[i].birth_date.year);
printf("Enter month\n");
scanf("%d", &student_array[i].birth_date.month);
printf("Enter day\n");
scanf("%d", &student_array[i].birth_date.day);
}
return student_array;
}
static
void print_student_data(struct Student* student_data, int number_of_student)
{
for (int i = 0; i < number_of_student; i++)
{
printf("name: %s\n", student_data[i].name);
printf("average: %f\n", student_data[i].grades);
printf("academic points: %f\n", student_data[i].points);
printf("ID: %d\n", student_data[i].id);
printf("birth year: %d\n", student_data[i].birth_date.year);
printf("birth month: %d\n", student_data[i].birth_date.month);
printf("birth day: %d\n", student_data[i].birth_date.day);
}
}
int main(void)
{
int number_of_student = 0;
struct Student* student_data = get_student_data(&number_of_student);
if (student_data != NULL)
{
print_student_data(student_data, number_of_student);
free(student_data);
}
return 0;
}
This simplifies the memory release, too. The code in the question leaks the array of structures (it only frees the array of pointers).
Related
I am learning structure and function and I'm trying to pass a pointer to structure as an argument. My code is to input student name,age and marks. This is my program
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct student {
char name[15];
int age;
double marks;
};
void display();
int main(){
struct student *s1;
s1 =(struct student *) malloc(sizeof(struct student));
for(int i=0; i<2; i++)
{
printf("\nEnter details of student %d\n\n", i+1);
printf("Enter name: ");
scanf("%s", s1->name);
printf("Enter age: ");
scanf("%d", &s1->age);
printf("Enter marks: ");
scanf("%f", &s1->marks);
}
display(&s1);
}
void display(struct student *s1){
printf("\nName\tAge\tMarks\n");
for(int i = 0; i<2;i++ )
{
printf("Name: %s",s1->name);
printf("\nAge: %d",s1->age);
printf("\nMarks: %.2lf",s1->marks);
}
}
the code runs but it gave a wrong outputs and garbage value. What did i do wrong?
There are several syntax error. I have included documentation in the code below.
Also, you are overwriting the content of s1 everytime when you are prompting user to input. Test it with two different data for example (name: "alex", age: 19, mark: 100.0 and name: "jason", age: 22, mark: 100.0) your program will output only the later.
To solve this, I would suggest you to allocate your student pointer before looping so that you have two distinct memory for each student and you wont overwrite them in this case.
Basically, each student struct is treated as an array and instead of s1->name you will dereference them as s1[i].name
display function declaration
void display(struct student *s1);
main function
int main()
{
int i;
struct student *s1;
s1 =(struct student *) malloc(sizeof(struct student) * 2); /* 2 = number of students */
for(i=0; i<2; i++)
{
printf("\nEnter details of student %d\n\n", i+1);
printf("Enter name: ");
scanf("%s", s1[i].name);
printf("Enter age: ");
scanf("%d", &s1[i].age);
printf("Enter marks: ");
scanf("%lf", &s1[i].marks); /* Instead of %f, it should be %lf */
}
display(s1); /* Instead of &, it should be s1 */
/* Free heap memory */
for(i=0; i<2; i++)
{
free(s1);
s1 = NULL;
}
return 0;
}
Display function, you need some modification in your display function as well
void display(struct student *s1)
{
int i;
printf("\nName\tAge\tMarks\n");
for(i = 0; i<2;i++ )
{
printf("%s\t",s1[i].name);
printf("%d\t",s1[i].age);
printf("%.2f\t",s1[i].marks); /* Instead of %.2lf, it should be %.2f */
printf("\n");
}
}
Struct for student
struct student
{
char name[15];
int age;
double marks;
};
I am quite new to programming. Memory allocation also, still confuses me. And our professor asked us to make an array of structures wherein users will input the array size. This is to know how many entries will the users enter in the telephone directory.
Here is it so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct TelDirectory {
char name[50];
char address[100];
char tel[20];
};
int main() {
int num, add, del, prev = 0;
char ask;
*//asking for the number of entries*
printf("Number of entries: ");
scanf(" %i", &num);
struct TelDirectory *entry[num];
Input(entry, prev, num);
Display(entry, num);
//Input and Displaying
void Input(struct TelDirectory *entry[], int prev, int num) {
int i;
for (i = prev; i < num; i++) {
entry[i] = (struct TelDirectory *)malloc(sizeof(struct TelDirectory) * num);
printf("\nEnter name (last, first, middle): ");
scanf(" %[^\n]", entry[i]->name);
printf("Enter address: ");
scanf(" %[^\n]", entry[i]->address);
printf("Enter telephone number: ");
scanf(" %[^\n]", entry[i]->tel);
}
void Display(struct TelDirectory *entry[], int num) {
int i, j;
printf("%i\n", num);
struct TelDirectory *temp;
temp = (struct TelDirectory *) malloc(sizeof(struct TelDirectory) * num);
for (i = 0; i < num; i++) {
for (j = i+1; j < num; j++) {
if (strcasecmp(entry[i]->name, entry[j]->name) > 0) {
temp = entry[i];
entry[i] = entry[j];
entry[j] = temp;
}
}
}
printf("\n\t\t\t\t\tInformation\n");
printf("------------------------------------------------------------------------------------------------\n");
printf("Name\t\t\t\t\tAddress\t\t\t\t\tTelephone Number\n");
printf("------------------------------------------------------------------------------------------------\n");
for (i = 0; i < num; i++) {
printf("%-30s\t\t%-30s\t\t%-30s\n", entry[i]->name, entry[i]->address, entry[i]->tel);
}
printf("------------------------------------------------------------------------------------------------\n");
}
And, we will also be asking the users if they will update the directory through either INSERTING more entries or DELETING entries. Is it possible to change the structure array size on run time?
I have been trying to allocate memory to the pointer variable but it keeps giving me errors or segmentation fault. How do i properly initialize the pointer variable to the course struct?
typedef struct {
char courseId[7];
char courseName[10];
} Course;
struct Student{
char firstName[10];
char lastName[10];
int studentId;
Course *course;
};
int main() {
int numStudents;
printf("How many students do you wish to register?: ");
scanf("%d", &numStudents);
struct Student *student[numStudents];
student[numStudents] = malloc(sizeof(*student[numStudents]));
student[numStudents]->course = malloc(sizeof*(numStudents * Course));
for (int i = 0; i < numStudents; i++) {
printf("Enter student #%d First Name: ", i+1);
scanf("%s", student[i]->firstName);
printf("Enter student Last Name: ");
scanf("%s", student[i]->lastName);
printf("Enter Student ID: ");
scanf("%d", &student[i]->studentId);
printf("Enter Course ID: ");
//student[i]->course = malloc(sizeof(*(student[i]->course)));
scanf("%s", student[i]->course->courseId);
printf("Enter Cousrse Name: ");
//student[i]->course = malloc(sizeof(*(student[i]->course)));
scanf("%s", student[i]->course->courseName);
}
for (int i = 0; i < numStudents; i++) {
printf("Student Name: %s %s\n", student[i]->firstName, student[i]->lastName);
printf("Student ID: %d\n", student[i]->studentId);
printf("Course Code: %s\n", student[i]->course->courseId );
printf("Course name: %s\n", student[i]->course->courseName);
free(student[i]->course);
}
You almost had it, there was a few corrections that needed to be made.
Course object in Student doesn't need to be a pointer. The array of Student structures need to be dynamically allocated then free'd later on. -> is used as a dereference operator but in your case [] is already dereferencing so you would use . instead of -> and when you allocate memory for the array of structures it needs to be the size of the structure multiplied by the number of structures. malloc(sizeof(struct Student)*numStudents);
typedef struct {
char courseId[7];
char courseName[10];
} Course;
struct Student{
char firstName[10];
char lastName[10];
int studentId;
Course course;
};
int main() {
int numStudents;
printf("How many students do you wish to register?: ");
scanf("%d", &numStudents);
struct Student* students = malloc(sizeof(struct Student)*numStudents);
for (int i = 0; i < numStudents; i++) {
printf("Enter student #%d First Name: ", i+1);
scanf("%s", students[i].firstName);
printf("Enter student Last Name: ");
scanf("%s", students[i].lastName);
printf("Enter Student ID: ");
scanf("%d", &students[i].studentId);
printf("Enter Course ID: ");
scanf("%s", students[i].course.courseId);
printf("Enter Cousrse Name: ");
scanf("%s", students[i].course.courseName);
}
for (int i = 0; i < numStudents; i++) {
printf("Student Name: %s %s\n", students[i].firstName, students[i].lastName);
printf("Student ID: %d\n", students[i].studentId);
printf("Course Code: %s\n", students[i].course.courseId );
printf("Course name: %s\n", students[i].course.courseName);
}
free(students);
return 0;
}
I tried to make minimal changes to your code.
I have a code like this for a student management system. The input function works fine but I haven't figured out why my output function stop immediately when i call it.( I know that i can not return a local array from a function in C, but i assign the array to a pointer and return that pointer, is it ok?)
Here is my code:
struct Student
{
char name[50];
char birth[25];
char gender[10];
float math, physics;
};
struct Student* input(int n, struct Student *p)
{
int i, id = 1;
struct Student s[n];
getchar();
for(i = 0; i < n; i++)
{
printf("Name: ");
fgets(s[i].name, 50, stdin);
s[i].name[strlen(s[i].name)-1] = '\0';
printf("Date of birth: ");
fgets(s[i].birth,25,stdin);
s[i].birth[strlen(s[i].birth)-1] = '\0';
printf("Gender: ");
fgets(s[i].gender,10,stdin);
s[i].gender[strlen(s[i].gender)-1] = '\0';
printf("Math = ");
scanf("%f", &s[i].math);
printf("Physics = ");
scanf("%f", &s[i].physics);
getchar();
}
p = s;
return p;
}
void outPut(int n, struct Student *p)
{
int i;
for(i = 0; i < n; i++)
{
printf("%s %s %s %f %f\n", p[i].name, p[i].birth, p[i].gender, p[i].math, p[i].physics);
}
}
int main()
{
int n;
struct Student *p, *p1;
int choice;
printf("-----------Student Management-----------");
printf("\n1. Add new students.\n2. Print student list.\n");
do
{
printf("Your choice = ");
scanf("%d", &choice);
switch(choice)
{
case 1:
printf("Number of students = ");
scanf("%d", &n);
input(n,p);
break;
case 2:
outPut(n,p);
break;
}
}
while(choice!=0);
return 0;
}
You are defining your array as a local variable. It means that it will no longer exist after the function ends. To avoid this, declare your array as a pointer and use malloc to initialize it:
struct Student *s = malloc(sizeof(Student) * n);
It will behave as a regular array and you will be able to use itself as the function return.
I am now learning malloc and nested structs. I have one problem however. When I print out a member of a struct I also get other variables from another nested struct. The code below is what I have.
structs.h
struct course_info{
char *name[20];
int *course_id;
int *count;
};
struct student_info{
char *last[20];
char *first[20];
int *student_id;
int count;
};
typedef struct gradebook_info{
struct course_info course;
struct student_info student;
}gradebook;
main.c
gradebook *info=NULL;
info=(gradebook *)malloc(sizeof(gradebook));
init(info);
in func.c
void init(gradebook *info)
{
int i;
info->course.course_id=(int *)malloc(sizeof(int));
info->student.student_id=(int *)malloc(sizeof(int));
for(i=0; i<20; i++)
{
info->course.name[i]=(char*)malloc(sizeof(char)*20);
info->student.last[i]=(char*)malloc(sizeof(char)*20);
info->student.first[i]=(char*)malloc(sizeof(char)*20);
}
info->course.count=0;
info->student.count=0;
}
void addCourse(gradebook *info)
{
int i, loop=0;
printf("Enter Number of Courses: ");
scanf("%d", &loop);
for(i=0; i<loop; i++)
{
printf("Enter Course ID: ");
scanf("%d", &info->course.course_id[info->course.count]);
info->course.count++;
}
}
void addStudent(gradebook *info)
{
int i, loop=0;
printf("Enter Number of Students: ");
scanf("%d", &loop);
for(i=0; i<loop; i++)
{
printf("Enter Student ID: ");
scanf("%d", &info->student.student_id[info->student.count]);
info->student.count++;
}
}
void printCourse(gradebook *info)
{
int i;
if(info->course.count==0)
printf("No Courses in Databse.\n");
else
{
printf("Course ID\tCourse Name\n");
for(i=0; i<info->course.count; i++)
printf("%d\t\t%s\n", info->course.course_id[i], info->course.name[i]);
}
}
void printStudent(gradebook *info)
{
int i;
if(info->student.count==0)
printf("No Students in Database.\n");
else
{
printf("Student ID\tLast Name\tFirst Name\n");
for(i=0; i<info->student.count; i++)
printf("%d\t\t%s\t\t%s\n", info->student.student_id[i], info- >student.last[i], info->student.first[i]);
}
}
When I add values to courses and students and call the print function for courses. Not only do I print all the members of the courses but also the members of students. I don't understand what is causing the memory leak and how to prevent it. Any help is appreciated.
As a suggestion, I'd use a structure setup like the following:
typedef struct student_info{
char last[20];
char first[20];
int student_id;
} student;
typedef struct course_info{
char name[20];
int course_id;
int student_count;
student* students;
} course;
typedef struct gradebook_info{
int course_count;
course* courses;
}gradebook;
A gradebook is composed of a number of courses. Each course holds its students.
The program would look something like this:
void createStudents(course *info)
{
int i;
printf("Enter Number of Students in Course %d: ", info->course_id);
scanf("%d", &info->student_count);
info->students = malloc(sizeof(student)* info->student_count);
for (i = 0; i<info->student_count; i++)
{
printf("Enter Student ID: ");
scanf("%d", &info->students[i].student_id);
// make sure printf doesn't run past end of name
info->students[i].first[0] = '\0';
info->students[i].last[0] = '\0';
}
}
void createCourses(gradebook *info)
{
int i;
printf("Enter Number of Courses: ");
scanf("%d", &info->course_count);
info->courses = malloc(sizeof(course)* info->course_count);
for (i = 0; i < info->course_count; i++)
{
printf("Enter Course ID: ");
scanf("%d", &info->courses[i].course_id);
createStudents(&info->courses[i]);
// make sure printf doesn't run past end of name
info->courses[i].name[0] = '\0';
}
}
void init(gradebook *info)
{
info->course_count = 0;
createCourses(info);
}
void clear(gradebook *info)
{
int i;
for (i = 0; i < info->course_count; i++)
{
free(info->courses[i].students);
}
free(info->courses);
}
void printStudents(course *info)
{
int i;
if (info->student_count == 0)
printf("No Students in Database.\n");
else
{
printf("Student ID\tLast Name\tFirst Name\n");
for (i = 0; i<info->student_count; i++)
printf("%d\t\t%s\t\t%s\n", info->students[i].student_id, info->students[i].last, info->students[i].first);
}
}
void printCourses(gradebook *info)
{
int i;
if (info->course_count == 0)
printf("No Courses in Database.\n");
else
{
printf("Course ID\tCourse Name\n");
for (i = 0; i < info->course_count; i++)
{
printf("%d\t\t%s\n", info->courses[i].course_id, info->courses[i].name);
printStudents(&info->courses[i]);
}
}
}
int main()
{
gradebook *info = 0;
info = (gradebook *)malloc(sizeof(gradebook));
init(info);
printCourses(info);
clear(info);
return 0;
}
and this is sample input/output:
Enter Number of Courses: 2
Enter Course ID: 1
Enter Number of Students in Course 1: 2
Enter Student ID: 100
Enter Student ID: 101
Enter Course ID: 2
Enter Number of Students in Course 2: 3
Enter Student ID: 123
Enter Student ID: 456
Enter Student ID: 789
Course ID Course Name
1
Student ID Last Name First Name
100
101
2
Student ID Last Name First Name
123
456
789