C---指針數組 & 數組指針---圖解篇

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章