以下两个代码块执行相同的操作:void foo(int * num){…}
int main(void){ int num = 5; FOO(试验#);
…}void foo(int * num){…}
int main(void){ int * num;…
我更喜欢将所有变量声明为指针,就像在第二个中一样,但我更频繁地看到第一个变量。
这句话没有多大意义 - 当然不是 一切 你工作的是一个指针。
代码
int *num; *num = 5; foo( num );
因为没有格式良好 num 并没有指向任何东西(它的价值是 不定 )。你正试图分配 5 某些随机内存地址可能导致段错误或损坏其他数据。它 可以 按计划工作没有明显的问题,但这是偶然的,而不是设计。
num
5
仅仅因为函数将指针作为参数并不意味着你必须传递一个 指针对象 作为那个参数。是的,就是你 可以 写点东西
int num; int *numptr = # *numptr = 5; foo( numptr )
但这并没有给你带来任何简单的写作
int num = 5; foo( &num );
C 要求 我们在2种情况下使用指针:
它们也可以用来构建动态数据结构,如列表,队列,树等等。但是你不应该使用它们 一切 。
以下两个代码块执行相同的操作:
不,他们没有。只有第一个完全定义了行为。第二个在执行时取消引用一个野指针 *num = 5 没有分配有效的指针 num 。
*num = 5
在这两种情况下,foo都需要一个指向int的指针参数。在第一个我声明一个int并使用地址运算符(&)将其传递给foo。在第二个我声明一个指针变量并直接将其传递给foo。
你似乎正在遭遇令人沮丧的共同点,它无法区分指针和它所指向的东西。它们是不同的,大部分是正交的声明 int *num 没有宣布或保留任何空间 int 。它声明了一个指针 能够 指向一个 int ,但是在指定一个指针之前,该指针的值无效 不 指向一个 int 。
int *num
int
是否有理由使用任何一种,而不是风格 偏爱?
是。第一个是有效的,第二个不是。
我更喜欢将所有变量声明为指针,如 第二个,但我更频繁地看到第一个。
听到你看到第二个,我很遗憾 一点都不 。
一
void one(void) { int n = 42; // initialization foo(&n); putchar(n); }
二
void two(void) { int *n; n = malloc(sizeof *n); *n = 42; // no initialization foo(n); putchar(*n); free(n); }
三
void three(void) { int n[1] = { 42 }; // initialization foo(n); putchar(*n); //putchar(n[0]); }
不,这两个片段做的很不一样。第一个片段是格式良好的代码。由于取消引用未初始化的指针,第二个片段是Undefined Behavior。
第二个版本可能会在执行时崩溃或执行其他一些不需要的操作。此外,在任何现代编译器上编译时都会显示警告,它会显示警告,例如:
警告:变量'num'在此处使用时未初始化 [-Wuninitialized]
第一个代码片段获取变量的地址并将其传递给 foo ,第二个取消引用未初始化的指针。你可以做的是:
foo
int *num = malloc(sizeof(int)); *num = 5; foo(num); free(num);
要么:
int num = 5; int *p = # foo(p);
要取消这一点的主要原因是第一种形式是最简单的。有效的指针变量必须指向程序控件中的内存,这需要更多的工作而不仅仅是 int *num; *num = 5;
int *num; *num = 5;
当然,正如其他人指出的那样,在第二步中你需要将点初始化为有效的已分配内存。所以这是支持第一个代码的一点。
对于约翰库格曼的例子
int num; int *p = # *p = 5; foo(p);
在第一个例子中似乎没有任何优势。因此,如果你修复了第二个例子,你可能只需要更多的代码,而不需要任何额外的清晰度。
最后,我认为作为一个公平的整体总结,第二个例子实际上并没有获得“将所有变量声明为指针”的价值。你必须在某处拥有实际的记忆,而第一个例子就是明确的。它作为指针传递,因此除了声明内存的代码之外,它是一个指针。