我对有问题的C程序(arrays-pointers.c)有很多疑问:
#include <stdio.h>
int main(void) {
char * vowels = {'A', 'E', 'I', 'O', 'U'};
printf("sizeof(vowels): %d\n", sizeof(vowels));
}
Run Code Online (Sandbox Code Playgroud)
我使用gcc(gcc arrays-pointers.c -o arrays-pointers.exe)进行编译,但收到警告(但不是完全错误):
In function 'main':
warning: initialization of 'char *' from 'int' makes pointer from integer
without a cast [-Wint-conversion]
char * vowels = {'A', 'E', 'I', 'O', 'U'};
^~~
note: (near initialization for 'vowels')
warning: excess elements in scalar initializer
char * vowels = {'A', 'E', 'I', 'O', 'U'};
^~~
note: (near initialization for 'vowels')
warning: excess elements in scalar initializer
char * vowels = {'A', 'E', 'I', 'O', 'U'};
^~~
note: (near initialization for 'vowels')
warning: excess elements in scalar initializer
char * vowels = {'A', 'E', 'I', 'O', 'U'};
^~~
note: (near initialization for 'vowels')
warning: excess elements in scalar initializer
char * vowels = {'A', 'E', 'I', 'O', 'U'};
^~~
note: (near initialization for 'vowels')
Run Code Online (Sandbox Code Playgroud)
尽管有这些警告,gcc仍会生成一个可执行文件,该可执行文件始终输出:
sizeof(vowels): 8
Run Code Online (Sandbox Code Playgroud)
我的问题是:
sizeof(vowels)总是8?这一点很容易理解,因为数组在C中是“奇怪的”。仅出于历史原因,它们就属于“特殊情况”。
您需要知道的是,数组和指针根本不是一回事。数组是一块有多个元素的内存块,指针是别的东西的地址。
造成混淆的是,在许多地方,如果使用C语言,则C语言会考虑使用指向数组第一个元素的指针(而不是数组)(在法律术语中,使用的短语是“数组衰减为指向第一个元素的指针”) )。
例如
int x[] = {1, 2, 3}; // x is an array
foo(x); // you cannot pass an array, a pointer to x[0] is passed instead
Run Code Online (Sandbox Code Playgroud)
所以你的代码是无效的,因为像
int *x = {1, 2, 3}; // Invalid: {1, 2, 3} is not a valid initializer for a pointer
Run Code Online (Sandbox Code Playgroud)
相反,这足够令人惊讶
int x[] = {1, 2, 3}; // An array
int *y = x; // Fine, it's like writing int *y = &x[0];
Run Code Online (Sandbox Code Playgroud)
在第二个示例中,的初始化y是有效的,因为在这种情况下,有一条规则说该数组会自动“衰减”为指向第一个元素的指针。
This confusion happens because arrays are not objects like the others (for historical reason) and for example assignment of arrays or returning an array from a function or accepting an array parameter is illegal (but, surprisingly, you can assign a structure, pass structures as parameters and return structures from functions... even if the structure contains an array). Fixing this illogical asymmetry now is out of question, as would break most of existing C or C++ programs by changing the meaning of existing code.
C and C++ unfortunately are full of these strange illogical rules, that's why learning C or C++ by experimentation is a bad idea (with C it's a bad idea but may be still doable as its size is small, but with C++ it's a suicide because it's literally a minefield of illogical traps, and a huge one).
To learn C or C++ you need to read the rules.
Don't try to be too smart and guess (guessing doesn't help when the correct answer is illogical).