从函数返回数组地址不起作用

时间:2015-04-23 07:07:59

标签: c arrays function pointers struct

我有一个C程序,用户可以在其中输入成绩集。一切正常。正确计算GPA等。但是,当数字打印出来时,学生结构中的两个指针由于某种原因指向同一地址,导致两个学生在打印出信息时显示第二个等级。其余信息是正确的,它只是相同的等级。

我唯一能想到的就是grade数组的第二次初始化会覆盖第一个。我不明白为什么会发生这种情况或如何解决它。

以下是该计划的示例IO:

Enter the number of students:> 2
Enter the number of grades to track:> 3

There are 2 students.
There are 3 grades.

Enter information for student:
        Enter SID:> 101
        Enter last name:> Enright
        Enter first name:> Reed
        Enter grades (separated by space):> 70.1 60 92

Enter information for student:
        Enter SID:> 123
        Enter last name:> Claire
        Enter first name:> Heidi
        Enter grades (separated by space):> 82.5 96.1 89.0

Student ID #101:
        Name:   Reed Enright
        Grades: 82.5 96.1 89.0
        GPA:    74.03
Student ID #123:
        Name:   Heidi Claire
        Grades: 82.5 96.1 89.0
        GPA:    89.20

这是完整的代码:

#include <stdio.h>
#define NAME_SIZE 25

typedef struct {
        int sid;
        char last_name[NAME_SIZE];
        char first_name[NAME_SIZE];
        float *grades;
        float gpa;
} Student;

// function prototypes

// get student information
Student prompt_student(int number_of_grades); 
// calculate the gpa based on the grades
float calculate_gpa(Student student, int number_of_grades); 
// prints all of the students
void print_all_students(Student students[], int number_of_students, int number_of_grades);

int main(){
        // initialise variables
        int number_of_students;
        int number_of_grades;

        // prompt for number of students
        printf("\nEnter the number of students:> ");
        scanf("%d", &number_of_students);
        // prompt for number of grades
        printf("Enter the number of grades to track:> ");
        scanf("%d", &number_of_grades);

        // confirm the above
        printf("\nThere are %d students. \nThere are %d grades.\n",
                        number_of_students, number_of_grades);

        // initialise student list
        Student students[number_of_students];
        // get and store student information
        for(int i = 0; i < number_of_students; i++){
                students[i] = prompt_student(number_of_grades);
        }

        // confirm the above
        print_all_students(students, number_of_students, number_of_grades);

        return 0;
}

Student prompt_student(int number_of_grades){
        // initialise student variable
        Student student;
        float grades[number_of_grades];
        printf("\nEnter information for student: \n");

        // prompt for student info
        printf("\tEnter SID:> ");
        scanf("%d", &(student.sid));

        printf("\tEnter last name:> ");
        scanf("%s", student.last_name);

        printf("\tEnter first name:> ");
        scanf("%s", student.first_name);

        printf("\tEnter grades (separated by space):> ");
        for(int i = 0; i < number_of_grades; i++){
                scanf("%f", &grades[i]);
        }
        student.grades = grades;

        student.gpa = calculate_gpa(student, number_of_grades);

        return student;
}

float calculate_gpa(Student student, int number_of_grades){
        float total = 0; // initialise variable for sum of grades
        // add all grades together
        for(int i = 0; i < number_of_grades; i++){
                total += student.grades[i];
        }
        // return average
        return total / number_of_grades;
}

void print_all_students(Student students[], int number_of_students, int number_of_grades){
        // loop through all students
        for(int i = 0; i < number_of_students; i++){
                // print student info
                printf("\nStudent ID #%d:", students[i].sid);
                printf("\n\tName:\t%s %s", students[i].first_name, students[i].last_name);
                printf("\n\tGrades:\t");
                for(int n = 0; n < number_of_grades; n++){
                        printf("%.1f ", students[i].grades[n]);
                }
                printf("\n\tGPA:\t%.2f", students[i].gpa);
        }
        printf("\n");
}

4 个答案:

答案 0 :(得分:2)

问题是你在函数prompt_student内声明了本地数组

float grades[number_of_grades];

并将此本地数组的第一个元素的地址分配给结构grades的数据成员Student

student.grades = grades;

因此,对于函数的每次调用,此数据成员将始终具有相同的地址。此外,该程序具有未定义的行为,因为退出该函数后,本地数组不活动。一般情况下,它将被销毁。

您必须动态分配数组并将分配的数组的地址分配给数据成员grades

例如

float *grades = malloc( number_of_grades * sizeof( float ) );

很明显,在main中,当结构的相应对象不再被使用时,你应该释放已分配的内存。

答案 1 :(得分:1)

问题:

prompt_student()函数中,grades是局部变量(数组)。从函数返回时,它超出了范围。所以,你不能将数组(基地址)分配给student.grades并在函数返回后使用它。如果使用指针访问内存,则会调用undefined behaviour

解决方案:

您需要使用动态内存分配malloc()/calloc()分配内存到student.grades复制扫描值。动态分配的内存生存期是直到它们被释放并且它们具有全局范围。因此,直到您通过调用free()释放内存,您也可以使用prompt_student()函数外部的内存。

答案 2 :(得分:0)

您正在使用本地(&#34; on-stack&#34;)自动变量,这些变量在退出时声明它们的范围时不再存在。这会给你未定义的行为。

您需要为此使用动态内存分配。

答案 3 :(得分:0)

您返回的是返回后遗失的本地对象。

Student prompt_student(int number_of_grades){
    // initialise student variable
    Student student;
    ...
    return student;
}

相反,传入指向在函数范围外创建的结构的指针

main() {
    Student student;

    prompt_student(&student, number_of_grades)

}


void prompt_student(Student *pStudent, int number_of_grades){
    // initialise student variable

    ...
    pStudent->grades = grades;
    ... etc ...
    return;

}