0.指針數組 & 數組指針(相見恨晚篇)
《C語言深度剖析》上面的解析如下:
指針數組: 首先它是一個數組,數組的元素都是指針,數組佔多少個字節由數組本身的大小決定,每一個元素都是一個指針,在32 位系統下任何類型的指針永遠是佔4 個字節。它是“儲存指針的數組”的簡稱。
數組指針: 首先它是一個指針,它指向一個數組。在32 位系統下任何類型的指針永遠是佔4 個字節,至於它指向的數組佔多少字節,不知道,具體要看數組大小。它是“指向數組的指針”的簡稱。
下面到底哪個是數組指針,哪個是指針數組呢:
A) int *p1[10];
B) int (*p2)[10];
- “[]”的優先級比“*”要高。p1 先與“[]”結合,構成一個數組的定義,數組名爲p1,int *修飾的是數組的內容,即數組的每個元素。那現在我們清楚,這是一個數組,其包含10 個指向int 類型數據的指針,即指針數組。
- 至於p2 就更好理解了,在這裏“()”的優先級比“[]”高,“*”號和p2 構成一個指針的定義,指針變量名爲p2,int 修飾的是數組的內容,即數組的每個元素。數組在這裏並沒有名字,是個匿名數組。那現在我們清楚p2 是一個指針,它指向一個包含10 個int 類型數據的數組,即數組指針。
我們可以藉助下面的圖加深理解:
這裏有個有意思的話題值得探討一下:
平時我們定義指針不都是在數據類型後面加上指針變量名麼?這個指針p2 的定義怎麼不是按照這個語法來定義的呢?也許我們應該這樣來定義p2:
int ()[10] p2;
int () [10] 是指針類型,p2 是指針變量。這樣看起來的確不錯,不過就是樣子有些彆扭。其實數組指針的原型確實就是這樣子的,只不過爲了方便與好看把指針變量p2 前移了而已。你私下完全可以這麼理解這點。雖然編譯器不這麼想。_
聰明的你,看完上面的講解好像都理解了,是吧?
如上的解釋,我再把重點囉嗦幾句:
- 指針數組:本質是數組,只是裏面存放的是多個指針(int * p1[10])。此處的p1是數組名,指針名沒有。如果想獲取指針&p1[i],這樣可以獲取指針
- 數組指針:本質是指針,雖然初始化的時候指向了一個數組( int(*p2)[10] ),但其實只是一個指針。p2是指針變量,想通過指針獲取地址,可以用指針的偏移去獲取,例如p2 + 1,代表第二個元素的地址
- 有關指針的偏移,可以參考博文:https://blog.csdn.net/chenmozhe22/article/details/106410963(圖文並茂)
1.指針數組
#include <stdio.h>
int main() {
int i;
char* pch[5] = { "我", "愛", "你", "祖", "國" }; // 此處初始化只能是5個元素,多一個少一個都不行
printf("%s \n", pch[0]); // pch是數組名,所以通過索引直接可以獲取到元素內的每個值
printf("%s \n", *(&pch[0])); // 既然每個變量可以找到,就能通過* + & + 變量方式,對指針取值
*(&pch[3]) = "中"; //pch[3] = "中";方式也一樣效果
for (i = 0; i < 5; i++) {
printf("%s, ", pch[i]);
};
printf("\n");
printf("%s\n", *(&pch[1] + 1)); // 通過指針獲取其他元素
printf("%d \n", sizeof(pch)); // 因爲pch是指針數組,裏面存放的是5個指針,所以4*5 = 20個字節
return 0;
};
我
我
我, 愛, 你, 中, 國,
你
20
2.數組指針
#include <stdio.h>
int main() {
int i;
int list[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* p1 = &list; // 指針指向數組方式一
printf("%p \n", p1);
printf("%p \n", p1+1); // &list[0] + 1
printf("%d \n", *p1);
printf("%d \n", *p1 + 1);
printf("===================\n");
int(*p2)[10] = &list; // 數據指針:指向了某個數組的指針,方式二
printf("%p \n", p2); //p2 和 *p2 的地址是一樣的???
printf("%p \n", *p2);
printf("%d \n", **p2); // **p2是元素的實際值
printf("%p \n", *p2 + 1);
printf("%p \n", (*p2 + 2));
return 0;
};
012FF6B8
012FF6BC
1
2
===================
012FF6B8
012FF6B8
1
012FF6BC
012FF6C0
如上結果,我主要困惑的地方如下:
1.我們看到p1 & p2 & *p2的值是一樣的
2.**p2纔是具體的值,那p2算是指針的指針嗎?
3.再談二維數組
有關二維數組的概念和基礎,可參考:https://blog.csdn.net/chenmozhe22/article/details/106280578
1.二維數組中的指針 & 數組名
#include <stdio.h>
int main() {
int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 },{ 8 , 9, 10, 11 }
};
int(*p)[4];
int i, j;
p = a;
printf("%p \n", p);
printf("%p \n", *p);
printf("%d \n", **p);
printf("=================\n");
printf("%p \n", a);
printf("%p \n", *a);
printf("%d \n", **a);
return 0;
}
00D3FD94
00D3FD94
0
=================
00D3FD94
00D3FD94
0
根據代碼,發現:
- **p / **a才能得到,二維數組元素對應的值
-在一維數組中(*p可以得到最終的元素),p代表的是指針變量;那麼二維數組(**p可以得到最終的元素),那 *p 就是指針變量。- p則是真實指向二維數組,首元素的指針,這裏有個概念,p不是指針的指針,可參考:https://blog.csdn.net/toyalll/article/details/50043193
- 我們可以通過指針、地址兩種方式,分別獲取並修改二維數組中的值。
2.獲取二維數組中元素的值–指針法
#include <stdio.h>
int main() {
int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 },{ 8 , 9, 10, 11 }};
int(*p)[4];
int i, j;
p = a;
printf("%d \n", **p);
printf("%d \n", *(*p + 1)); // *p+1,可以得到下一個元素的指針地址
printf("%d \n", *(*p + 2));
printf("=================\n");
printf("%d \n", *(*(p + 1))); //*(p+1),可以得到下一行元素的指針地址
printf("%d \n", *(*(p + 1)+1));
printf("=================\n");
printf("%d \n", *(*(p + 2)));
printf("%d \n", *(*(p + 2)+1));
return 0;
}
有關指針的偏移,可以參考:
https://blog.csdn.net/chenmozhe22/article/details/106410963
0
1
2
=================
4
5
=================
8
9
如上代碼,經過優化之後如下:
#include <stdio.h>
int main() {
int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 },{ 8 , 9, 10, 11 }};
int(*p)[4];
int i, j;
p = a;
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++)
printf("%2d ", *(*(p + i) + j));
printf("\n");
}
return 0;
}
0 1 2 3
4 5 6 7
8 9 10 11
3.獲取二維數組中元素的值–地址法
int main() {
char list[2][5] = { { '1', '2', '3', '4', '5' }, { 'a', 'b', 'c', 'd', 'e' }};
printf("%c \n", list[0][0]); //獲取第一行的第一個元素
printf("%c \n", list[1][0]); //獲取第二行的第一個元素
printf("%p \n", &list[0]);
printf("%p \n", &list[1]);
printf("%d-%d",&list[1],&list[0]); // 計算第一行第一個元素和第二行第一個元素相差的字節數
return 0;
};
1
a
00DBFD3C
00DBFD41
14417217-14417212
#include <stdio.h>
int main() {
char list[2][5] = { { '1', '2', '3', '4', '5' }, { '6', '7', '8', '9', '0' } };
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 5; j++)
printf("%c \t", *(&list[i][j]));
printf("\n");
};
return 0;
};
1 2 3 4 5
6 7 8 9 0
文章參考:
- 《C語言深度剖析》(強烈推薦大家看看,特別是初學者,昨天買了一本,家中常備!)
- https://www.cnblogs.com/hongcha717/archive/2010/10/24/1859780.html
- https://www.cnblogs.com/mq0036/p/3382732.html#commentform