在我的代碼中,我有這個(它是由練習給出的):
typedef struct student{
int id;
float *grades;
char name[100];
}Student;
Student* fillStudent();
我的問題是:為什么函式“fillStudent()”會回傳一個Student型別的指標?是不是因為里面有成績指標?最初我認為這是因為你應該回傳一個由各種學生組成的向量,但它沒有意義,因為另一個結構:
typedef struct subject{
Student *V;
float average[5];
int nStudents;
}Subject;
該練習要求您呼叫函式“fillStudent()” nStudents次來填充向量 V,因此在一次呼叫中回傳所有學生是沒有意義的。那么為什么 fillStudent() 需要回傳一個指標呢?難道它不能只是一個Student型別的變數,并在成績上做一個malloc嗎?如果是這樣,那么變數到底會不會被認為是一個指標?
uj5u.com熱心網友回復:
我只能告訴你,你的推理是有道理的。首先,一個被呼叫的函式fillStudent應該“填充”已經存在的東西。因此,一個可能的簽名是:
void fillStudent(Student *dest);
這將是理想的,因為您會預先分配nStudents然后呼叫函式fillStudent nStudents時間。
此外,該結構Student不是很有用,因為您有一個指標,grades但您沒有一個變數來知道那里存盤了多少年級(所以我猜您不能在沒有某種型別的約定的情況下回圈遍歷它們,例如“last grade是-1“這是一種不當行為)。
對于您的問題,struct即使它們內部有向量,C 中按值回傳也沒有問題。
uj5u.com熱心網友回復:
我想首先解決您推測推理時出現的一些子問題。
問題1,函式fillStudent()回傳一個Student型別的指標是不是因為里面有一個成績指標?
答:不可以。結構可以[通常]在其欄位中包含任何型別的變數,而不必在指標變數本身中,并且是正確的 C 代碼。
Q2:為什么fillStudent()需要回傳一個指標?難道它不能只是一個Student型別的變數,并要求malloc成績嗎?
它絕對可以回傳一個Student結構,該結構的成績欄位初始化為malloc. (盡管正如@Zeppe 指出的那樣,如果您不知道陣列有多長,這樣做可能會出現問題)。這看起來像這樣,
#include <string.h>
Student createStudent(char* name, id, int num_of_grades) {
Student s;
s.id = id;
//since s.name is a fixed length array in the struct, memory was reserved
//for it when we declared the variable s.
strcpy(s.name, name)
//s.grades is a pointer to memory on the heap, so we have to
//allocate with something like malloc or calloc
s.grades = malloc(num_of_grades * sizeof(float));
return s; //perfectly okay to return a struct from a function.
}
Q3:Q2中函式回傳的變數是否被認為是指標?
答:沒有。我們回傳了一個結構體而不是一個指標。一個回傳指標的函式看起來像這樣,
Student * foo() {
Student * s = malloc(sizeof(Student));
//code to initialize/do something with s
//s is a pointer to a Student structure, so by returning s, we are returning
//a pointer to a Student structure
return s;
}
總而言之,鑒于您描述的設定,函式必須簽名回傳一個指標是沒有理由的,它甚至可能是一個錯誤!但是按照他們的方式去做并沒有錯,并且根據其余代碼的樣子,可能會有一些優勢。
第一個是世俗的。如果您的所有其余代碼都在處理Student*'s 而不是Student's,那么讓您用來構造它們的函式給您Student*'s 而不是Student's可能會感覺更方便。您可以對這是否是一個很好的理由發表意見,但這是我的猜測,因為它在您的案例中是這樣寫的最可能的原因。
下一個原因有更明顯的優勢。如果創建一個Student可能失敗(比如他們可能沒有注冊足夠的課程或其他東西),那么您希望能夠向程式的其余部分表明這一點。如果你只是回傳一個結構體,那么你通常無法從回傳值中知道它是否有效。你可以做這樣的事情
#include <stdbool.h>
//value of is_error gets set to true if there was an error, and false otherwise
Student createsStudent(char * name, /* other fields */, bool * is_error)
可以像這樣使用
bool is_error;
Student s = createsStudent(/* ... */, &is_error)
if(is_error) {
//respond to error
}
這很好用,但你最終is_error可能會得到很多額外的變數,這可能會有點煩人/分心。相反,如果創建方法Student回傳指向 的指標Student,那么您可以檢查它是否為空,并使用它來了解是否有錯誤。
最后,如果您有一堆修改 a 的函式Student,您可能希望在同一個變數上一個接一個地呼叫它們。但如果他們是這樣寫的,
Student createStudent(/*...*?);
void foo(Student* s);
void bar(Student* s);
void baz(Student* s);
你必須這樣稱呼他們
Student s = createStudent(/*...*/);
foo(&s);
bar(&s);
baz(&s);
但是如果你這樣寫,函式回傳指向它們引數的指標(它們只回傳 s),
Student * createStudent(/*...*/?);
//returns s
Student * foo(Student* s);
//returns s
Student * bar(Student* s);
//returns s
Student * baz(Student* s);
你可以這樣做,
Student * s = baz( bar( foo( createStudent(/*...*/) ) ) );
這是一件小事,但可以非常好。
總而言之,這兩種方式都沒有對與錯。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/373367.html
