1. 程式人生 > >陣列(一維和二維)與指標(C語言)

陣列(一維和二維)與指標(C語言)

文章目錄


讀者,你好!
如果你精通C,希望能得到你的斧正;如果你是初學者,希望能對你有所幫助。
加粗的是一些我認為比較重要的內容。
#一、指向一維陣列的指標
##1、使指標指向陣列首地址的方法
int a[5];      //整型陣列
int *pa;       //整形指標,可以指向整型陣列
pa = a;        //把陣列a的首地址賦給pa
pa = &a[0];		//把陣列a的首元素地址的地址賦給pa
  • C語言規定,陣列名代表陣列首地址,因此用“pa = a”表示將陣列a首地址傳給指標pa,而如果用"pa = &a",的形式就是錯誤的。這裡要注意陣列名和普通變數名的差別。


    ##2、通過指標引用一維陣列元素
    把陣列的首地址傳給指標變數的形式稱為“地址傳遞”,地址傳遞以後,陣列和指標就可以“共享”一段陣列空間。因此訪問陣列元素的內容,就有兩種方式:
    ①下標法:a[0], a[1],…a[i];
    ②指標法間接訪問:*p, *(p+1),…*(p+i);

  • 陣列指標變數向前或向後移動一個位置和地址加1或減1的概念不同,因為陣列可以有不同型別,各種型別的陣列元素所佔的位元組長度是不同的,指標變數向前或向後移動一個位置就是變數減1或加1,即指向下一個資料元素的首地址。而不是在原有的地址基礎上加上1。

陣列元素a[i]及其地址的表示法:

表示方法 元素 地址 說明
下標法 a[i] &a[i] 下標法
指標下標法 p[i] &p[i] 下標法
地址法 *(a+i) a+i 指標法
指標法 *(p+i) p+i 指標法

特別注意這裡的i是指陣列元素的偏移量,而不是說實際地址加i。
程式碼驗證如下:

#include <stdio.h>
int main()
{
	int a[10] = {1,2,3,4,5,6,7,8,9,0} , b, c, d, e;
	int *p  = &a[0];
	b = *(a + 1);
	c = *(p + 1);
	d = a[1];
	e = p[1];
	printf("*(a + 1) = %d\n *(p + 1) = %d\na[1] = %d\np[1] = %d\n", b, c, d, e);
} 

執行結果:
這裡寫圖片描述

*注意:若將上述演算法中的 c = *(p+1);改為c = (*P)+1; 那麼輸出結果是完全不同的,(p)+1;意思是取P這個地址所存的資料,再給這個資料加一,按照演算法,c = 3。而如果使用p++,又會怎樣呢?比如p += 3 那麼此時p指向的是陣列第4個元素的地址,此時p[0]就是a[3]了,也就是 4,而票p[-1]就是a[2]。

  • 如何用指標實現陣列的輸入與輸出。具體演算法如下:
#include <stdio.h>
int main()
{
	int arr[4] = {0}, counter;
	int *pa = arr;
	for(counter = 0;counter <= 3; counter++)
	{
		scanf("%d",pa++);
	}
	pa--;
	for(counter = 3; counter >= 0;counter--)
	{
		printf("%d ", *pa--);
	}
 } 

注意事項:
輸入時是scanf("%d", pa++); 而輸出時是printf("%d", *pa--);輸入時要存一個數據,所以必須先取得記憶體地址,而輸出時是一個整數,要知道這個記憶體空間所存的資料具體是什麼。
#二、二維陣列與指標
##1、先重新認識一下二維陣列
二維陣列可以看做是一維陣列的陣列,列如對於二維陣列int A[3][4]; 可以把 A看作是由3個一維陣列元素組成的。即A由A[0], A[1], A[2]組成,而A[i]都是長度為4的一維陣列。
對於三個元素A[0],A[1],A[2]又是三個一位陣列名,也就是三個地址,即都是指標,分別指向三個陣列的首元素,即A[0][0], A[1][0], A[2][0]。

  • 比如現在要訪問元素A[1][3],有下列幾種方法:
    ①就是直接用二維陣列下標法:A[1][3]。
    ②用一維陣列名的方法:*(A[1] +3);*(A[0]+7); 當然也可以是*(A[2]-1);
    ③用二維i陣列名的方法, 只要②中的一維陣列名改成相應的二維陣列名即可:比如把A[1]改成*(A+1) 這樣就可以得到如下訪問方式:*(*(A+1)+3)*((*A)+7)*(*(A+2)-1) .一般情況下不用這種方法,過於繁瑣。
    ④還可以用*& 運算子來訪問,*(&A[1][3]) ,,同理也可以用&A[0][0] 來代替A[0]。
  • 先看一下列子
#include <stdio.h>
int main()
{
	int A[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}},i = 0, j = 0;
	
	for(i = 0;i < 3; i++)
	{
		for(j =0;j < 4 ; j++)
		{
			printf("&A[%d][%d]  = %p  ", i, j, &A[i][j]);
		}
		printf("\n");
	}
	printf("\n&A[0][0] = %p\n", &A[0][0]);
	printf("*(&A[0][0]) = %d\n", *(&A[0][0]));
	printf("&A[0] = %p\n", &A[0]);
	printf("A = %p\n", A);
	printf("&A = %p\n", &A); 
	printf("*A = %d\n", *A);
	printf("**A = %d\n", **A);
	printf("A[0] = %p\n", A[0]);
	printf("*A[0] = %d\n", *A[0]);
	return 0;
} 
	

執行結果為:
這裡寫圖片描述
從上述結果可以看出,&A[0][0], A[0], A,都指向元素A[0][0], 但是要真正訪問該地址所存的內容時,應該*A[0], **A, 而不能是*A, 因為*A 訪問的是A所存的內容,A中存的是A[0][0] 的地址。

  • 訪問一個二維陣列元素的通用公式:
int A[M][N] = {};
int *pa = A;
pa = pa + i * N + j; //訪問元素A[i][j]。
printf("%d", *pa);

#三、指向陣列的指標變數指向二維陣列某一行
這部分內容與上面的有點重複,但是為了更好地理解,我還是要寫。
先說明一點, A[i]無條件等於*(A+i)
所以我們為了讓“二維陣列名+1” 指向二維陣列的下一行,考慮是否定義一種特別的指標, 當該指標加一時能指向二維陣列下一行,而不是下一個元素。下面讓我們來定義一個這樣的指標。

指向陣列的指標變數的定義和使用

語法 樣列 說明
資料型別(*指標變數名)[m]; int A[3][4];int (*p)[4]; p = A; 定義指標變數,指向由m個某資料型別元素組成的一維陣列。圓括號不能丟失,否則變成“指標陣列”

這裡需要注意的是,定義方式int (*p)[M]; ①M是指該陣列的列數。②不要忘了圓括號(*p)
有了上面的定義,二維陣列各元素的地址可以通過指標p來表示。For example:

*(p+0)+0 *(p+0)+1 *(p+0)+2 *(p+0)+3
*(p+1)+0 *(p+1)+1 *(p+1)+2 *(p+1)+3
*(p+2)+0 *(p+2)+1 *(p+2)+2 *(p+2)+3

當然這裡也可以直接用二維陣列名錶示,**比如*(p+0)+1 可以寫成是*(A+0)+1。**下面程式碼驗證這兩種情況:

/*This program is used to find the max in each row of a matrix*/

#include <stdio.h>
#define M 3
#define N 4
int main()
{
	int A[M][N], i, j, max;
	int (*p)[N];
	p = A;	
	for(i = 0; i < M;i++)
	{
		for(j = 0;j < N;j++)
		{
			scanf("%d", &A[i][j]);
		}
	}
	
	printf("--------matrix-------\n");
	for(i = 0; i < M;i++)
	{
		printf("row %d: ", i);
		for(j = 0;j < N;j++)
		{
			printf("%3d", *(*(A+i)+j));
		}
		printf("\n");
	}
	printf("\n");
	
	for(i = 0;i < M;i++)
	{
		max = A[i][0];
		for(j = 0; j < N;j++)
		{
			if(max < *(*(p + i)+j))
			{
				max = *(*(p + i)+j);
			}
		}
		printf("row %d :max = %d\n", i, max);
	}
	return 0; 	
} 

執行結果為:
這裡寫圖片描述
送福利了