C語言指標——指標與陣列

2021-03-22 14:00:17

種一棵樹最好的時間是十年前,其次是現在。

指標與陣列

一、指標的運算

指標可以進行三種運算:

1.指標加上整數

如果指標p指向陣列a[i],那麼指標p + j 指向a[i + j](前提是a[i + j]存在!)

2.指標減去整數:

如果指標p指向陣列a[i],那麼指標p - j 指向a[i - j](前提 a[i - j] 存在!)

3.兩個指標相加減兩指標必須指向同一變數!!!否則運算沒有意義的!

當兩個指標相減時,結果是指標在記憶體上的距離,可以用陣列元素的個數來度量,所以如果指標p指向a[ i ],q指向a[ j ],那麼p - q就等於i - j.

指標比較:指標可以使用 >  <  =  >=  <=  ==  != 等符號進行比較,(也是隻有在指標指向同一陣列時,使用關係運算子進行的指標比較才有意義!)

二、指標用於陣列的處理

由於指標的算術運算,所以我們可以通過指標的自增自減來存取陣列的元素。

#include<stdio.h>

int main()
{
	int a[10] = {0,1,2,3,4,5,6,7,8,9};
	int *p;
	for(p = &a[0];*p < a[10];p++)
	{
		printf("%d\n",*p);
	}
	
	
	return 0;
}

使用陣列下標可以寫出不用指標的迴圈,有一種論調說使用指標可以節省時間,不過對於現在的編譯器來說,實際上會自動對使用下標的迴圈進行優化,即依靠下標的迴圈會產生更好的程式碼(大佬說的 [^.^])

 

*和++組合使用:

#include<stdio.h>

int main()
{
	int a[10] = {0,1,2,3,4,5,6,7,8,9};
	int *p = &a[0];// *p = a;
	while (*p < a[10])
	{
		printf("%d\n",*p++);
	}	
	return 0;
}

當然還有*++p、(*p)++

三、用陣列名作為指標

1.可以用陣列名作為指向陣列第一個元素的指標。例如int a[10] ;    *a = 7 ;這樣就是把a[0]元素給他賦值7。通常情況下a + i 就相當於&a[i] ,*(a + i) 就相當於a[i]。

2.陣列變數本身表達地址,所以用陣列對指標初始化不用&取地址符號,int a[10]; int *p = a;    。但是陣列的每一個元素表達的是一個變數,需要取地址符&。 

3.[ ]也可以對指標做,p[0] 相當於a[0] 。*也可以對陣列做, *a 相當於a[0]。

注意:當陣列變數是一個const型別的指標,就不能被賦值了!

 

4.陣列作為函數引數

下面我們看一個有趣的東西( It's amazing!):

#include<stdio.h>
void test1(int a[]);

int main()
{
	int a[5] = {0,1,2,3,3};
	printf("main中sizeof(a[]) = %lu\n",sizeof(a));
	
	test1(a);
	
	return 0;
}

void test1(int a[])
{
	printf("函數中sizeof(a[]) = %lu\n",sizeof(a));
}

執行結果如下:

amazing

在函數test1中sizeof傳進去的陣列我們發現他的位元組大小是8!而不是陣列本身的位元組大小 20!有趣吧哈哈哈哈QAQ。這是因為陣列作為引數傳參的時候傳進去的是一個指標!就是之前我們說了的陣列變數是一個特殊的指標。陣列名在傳遞給函數的時候總是被視為指標

這對我們有很大的意義!:

(1).在給函數傳遞普通變數時,變數的值會被複制,任何對相應的形式引數的改變都不會影響到變數。而作為實際引數的陣列我們可以改變(除非const了一下它)!

(2).給函數傳遞陣列的時間與陣列的大小半毛錢關係都沒有!(編譯器:「我根本就沒對你陣列進行復制,沒想到吧!哈哈哈」)

(3).我們可以在需要的時候吧陣列形式引數宣告為指標。(編譯器對陣列和指標的宣告完全看做是一樣滴)

注意:對於形式引數而言,宣告為陣列跟宣告為指標是一樣的;但是對於變數而言宣告為陣列跟宣告為指標是不同的!

5.用指標名當做陣列名(如下程式碼)

#include<stdio.h>

int main()
{
	int a[10],*p = a, i = 0;
	
	for(i = 0;i < 10;i++)
	{
		*p++ = i;
		printf("%d\n",a[i]);
	}
	
	return 0;
}

指針名做函數名

四、指標與多維陣列

int a[4][5] = {{0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};

可以把這個理解為包含四個行元素的陣列:a[0]、a[1]、a[2]、a[3],可以把a[0]

還需要記住的是陣列名為首元素的地址。有這樣的說法a不是a[0][0]的地址,但是我試了一下,結果是它們地址相同,所以總結成一句話:陣列名為首元素地址。

行指標:一個二維陣列每一行視為一個一維陣列,指向每一行的一維陣列的指標。

處理多維陣列的行:

#include<stdio.h>

int main()
{
	int a[4][5] = {{0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};
	int *p,i = 0,j = 4;
	i = 3;
	for (p = a[i];p < a[i] + j;p++)//p = a[i]給p初始化.p < a[i] + j 中a[i]+j表示的是a[i][j] 
	{
		*p = 0;
	}
	
	printf("%d\n",a[i][2]);//輸出驗證第i行第2列是否為0 
	return 0;
}

p++執行一次之後 就相當於 p +1 就相當於 a[i] +1 就相當於 a[i][1]

處理多維陣列的列:

#include<stdio.h>

int main()
{
	int a[4][5] = {{0,1,2,3,4},{10,11,12,13,14},{20,21,22,23,24},{30,31,32,33,34}};
	int (*p)[5],i = 2;//(*p)的括號不可省略![5]這個表示的是一維陣列的長度,不可省略!定義了一個行指標,其寬度為5(即二維陣列的列數為5) 
	for ( p = &a[0]; p < &a[4];p++)//p=&a[0]是把第0行那個一行的一維陣列的地址交給p這個行指標  &a[4]相當於a+4. p=&a[0]相當於p=a 
	{
		(*p)[i] = 0;//(*p)這裡代表著a的一整行 
	} 
	printf("%d\n",a[2][i]);//輸出驗證第2行第2列是否為0 
	return 0;
}