我想首先解决您在推测推理时提出的一些子问题。
问题一,函数fillStudent()返回一个Student类型的指针是因为里面有一个成绩指针吗?
答:不。一个结构[通常]可以在其字段中包含任何类型的变量,而不必位于指针变量本身中,并且是正确的 C 代码。
Q2:为什么fillStudent()需要返回一个指针?难道不能简单地是一个Student类型的变量,并在成绩上调用malloc吗?
它绝对可以返回一个Student 结构,它的grades 字段用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*而不是Student,那么让您用来构造它们的函数为您提供Student*而不是Student可能会感觉更方便的。你可以对这是否是一个很好的理由有意见,但我猜测你的情况最有可能是这样写的。
下一个原因有更明显的优势。如果创建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 的指针,那么您可以检查它是否为空,并使用它来判断是否有错误。
最后,如果您有一堆修改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(/*...*/) ) ) );
这是一件小事,但可以非常好。
总而言之,这两种方法都没有对错。