哪种风格更好?
int set_int (int *source) {
*source = 5;
return 0;
}
int main(){
int x;
set_int (&x);
}
OR
int *set_int (void) {
int *temp = NULL;
temp = malloc(sizeof (int));
*temp = 5;
return temp;
}
int main (void) {
int *x = set_int ();
}
为了获得更高级别的编程背景,我得说我更喜欢第二个版本。任何提示都会非常有帮助。还在学习C。
答案 0 :(得分:6)
都不是。
// "best" style for a function which sets an integer taken by pointer
void set_int(int *p) { *p = 5; }
int i;
set_int(&i);
或者:
// then again, minimise indirection
int an_interesting_int() { return 5; /* well, in real life more work */ }
int i = an_interesting_int();
仅仅因为更高级别的编程语言在幕后进行了大量的分配,不意味着如果你不断添加更多不必要的分配,你的C代码将变得更容易编写/读取/调试: - )
如果你确实需要一个用malloc分配的int,并使用一个指向那个int的指针,那么我会选择第一个(但是没有修复):
void set_int(int *p) { *p = 5; }
int *x = malloc(sizeof(*x));
if (x == 0) { do something about the error }
set_int(x);
请注意,函数set_int 的方式相同。它不关心它设置的整数来自何处,无论是堆栈还是堆,谁拥有它,它是否已存在很长时间或是否是全新的。所以它很灵活。如果你想编写一个执行两项操作的函数(分配一些东西并设置值),那么当然你可以使用set_int
作为构建块,也许是这样的:
int *allocate_and_set_int() {
int *x = malloc(sizeof(*x));
if (x != 0) set_int(x);
return x;
}
在真实应用的环境中,您可能会想到一个比allocate_and_set_int
更好的名字...
答案 1 :(得分:2)
一些错误:
int main(){
int x*; //should be int* x; or int *x;
set_int(x);
}
此外,您在第一个代码示例中没有分配任何内存。
int *x = malloc(sizeof(int));
关于风格:
我更喜欢第一个,因为你没有释放指针占用的内存的机会较少。
答案 2 :(得分:2)
第一个是不正确的(除语法错误外) - 您正在将未初始化的指针传递给set_int()
。正确的电话会是:
int main()
{
int x;
set_int(&x);
}
如果它们只是int
,并且它不会失败,那么通常的答案就是“不” - 你通常会这样写:
int get_int(void)
{
return 5;
}
int main()
{
int x;
x = get_int();
}
但是,如果它是一个更复杂的聚合类型,那么第二个版本很常见:
struct somestruct *new_somestruct(int p1, const char *p2)
{
struct somestruct *s = malloc(sizeof *s);
if (s)
{
s->x = 0;
s->j = p1;
s->abc = p2;
}
return s;
}
int main()
{
struct somestruct *foo = new_somestruct(10, "Phil Collins");
free(foo);
return 0;
}
这允许struct somestruct *
成为“不透明指针”,其中调用代码不知道类型struct somestruct
的完整定义。标准库使用此约定 - 例如,FILE *
。
答案 3 :(得分:1)
绝对选择第一个版本。请注意,如果您忘记稍后释放该内存,则允许您省略动态内存分配(即SLOW),并且可能是错误的来源。
此外, if 由于某种原因决定使用第二种样式,请注意您不需要将指针初始化为NULL。任何malloc()
返回都会覆盖此值。如果你内存不足,malloc()
将自己返回NULL,没有你的帮助:-)。
所以int *temp = malloc(sizeof(int));
就足够了。
答案 4 :(得分:1)
内存管理规则通常声明内存块的分配器也应该释放它。当返回分配的内存时,这是不可能的。因此,第二个应该更好。
对于像结构这样更复杂的类型,你通常会得到一个函数来初始化它,也许是一个处理它的函数。分配和解除分配应由您单独完成。
C使您可以自由地动态或静态地分配内存,并且只使用两种模式中的一种模式(如果您有一个返回动态分配的内存的函数就是这种情况)会限制您。
typedef struct
{
int x;
float y;
} foo;
void foo_init(foo* object, int x, float y)
{
object->x = x;
object->y = y;
}
int main()
{
foo myFoo;
foo_init(&foo, 1, 3.1416);
}
答案 5 :(得分:0)
在第二个中你需要一个指向它的指针才能工作,而在第一个中你没有使用返回值,尽管你应该这样做。
我倾向于选择第一个,在C中,但这取决于你实际在做什么,因为我怀疑你做的事情很简单。
保持您的代码尽可能简单,KISS原则仍然有效。
答案 6 :(得分:0)
如果某人不知道它是如何工作的,最好不要从函数返回一块已分配的内存,否则它们可能不会释放内存。 内存释放应该是分配内存的代码的责任。
答案 7 :(得分:0)
第一个是首选(假设简单的语法错误是固定的),因为它是你模拟Out参数的方式。但是,只有在调用者可以安排所有空间分配以在调用之前将值写入时,它才可用;当调用者缺少该信息时,你必须返回一个指向内存的指针(可能malloc
,也许来自池等等。)
答案 8 :(得分:0)
您更普遍地问的是如何从函数返回值。这是一个很好的问题,因为它很难做对。您可以学到的是一些经验法则,可以阻止您制作可怕的代码。然后,阅读好的代码,直到内化不同的模式。
以下是我的建议:
通常,任何返回 new 值的函数都应该通过其return语句执行此操作。这显然适用于结构,但也适用于数组,字符串和整数。由于整数是简单类型(它们适合一个机器字),你可以直接传递它们,而不是指针。
永远不要将指针传递给整数,这是一种反模式。始终按值传递整数。
学习按类型对功能进行分组,这样您就不必单独学习(或解释)每个案例。一个好的模型是一个简单的OO模型:一个_new函数,它创建一个不透明的结构并返回一个指向它的指针;一组函数,它们将指针指向该结构并用它做任务(设置属性,做功);一组返回该结构属性的函数;一个析构函数,它获取指向结构的指针并释放它。嘿presto,C变得更加漂亮。
当你修改参数(只有结构或数组)时,坚持使用约定,例如stdc库总是从右到左复制;我解释的OO模型总是把结构指针放在第一位。
避免在一个函数中修改多个参数。否则你会得到一些你不记得的复杂界面,最终你会出错。
返回0表示成功,返回-1表示错误,当函数执行可能出错的情况时。在某些情况下,您可能必须返回-1表示错误,0或更高表示成功。
标准POSIX API是一个很好的模板,但不使用任何类型的模式。