2015-04-23 36 views
0

我有一個C程序,用戶在其中輸入一組等級。一切工作正常。 GPA計算正確等。但是,當數字被打印出來時,由於某種原因,學生結構中的兩個指針指向相同的地址,導致兩個學生在打印出信息時顯示第二個等級。其餘信息是正確的,只有等級是相同的。從函數返回數組地址不起作用

我能想到的唯一的事情是第二次初始化成績數組覆蓋第一個。我不明白爲什麼會發生這種情況,或者如何解決這個問題。

以下是該程序的樣品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"); 
} 
+0

考慮''student.grades = grades;''prompt_student()''中的行。成績在哪裏? –

回答

2

的問題是,內部功能prompt_student你聲明的局部陣列

float grades[number_of_grades]; 

和的地址將該本地數組的第一個元素分配給結構爲Student的數據成員grades

student.grades = grades; 

因此,該數據成員將始終具有相同的地址爲函數的每次調用。此外,該程序有未定義的行爲,因爲退出該函數後,本地數組不活。一般情況下它會被銷燬。

您必須動態分配數組並將分配數組的地址分配給數據成員grades

例如

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

顯而易見的是,在主,你應該釋放分配的內存中,當結構的相應的對象將不使用任何更多。

1

問題:

在你prompt_student()功能,grades是一個局部變量(陣列)。從函數返回時它超出了範圍。所以,你不能將數組(基地址)分配給student.grades,並在函數返回後使用它。如果您使用指針訪問內存,它將調用undefined behaviour

解決方案:

你需要使用動態內存分配malloc()/calloc()分配內存以student.grades在那裏複製掃描值。動態分配的內存使用期限一直到它們被釋放並且它們具有全局範圍。所以,直到你通過調用free()釋放內存,你也可以使用prompt_student()函數以外的內存。

0

您正在使用本地(「棧」)自動變量,當它們聲明的範圍退出時,它們不再存在。這給你一個未定義的行爲。

您需要爲此使用動態內存分配。

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; 

} 
+0

我遇到的問題與返回的Student變量不同,它與該學生中的成績數組一起使用。正如示例輸出顯示的那樣,我特別沒有問題。 – PitaJ

+0

你有與成績陣列相同的問題。您正在創建當您離開該功能時會消失的本地「堆棧」對象。 – rost0031