从函数返回数组地址无效
Returning array address from function did not work
我有一个 C 程序,用户可以在其中输入多组成绩。一切正常。 GPA 计算正确等。但是,当打印回数字时,由于某种原因,Student 结构中的两个指针都指向相同的地址,导致两个学生在打印信息时显示第二个学生的成绩。其余信息都是正确的,只是等级相同。
我唯一能想到的是成绩数组的第二次初始化覆盖了第一次。我不明白为什么会发生这种情况或如何解决它。
程序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");
}
问题:
在你的prompt_student()
函数中,grades
是一个局部变量(数组)。当您从函数中 return 时,它超出了范围。因此,您不能将数组(基地址)分配给 student.grades
并在函数 return 之后使用它。如果您使用指针访问内存,它会调用 undefined behaviour.
解决方案:
您需要使用动态内存分配 malloc()
/calloc()
来分配内存到 student.grades
并 复制 那里的扫描值。动态分配的内存生命周期是直到它们被释放并且它们具有全局范围。因此,在您通过调用 free()
释放内存之前,您也可以从 prompt_student()
函数外部使用内存。
您正在使用局部 ("on-stack") 自动变量,当它们在声明中声明的范围退出时,这些变量将不复存在。这会给你未定义的行为。
您需要为此使用动态内存分配。
您正在 returning 一个在 return 之后消失的本地对象。
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;
}
问题是您在函数 prompt_student
中声明了局部数组
float grades[number_of_grades];
并将此局部数组的第一个元素的地址分配给结构 Student
的数据成员 grades
student.grades = grades;
所以这个数据成员对于函数的每次调用总是具有相同的地址。而且该程序具有 未定义的行为 因为在退出该函数后本地数组不存在。一般情况下会被销毁。
必须动态分配一个数组,并将分配数组的地址赋值给数据成员grades
。
例如
float *grades = malloc( number_of_grades * sizeof( float ) );
很明显,在main中,当结构的相应对象不再被使用时,你应该释放分配的内存。
我有一个 C 程序,用户可以在其中输入多组成绩。一切正常。 GPA 计算正确等。但是,当打印回数字时,由于某种原因,Student 结构中的两个指针都指向相同的地址,导致两个学生在打印信息时显示第二个学生的成绩。其余信息都是正确的,只是等级相同。
我唯一能想到的是成绩数组的第二次初始化覆盖了第一次。我不明白为什么会发生这种情况或如何解决它。
程序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");
}
问题:
在你的prompt_student()
函数中,grades
是一个局部变量(数组)。当您从函数中 return 时,它超出了范围。因此,您不能将数组(基地址)分配给 student.grades
并在函数 return 之后使用它。如果您使用指针访问内存,它会调用 undefined behaviour.
解决方案:
您需要使用动态内存分配 malloc()
/calloc()
来分配内存到 student.grades
并 复制 那里的扫描值。动态分配的内存生命周期是直到它们被释放并且它们具有全局范围。因此,在您通过调用 free()
释放内存之前,您也可以从 prompt_student()
函数外部使用内存。
您正在使用局部 ("on-stack") 自动变量,当它们在声明中声明的范围退出时,这些变量将不复存在。这会给你未定义的行为。
您需要为此使用动态内存分配。
您正在 returning 一个在 return 之后消失的本地对象。
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;
}
问题是您在函数 prompt_student
中声明了局部数组
float grades[number_of_grades];
并将此局部数组的第一个元素的地址分配给结构 Student
grades
student.grades = grades;
所以这个数据成员对于函数的每次调用总是具有相同的地址。而且该程序具有 未定义的行为 因为在退出该函数后本地数组不存在。一般情况下会被销毁。
必须动态分配一个数组,并将分配数组的地址赋值给数据成员grades
。
例如
float *grades = malloc( number_of_grades * sizeof( float ) );
很明显,在main中,当结构的相应对象不再被使用时,你应该释放分配的内存。