C++數組名可以看成指針么?

很多老師和書都說把數組名看成指針,

但為什麼下面的輸出是一樣的

char ca[]="abcde";
printf("%#x
", ca);
printf("%#x
", ca);

從編譯器的角度,應該怎麼看待數組名?


數組就是數組,但是他可以隱式轉換成指針。當一個重載函數分別接受數組和指針的時候,肯定還是數組的那個命中。參見sizeof和strcpy_s。

數組不能被直接複製,所以當數組名作為函數參數的時候,要麼就是數組的引用,要麼就是指向第一個元素的指針,他們的值是相等的。當你對一個數組做的時候,他提取的是指向數組的指針,然後仍然可以隱式轉換成指向第一個元素的指針,而且它們的值是相等的。所以對於printf這種只認binary的函數來講,自然會輸出一樣的結果。


不可以,如果老師這麼教你,那麼老師是SB,我不開玩笑的說。

指針和數組名的共同特點是都是用來指代一個地址的。

不同的是:

1、指針是需要佔用內存空間來存儲地址的;數組名則更像是一個立即數或者常數。你可以修改指針指向的內容,但你絕對無法改變數組名的指向。

2、數組和指針對於sizeof來說是不同的,指針變數佔用的空間通常等於當前CPU的最大位數,數組名取sizeof的話,得到的則是數組的大小。

3、如果用extern聲明一個外部變數,指針和數組不能混用。比如在文件1.cpp里聲明了char ca[]="abcde",在文件2.cpp里如果要引用,那麼必須是extern char ca[]而不是extern char * ca,因為前者是常數,後者是一個佔用了內存空間的有效的變數,區別還是很大的。

4、對數組名取地址是合法的,但有些編譯器不推薦這樣做,對數組名取地址的結果與直接使用數組名的結果是一致的,這是C語言的一種特殊規定。有一個類似的效果就是函數名,假如func1是一個函數名,那麼*func1==func1==func1,這只是特殊用法,不代表函數名/數組名真的可以這麼做。


數組是數組,元素指針是元素指針,兩個是不同的東西,

但是數組的指針和數組第一個元素的指針的值顯然一樣啊!但是指針的類型不一樣(移動的步長不一樣!數組指針移動一個位置的話,就跳過了整個數組,元素指針移動一個位置,僅跳過一個元素)。

例子:

int a[5] = {1, 2, 3, 4, 5};
int (*pa)[5] = a;
int* paEle = a; // 相當於 a[0]
printf("ptr array : %d
", pa);
printf("ptr first element : %d
", paEle);
printf("move one step (arr) : %d
", pa + 1);
printf("move one step (element) : %d
", paEle + 1);

而且,它們sizeof的結果也不一樣:

int a[5] = {1, 2, 3, 4, 5};
int* paEle = a;
printf("%d
", sizeof(a));
printf("%d
", sizeof(paEle));

前者非常容易(例如作為函數參數時,參與算數運算時.....)退化(decay)成後者:

An lvalue or rvalue of type 「array of N T」 or 「array of unknown bound of T」 can be converted to an rvalue of type 「pointer to T.」

而且,模版函數的參數類型推導時,在不涉及引用的情況下,數組類型往往會先退化成元素指針類型後再進行推導。

template &
void array_to_pointer(T)
{
static_assert(std::is_same&::value, "");
}

int main()
{
int a[3];
static_assert(std::is_same&::value, "");
array_to_pointer(a); // array to pointer conversion: T = "int*"
}

所以國內的Cpp教師總愛說這麼一個歪理:數組就是指針,指針就是數組(呵呵呵呵呵)


首先數組名不是指針,這個可以用sizeof驗證

printf("%#x
", ca);是傳遞數組首地址,毫無疑問

printf("%#x
", ca);傳遞的是數組,但數組做參數傳遞時會自動退化成首地址,也就是說編譯器自動加了個


另外一種情況下數組和指針不能互換的情況

int main(int argc, char **argv)

{

char a[] = "hello world.
"; // 字元串在棧上

char *b = "hello world.
"; // 保存在棧上的指針指向保存在數據段的字元串

printf("a:%s b:%s
", a, b); // 看起來似乎是一樣的

// 但是修改一下內容就知道有什麼區別了

a[1] = 0;

b[1] = 0;

return 0;

}

解釋猛擊右側即可 C語言中字元串常量的好處在哪裡?



729 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 totype」 that points to the initial element of the array object and is not an lvalue.

http://c0x.coding-guidelines.com/6.3.2.1.html


你猜
printf("%#x
", ca+1);
printf("%#x
", ca+1);
相等么?
==================================


看你會不會看。會看就可以,不會看就不可以。


參見C語言ISO規範:

第四行:

if E1 is an array object (equivalently,a pointer to the initial element of an array object)懂我的意思沒~


推薦閱讀:

C 語言指針怎麼理解?
同樣的數組參數,用sizeof求數組長度為何會產生不同的結果?
國外有什麼優秀的c語言入門教學視頻?
僅用C語言可以構造出Python中Dict那種數據結構嗎?
在C語言中,可不可以實現使用一個字元串變數的內容為函數名,調用一個函數?

TAG:編程 | C編程語言 | CC | 指針 |