简体   繁体   中英

C pointer does not get set after being passed to a function

So I have been working away learning C for a little while and I have finally hit a brick wall. I have found different practice problems online and I am really having problems with this one.

Initially I wrote this code all inside the main function and it works just fine and gives the desired output (Here is the example that is working )

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

typedef struct Student STUDENT;
typedef struct Teacher TEACHER;
typedef struct Course COURSE;

int addStudentToTree(STUDENT *students, STUDENT *newStudent, STUDENT *currentStudent);
void printStudents(STUDENT *s);

struct Student
{
    int StudentNumber;
    char FirstName[BUFSIZ];
    STUDENT *left, *right;
};

struct Teacher
{
    int TeacherNumber;
    char FirstName[BUFSIZ];
    TEACHER *left, *right;
};

struct Course
{
    int CourseNumber;
    char CourseName[BUFSIZ];
    int SemesterNumber;
    COURSE *left, *right;
};

int main()
{
    FILE *db = fopen("DatabaseFile.txt", "r");
    char line[BUFSIZ]; 

    STUDENT *newStudent, *currentStudent, *students;
    students = NULL;

    if (db != NULL)
    {
        while (fgets(line, sizeof(line), db) != NULL)
        {   
            if (line[0] == 'S')
            {
                newStudent = malloc(sizeof(STUDENT));

                if (sscanf(line, "S %d %s", &newStudent->StudentNumber, newStudent->FirstName) == 2)
                {
                    newStudent->left = NULL;
                    newStudent->right = NULL;

                if (students == NULL)
                {   
                    students = newStudent;      

                }
                else
                {
                    currentStudent = students;

                    while(currentStudent)
                    {
                        if (newStudent->StudentNumber != currentStudent->StudentNumber)
                        {
                            if (newStudent->StudentNumber < currentStudent->StudentNumber)
                            {
                                if (currentStudent->left == NULL)
                                {
                                    currentStudent->left = newStudent;
                                    break;
                                }
                                else
                                {
                                    currentStudent = currentStudent->left;
                                }
                            }
                            else
                            {
                                if (currentStudent->right == NULL)
                                {
                                    currentStudent->right = newStudent;
                                    break;
                                }
                                else
                                {
                                    currentStudent = currentStudent->right;
                                }
                            }
                        }

                    }
                }               

                }

            }
        }
    }
    printStudents(students);
}

It successfully populates the tree and after that traverses it to give the following output:

Student Number: 203214 Student Name: Agneta
Student Number: 208214 Student Name: Janeta
Student Number: 213363 Student Name: Jill
Student Number: 215263 Student Name: Hansi
Student Number: 215363 Student Name: Laurent
Student Number: 228214 Student Name: James

Now part of the practice problem is also moving this out in to functions so everything doesn't just run inside the main method.

I have done this like so:

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

typedef struct Student STUDENT;
typedef struct Teacher TEACHER;
typedef struct Course COURSE;

int addStudentToTree(STUDENT *students, STUDENT *newStudent, STUDENT *currentStudent);
void printStudents(STUDENT *s);

struct Student
{
    int StudentNumber;
    char FirstName[BUFSIZ];
    STUDENT *left, *right;
};

struct Teacher
{
    int TeacherNumber;
    char FirstName[BUFSIZ];
    TEACHER *left, *right;
};

struct Course
{
    int CourseNumber;
    char CourseName[BUFSIZ];
    int SemesterNumber;
    COURSE *left, *right;
};

int main()
{
    FILE *db = fopen("DatabaseFile.txt", "r");
    char line[BUFSIZ]; 

    STUDENT *newStudent, *currentStudent, *students;
    students = NULL;

    if (db != NULL)
    {
        while (fgets(line, sizeof(line), db) != NULL)
        {   
            if (line[0] == 'S')
            {
                newStudent = malloc(sizeof(STUDENT));

                if (sscanf(line, "S %d %s", &newStudent->StudentNumber, newStudent->FirstName) == 2)
                {
                    newStudent->left = NULL;
                    newStudent->right = NULL;
                    addStudentToTree(students, newStudent, currentStudent);                 
                }

            }
        }
    }
    printStudents(students);
}

int addStudentToTree(STUDENT *students, STUDENT *newStudent, STUDENT *currentStudent)
{

    if (students == NULL)
    {   
        students = newStudent;
        return 1;
    }
    else
    {
        currentStudent = students;

        while(currentStudent)
        {
            if (newStudent->StudentNumber != currentStudent->StudentNumber)
            {
                if (newStudent->StudentNumber < currentStudent->StudentNumber)
                {
                    if (currentStudent->left == NULL)
                    {
                        currentStudent->left = newStudent;
                        return 1;
                    }
                    else
                    {
                        currentStudent = currentStudent->left;
                    }
                }
                else
                {
                    if (currentStudent->right == NULL)
                    {
                        currentStudent->right = newStudent;
                        return 1;
                    }
                    else
                    {
                        currentStudent = currentStudent->right;
                    }
                }
            }

        }
    }
    return 0;
}

Now the problem arrises. I pass in the pointer 'students' and the first time it is passed it is a null pointer and is rightly caught by the if statement in the function. the newStudent variable points to a memory address.

After these line:

if (students == NULL)
{   
    students = newStudent;
    return 1;
}

the pointer 'students' is now pointing at an actual address. But right after returning to the while loop in the main method, the 'students' pointer is once again a NULL pointer.

as an added info, you can see that putting in these printf's:

if (students == NULL)
    {   
        printf("students: %p, newStudent: %p\n",students, newStudent );
        students = newStudent;
        printf("students: %p\n",students);
        return 1;
    }

produces this output:

students: 0x0, newStudent: 0x7fc6e2001200
students: 0x7fc6e2001200
students: 0x0, newStudent: 0x7fc6e2001800
students: 0x7fc6e2001800
students: 0x0, newStudent: 0x7fc6e2005200
students: 0x7fc6e2005200
students: 0x0, newStudent: 0x7fc6e2005800
students: 0x7fc6e2005800
students: 0x0, newStudent: 0x7fc6e2005e00
students: 0x7fc6e2005e00
students: 0x0, newStudent: 0x7fc6e2006400
students: 0x7fc6e2006400

I have really been spending a lot of time on this and finally gave in to come in here to ask you all. Let me know if there is anything else you need to clarify this question.

Peter

you need to pass the address of the pointer... in this case the argument is created on the stack and when the function exits the stack is unwinded and your arguments remain no longer valid

int addStudentToTree(STUDENT **students, STUDENT *newStudent, STUDENT *currentStudent);

call like

addStudentToTree(&students,newStudent,currentStudent);

in the function do like

*sudents=NULL;

hope that helps

Imagine this:

void func(int var)
{
    var = 1;
}

int main()
{
    int var = 0;
    func(var);
    // What is the value of 'var' at this point?
    ...
}

If your answer to the question above is 1 , then you should probably go back to the basics and learn the language from scratch.

If you do understand that the copy of variable var in function main retains its "original" value, then you shouldn't have any problems understanding that whatever value you assign to (the copy of) variable students inside function printStudents , will not take effect outside that function.

That being said, here are the general guidelines for passing this variable by reference :

  1. Add * to the variable type in the function declaration - printStudents(STUDENT** s)
  2. Add * to every reference that you make to this variable inside function printStudents
  3. Add & before the variable in every place that you call the function - printStudents(&s)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM