指針和數組的關系


指針是一個值為地址的變量,即存儲地址的變量,地址沒有數據類型之說,char *,int *都是一樣的長度,跟機器有關。

int *a表示a地址處存儲的值為整型。

指針的初始化

int a = 10;
int *b = &a;

 或者

1 int a = 10;
2 int *b;
3 b = &a;

指針的解引用

通過*b,可以對指針b進行解引用(間接訪問)從而訪問得到a的值。在指針解引用之前需要對它進行檢查,判斷b是否為NULL

指針常量和常量指針

int *p表示指向整型的指針,也叫整型指針,int const *p和int * const p兩個變量則不同,根據const和*的順序,int const *p中表示常量指針,int * const p表示指針常量,其中常量指針也可寫作const int *p。

常量指針(與整型指針類比),表示指針指向的值是常量,不可修改。指針常量,表示指針是常量,地址不可修改。

1 int a,b;
2 
3 int * const p = &a; //指針常量
4 *p = 9; //操作成功
5 p = &b; //操作錯誤
6 
7 int const * m = &a; //常量指針
8 *m = 9; //操作錯誤
9 m = &b; //操作成功

指向常量的指針常量該怎么寫? 

 1 const int * const b = &a;//指向常量的指針常量 

 

數組

在討論一維和二維數組之前,先討論一下數組首地址和首元素地址雖然首元素地址和首地址在數值上是相同的,但是它們所表示的意義卻不相同:

(1)數組的首元素地址:表示數組的首個元素的地址。

(2)數組的首地址:表示整個數組的地址。

只有使用“&數組名”時,才是取數組首地址;數組名或者&數組名[0]都是取得數組首元素地址,另外,首地址+1得到的是跳過整個數組的地址,首元素地址+1得到的是下一個元素的地址。

1.一維數組

int b[10],其中數組名b的值表示一個指針常量,是第一個元素的地址,該地址不可修改,但所指向的值可以修改。

當數組名在表達式中使用時,編譯器為它產生一個指針常量,除了兩種情況數組名不用指針常量來表示:sizeof和&。sizeof返回整個數組的長度(以字節為單位),而不是指向數組的指針的長度。&取一個數組名的地址所產生的是一個指向數組的指針,而不是一個指向指針常量的指針。

1 int a[10];
2 int *c;
3 
4 c = &a[0]; //第一個元素的地址
5 c = a; //c指向數組第一個元素
6 
7 a = c; //錯誤,數組名是常量指針,該值不可修改
8 *a = 1;//指向的值可以修改

(1)一維數組下標訪問和指針間接訪問

聲明一個數組a,a和&a[0]表示同一個地址,對數組中的值進行訪問時,*a和a[0]都表示第一個元素,*(a+n)和a[n]同。

 1 int a[10] = {0,1,2,3,4,5,6,7,8,9};
 2 
 3 int *b = a+1; //b指向a[1]
 4 //int *b = &a[1];
 5 
 6 //從b的角度訪問
 7 printf("%d", *b++);
 8 printf("%d", b[0]);
 9 printf("%d", b[-1]);
10 
11 
12 //從a的角度訪問
13 printf("%d", a[n]);
14 printf("%d", *(a+n));

上述代碼中3、4兩條語句表示的意思相同,表示b指向a[1]。C的下標引用和間接訪問表達式是一樣的,其中b[0]表示a[1],b[-1]表示a[0].

另外注意數組的間接訪問形式,a數組名是指針常量不可以用如下方式訪問:

1 printf("%d", *a++);
2 
3 a+=n;
4 printf("%d", *a);

(2)一維數組進行函數傳參

一般的函數傳參分為傳值和傳址,傳值意味着對實參沒有影響,僅僅是對拷貝進行操作;傳址意味着可以訪問實參指針所指向的值,也可以對其進行操作。

