天天看點

數組名和指針差別(還有數組退化等)

1. 什麼是數組類型?

下面是C99中原話:

An array type describes a contiguously allocated nonempty set of objects with a

particular member object type, called the element type.36) Array types are characterized by their element type and by the number of elements in the array. An array type is said to be derived from its element type, and if its element type is T , the array type is sometimes called ‘‘array of T ’’. The construction of an array type from an element type is called ‘‘array type derivation’’. 

很顯然, 數組類型也是一種資料類型, 其本質功能和其他類型無異:定義該類型的資料所占記憶體空間的大小以及可以對該類型資料進行的操作(及如何操作).

2. 數組類型定義的資料是什麼?它是變量還是常量?

char s[10] = "china";

在這個例子中, 數組類型為 array of 10 chars(姑且這樣寫), 定義的資料顯然是一個數組s.

  An lvalue is an expression with an object type or an incomplete type other than void; if an lvalue does not designate an object when it is evaluated, the behavior is undefined. When an object is said to have a particular type, the type is specified by the lvalue used to designate the object. A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.

看了上面的定義, 大家應該明白了modifiable lvalue和lvalue的差別, 大家也應該注意到array type定義的是lvalue而不是modifiable lvalue.是以說s是lvalue.

s指代的是整個數組, s的内容顯然是指整個數組中的資料, 它是china/0****(這裡*表示任意别的字元).s的内容是可以改變的, 從這個意義上來說, s顯然是個變量.

3. 數組什麼時候會"退化"

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.

上面這句話說的很清楚了, 數組在除了3種情況外, 其他時候都要"退化"成指向首元素的指針.

比如對 char s[10] = "china";

這3中例外情況是:

(1) sizeof(s)

(2) &s;

(3) 用來初始化s的"china";

除了上述3種情況外,s都會退化成&s[0], 這就是數組變量的操作方式

4. 數組與指針有什麼不同?

4.1 初始化的不同

char s[] = "china";

char *p = "china";

在第一句中,以&s[0]開始的連續6個位元組記憶體分别被指派為:

'c', 'h', 'i', 'n', 'a', '/0'

第二句中,p被初始化為程式data段的某個位址,該位址是字元串"china"的首位址

4.2 sizeof的不同

sizeof就是要求一種資料(類型)所占記憶體的位元組數. 對于4.1中的s和p

sizeof(s)應為6, 而sizeof(p)應為一個"指針"的大小.

這個結果可以從1中對于數組類型的定義和3中數組什麼時候不會"退化"中得出來.

4.3 &操作符

對于&操作符, 數組同樣不會退化.

4.1中的s和p分别取位址後,其意義為:

&s的類型為pointer to array of 6 chars.

&p的類型為pointer to pointer to char.

4.4 s退化後為什麼不可修改

除3種情況外,數組s在表達式中都會退化為"指向數組首元素的指針", 既&s[0]

舉個例子

int a;

(&a)++; //你想對誰++? 這顯然是不對的

對(&s[0])++操作猶如(&a)++, 同樣是不對的,這就導緻退化後的s變成不可修改的了.

4.5 二維數組與二級指針

char s[10];與char *p;

char s2[10][8];與char **p2;

s與p的關系,s2與p2的關系,兩者相同嗎?

緊扣定義的時候又到了.

除3種情況外,數組在表達式中都會退化為"指向數組首元素的指針".

s退化後稱為&s[0], 類型為pointer to char, 與p相同

s2退化後稱為&s2[0], 類型為pointer to array of 8 chars, 與p2不同

4.6 數組作為函數參數

毫無疑問, 數組還是會退化.

void func(char s[10]); <===> void func(char *s);

void func(char s[10][8]); <===> void func(char (*s)[8]);

(我在寫如下代碼時:

char e[10][8];

func(e);

void func( char **a)

{

printf("%d\n",sizeof(a));

printf("%d\n",a[0]);

}

報錯:

char (*s)[8]類型的實參與char **P類型的形參不相容