Search code examples
cpointersrecursionvectordynamic-memory-allocation

Vector of pointers with dynamic memory allocation in C


I am learning about vector of pointers in C as part of an assignment. One part of my code, however, does not run and I do not understand why. I have included the full code below although my problem lies specifically in the selectApproved function.

I am only having trouble in the function selectApproved. It receives a pointer vector of type Student, which is a struct I have defined and among its elements has the grades of two different tests. The function is supposed to recursively identify the students who have achieved a pass result (defined as test1 + test2 >= 10) and return a vector of pointers, in which each element of the vector of pointer contains a pointer to a Student struct.

An error occurs right after the statement printf("Position %d\n", position); is located, after all recursive calls have occured. Specifically I know the error happens at this statement: approved_students[position] = vector[position];.

I do not understand why this error happens. After all recursive calls have occured I dynamically allocate my vector of pointer to hold exactly the number of students who passed: approved_students = (Student **) malloc( (*passed) * sizeof(Student *)). As far as I understand approved_student should have exactly the number of "slots" as *passed (in this case 4 slots). I even treat for the event where no student have been approved in the if statement if(num_students == 0).

I know my recursive function is working well, since the printf("Position %d\n", position); prints out a 3, which means that 4 students have been approved as expected (students 0,1,2,3 have been approved). The IDE I am using (Visual Studio 2012) allows me to do approved_students[position] = vector[position];. This statement, in my view, is saying that, for example approved_students[position] will contain a pointer to the struct located in vector[position]. After all, approved_student is a vector of pointers.

I am truly lost as to why the function doesn't work. Could someone help? I think

# include <stdio.h>
# include <stdlib.h>
# include <string.h>

struct Studentgrade{    

    float test1;
    float test2;

};

typedef struct Studentgrade Grade;

struct student

{   

    int ID_number;
    char name[51];
    Grade *scores;

};

typedef struct student Student;

Student *createStudent(int ID_num, char name_student[], float test1_grade, float test2_grade){

    int i = 0;
    Student *newStudent = (Student *) malloc(sizeof(Student));

    if (newStudent == NULL){

        printf("Error in memory allocation\n");
        exit(1);

    }

    newStudent->scores = (Grade *) malloc(sizeof(Grade));

    if (newStudent->scores == NULL){

        printf("Error in memory allocation\n");
        exit(1);

    }

    newStudent->scores->test1 = test1_grade;
    newStudent->scores->test2 = test2_grade;

    newStudent->ID_number = ID_num;

    while(i < 51  && name_student[i] != '\0')

        newStudent->name[i] = name_student[i++];

    newStudent->name[i] = '\0';

    return newStudent;
}

Student **selectApproved(Student *vector[], int num_students, int *passed){

    int position;
    int i;
    float comparison;
    Student **approved_students = NULL;

    if(num_students == 0){

        if(*passed == 0){

            printf("No student passed\n");
            return NULL;


        }

        else{

            approved_students = (Student **) malloc( (*passed) * sizeof(Student *));

            /*for (i = 0; i < (*passed); i++)

            approved_students[i] = (Student *) malloc(sizeof(Student *));*/

            if (approved_students == NULL){

                printf("Error in memory allocation\n");
                exit(1);
            }

            return approved_students;
        }
    }

    comparison = (vector[0]->scores->test1) + (vector[0]->scores->test2);

    if(comparison >= 10){

        position = *passed;
        (*passed)++;

        approved_students = selectApproved(&vector[1], num_students - 1, passed);

        printf("Position %d\n", position);

        approved_students[position] = vector[position];


    }

    else

        selectApproved(&vector[1], num_students - 1, passed);

    return approved_students;

}

int main(void){

    Student *vpstudent[12]; 
    Student **vpstudent2;
    int i = 0;
    vpstudent[0] = createStudent(444,"Rita",6.4, 7.8);
    vpstudent[1] = createStudent(111,"Rita",5.6, 8.8);
    vpstudent[2] = createStudent(999,"Rita",8.2, 7.1);
    vpstudent[3] = createStudent(555,"Dina",2.7, 6.4);
    vpstudent[4] = createStudent(777,"Lana",9.5, 5.3);
    vpstudent[5] = createStudent(666,"Tais",2.2, 2.8);
    vpstudent[6] = createStudent(222,"Cris",3.1, 4.2);
    vpstudent[7] = createStudent(333,"Vera",4.4, 5.4);
    vpstudent[8] = createStudent(888,"Cris",4.4, 5.4);
    vpstudent[9] = createStudent(303,"Vera",4.4, 5.4);
    vpstudent[10] = createStudent(101,"Cris",5.4, 3.4);
    vpstudent[11] = createStudent(202,"Vera",1.4, 8.4);

    vpstudent2 = selectApproved(vpstudent, 12, &i);
    return 0;

}

Solution

  • It appears you are relying on the final recursion into selectApproved to allocate the memory for your vector.

    However, you don't guarantee that allocated pointer actually gets returned up back up the call stack.

    The Else condition of "if(comparison >= 10)" does not load approved_students.

     if(comparison >= 10){
       ...
        approved_students = selectApproved(&vector[1], num_students - 1, passed);
       ...
    } else {
        approved_students = selectApproved(&vector[1], num_students - 1, passed);
    }   
    
    return approved_students;
    

    Based on that, I would say that student at the deepest recursion level did not pass.