數組傳參比較有趣的地方在於既是傳址也是傳值。傳址是傳遞數組的地址或首元素的地址,可以通過該指針對數組進行間接訪問,也修改數組值;傳值是因為,對形參指針的操作並不影響實參指針。

 1 #include <stdio.h>
 2 #include<stdlib.h>
 3 
 4 void mytest_(int *a){
 5     a++;
 6     printf("指針形參sizeof(a) = %d\n", sizeof(a));
 7 }
 8 
 9 void mytest(int a[]){
10     *a = 100;
11     printf("數組形參sizeof(a) = %d\n", sizeof(a));
12 }
13 
14 int main(){
15     int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
16     printf("實參*a = %d\n", *a);
17     printf("數組sizeof(a) = %d\n", sizeof(a));
18     
19     mytest_(a);
20     printf("實參*a = %d\n", *a);
21     
22     mytest(a);
23     printf("實參*a = %d\n", *a);
24     system("pause");
25     return 0;
26 }

輸出如下結果:

另外在前面C語言操作符提到過sizeof的操作數為數組名時,返回整個數組的長度,這個僅限於非傳參函數的數組,如代碼中main函數第一次sizeof所示。若數組作為參數進行傳參,即使形參是數組形式,在函數中依然表示為指針,因此更加准確的參數形式應該為指針而非數組名,此時sizeof表示的是指向整型的指針的長度,而不是數組的長度。

(3)字符數組和字符串常量初始化

1 char a[] = "HELLO";
2 char *b = "HELLO";

字符數組初始化,可以寫明元素個數,也可不寫(自動計算數組的長度),但進行字符串處理時必須寫明元素個數。對字符數組進行初始化,看上去與字符串常量相同,a為字符數組,字符串常量b表示指向字符的指針。

2.二維數組

 如果數組的維數不止一個,則為多維數組,這里以二維數組為例。

 1 int a[6][10]; 

a表示二維數組,實質上可以說是一維數組的一維數組,包含了6個元素的數組,每個元素是包含了10個元素的數組。

a這個名字的值是指向它第一個元素的指針,所以a是一個指向10個整型元素的數組的指針,又稱數組指針

 1 char a[2][2] = {1, 2, 3, 4};
 2 
 3 
 4 //第二行第一個元素的地址 5 printf("%d\n", *(a + 1));
 6 printf("%d\n", a[1]);
 7 printf("%d\n", &a[1][0]);
 8 
 9 //第二行第一個元素
10 printf("%d\n", **(a + 1));
11 printf("%d\n", *a[1]);
12 printf("%d\n", a[1][0]);
13 
14 //第二行第二個元素地址
15 printf("%d\n", *(a + 1)+1);
16 printf("%d\n", a[1]+1);
17 printf("%d\n", &a[1][1]);
18 
19 //第二行第二個元素
20 printf("%d\n", *(*(a + 1)+1));
21 printf("%d\n", *(a[1]+1));
22 printf("%d\n", a[1][1]);

(1)訪問地址

其中a是第一行元素的地址,*a和a[0]相同,表示第一行第一個元素的地址,&a[0][0]表示第一行第一個元素的地址,因此a=&a[0]=&(&a[0][0]),a表示地址的地址

a+n表示第n+1行元素地址,*(a+n)和a[n]相同,表示第n+1行第一個元素的地址,&a[n][0]表示第n+1行第一個元素的地址,因此a+n=&a[n]=&(&a[n][0])。

*(a+n)+n和a[n]+n表示第n+1行第n+1個元素地址

(2)訪問元素

從上面地址中可以看出,訪問第n+1行第n+1個元素,可以用a[n][n]和*(*(a+n)+n)

(3)二維數組進行函數傳參

二維數組int a[2][3]中a是一個指向整型數組的指針,又名數組指針。

int a[2][2];
int(*p)[2] = a;

 多維數組進行函數傳參時,下面兩種形式任選一種即可

void func(int (*p)[2]);
void func(int p[][2]);

  二維數組傳參時編譯器必須知道第2個維度的長度才能對各下標進行求值(下標引用和間接訪問一樣),第1個維度的長度並不需要,因此可以寫成指針的形式。但不能將其聲明為

 1 void func(int **p); 

指向整型指針的指針和指向整型數組的指針不是一回事。首先整型數組並不是整型指針,只有在某些表達式中,可以作為數組名可以作為一個指針常量,而且二維數組作為函數傳參只能省略第一維參數 。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM