關於函數(二)數組指標和指標數組__函數

來源:互聯網
上載者:User

參考http://blog.csdn.net/touch_2011/article/details/6966980 1、概述 指標數組:指標數組可以說成是”指標的數組”,首先這個變數是一個數組,其次,”指標”修飾這個數組,意思是說這個數組的所有元素都是指標類型,在32位系統中,指標佔四個位元組。 數組指標:數組指標可以說成是”數組的指標”,首先這個變數是一個指標,其次,”數組”修飾這個指標,意思是說這個指標存放著一個數組的首地址,或者說這個指標指向一個數組的首地址。
根據上面的解釋,可以瞭解到指標數組和數組指標的區別,因為二者根本就是種類型的變數。 2、數組指標(指向數組的指標) (1)數組在記憶體中的表示

建立一個數組就是在記憶體裡面開闢一塊連續的空間,比如int a[4];就是在記憶體裡面開闢了一個大小為4*sizeof(int)位元組的記憶體空間。二維數組是特殊的一維數組。
先來看一段代碼:

void main()  {      int a[2][2]={1,2,3,4};//這是一個2*2的二維數組      int (*p)[2];//數組指標      p=a;//令p指向數組a  }

注意到代碼中這句話:int (*p)[2];這裡的p是一個數組指標變數。
a中各個元素在記憶體中是這樣存放的:
(2)理解數組名和數組指標變數

現在我們思考a,a[0],a[1],p,a+1,a[0]+1,p+1到底是什麼。

分析:
1. a是一個數組名,類型是指向一維數組的指標,不是變數,a的值是指標常量,即不能有a++或者a=p這些操作。a指向這塊連續空間的首地址,值是&a[0][0]。
2. a[0]是一維數組名,類型是指向整型的指標,值是&a[0][0],這個值是一個常量。
3. a[1]是一維數組名,類型是指向整型的指標,值是&a[1][0],這個值是一個常量。
4. p是一個數組指標變數,指向一維數組的指標變數,值是&a[0][0]。可以執行p++;p=a等操作。
5. a+1表示指向下一行元素,也可以理解為指向下一個一維數組。
6. *(a+1)是取出第一行的首地址。
7. a[0]+1是指向第0行第1個元素,也可以理解為指向一維數組a[0]的第一個元素。
8. p+1同a+1
9. *(p+1)和*(a+1)
10. 雖然a跟a[0]值是一樣,但類型不一樣,表示的意義不一樣。通過分析就不難理解為什麼((a+i)+j)和a[i][j]等效了。

       既然pa是一個指標,存放一個數組的地址,那麼在我們定義一個數組時,數組名稱就是這個數組的首地址,那麼這二者有什麼區別和聯絡呢。

int  a[2];

a是一個長度為2的整型數組,a是這個數組的首元素首地址。既然a是地址,p是指向數組的指標,那麼能將a賦值給p嗎。答案是不行的。因為a是數組首元素首地址,p存放的卻是數組首地址,a是int*類型,a+1,a的值會實實在在的加1,而p是int[2]類型的,p+1,p則會加2,雖然數組的首地址和首元素首地址的值相同,但是兩者操作不同,所以類型不符不能直接賦值,但是可以這樣:p = &a,p相當與二維數組的行指標,現在它指向a[2]的地址。 (3)指標是數組的迭代器

#include<stdio.h>  #define M 2  #define N 3  int main()  {      int a[M][N]={1,2,3,4,5,6};      int *start=&a[0][0];      int * const end=start+M*N;      for(;start!=end;start++)          printf("%-5d",*start);      putchar('\n');      return 0;  }

       理解這段代碼,用指標遍曆一個二維數組,是不是很像C++標準庫裡面vector的迭代器。注意這裡只用了一個for迴圈,這也可以說明二維數組其實就是特殊的一維數組。 (4)數組名與數組指標變數的區別

       從(2)中的分析中得出數組名是指標,類型是指向元素類型的指標,但值是指標常量,聲明數組時編譯器會為聲明所指定的元素數量保留記憶體空間。數組指標是指向數組的指標,聲明指標變數時編譯器只為指標本身保留記憶體空間。

看看這個代碼:

#include<stdio.h>  void main()  {      int a[2][2]={1,2,3,4};//這是一個2*2的二維數組      int (*p)[2];//數組指標      p=a;//令p指向數組a      printf("%d\n%d\n",sizeof a,sizeof p);  }


       注意當sizeof用於變數時返回這個變數佔用的實際空間的大小。當sizeof用於數組名時,返回整個數組的大小(這裡的大小指佔用的位元組數)。p是一個指標變數,這個變數佔用四個位元組。而a是數組名,所以sizeof a返回數組a中的全部元素佔用的位元組數。瞭解了sizeof,看下面這段代碼輸出什麼

#include<stdio.h>  void main()  {      int a[2][2]={1,2,3,4};//這是一個2*2的二維數組      int (*p)[2];//數組指標      p=a;//令p指向數組a      printf("%d\n%d\n",sizeof(a+1),sizeof(p+1));      printf("%d\n%d\n",sizeof(a+0),sizeof(p+0));  }


從結果中看出,a在做+運算時是轉化成了指標變數,此時a+i的類型是一個指標變數,而不是一個數組名。但a[i]是一個一維數組的數組名,sizeof(a[0])的值是8。

現在再來看一段代碼:

#include<stdio.h>  void f(int a[][2])  {      printf("%d\n",sizeof a);  }  void main()  {      int a[2][2]={1,2,3,4};//這是一個2*2的二維數組      printf("%d\n",sizeof a);      f(a);  }


       解釋:這是因為傳參的時候數組名轉化成指標變數,注意到函數f中f(int a[][2])這裡並不需要指定二維數組的長度,此處可以改為int (*a)[2]。所以傳過來的就是一個數組指標變數。

       總結: 數組名的類型是指向元素類型的指標,值是指標常量。(a+1)的類型是一個指標變數。把數組名作為參數傳遞的時候實際上傳遞的是一個指標變數。sizeof對變數和數組名操作時返回的結果會不一樣。數組指標是指向數組的指標,其值可以是變數。 2、指標數組(存放指標的數組) (1)認識指標數組

       一個存放int類型的數組稱為整型數組,那麼存放指標的數組就叫指標數組。

#include<stdio.h>  void main()  {      int i=1,j=2;      //p先跟[]結合,然後再跟*結合      int *p[2];//指標數組,存放指標的數組      p[0]=&i;      p[1]=&j;      printf("%d",sizeof(p));  }


此例數組p就兩個元素,p[0]是指向i的指標,p[1]是指向j的指標。這兩個指標都是int型指標,所以p是存放int型指標的數組。sizeof(p)返回數組佔用的總空間,所以程式輸出是8。 (2)深入瞭解

       首先先定義一個指標數組,既然是數組,名字就叫arr。

char *arr[4] = {"hello", "world", "shannxi", "xian"};//arr就是我定義的一個指標數組,它有四個元素,每個元素是一個char *類型的指標,這些指標存放著其對應字串的首地址。

       當一個變數出現左右都出現一個運算子時,沒有記住運算子優先順序的人就會糾結arr變數到底跟哪一個運算子先結合。如果是自己定義一個指標數組,搞不清楚運算子的優先順序,那麼就加上小括弧(),比如定義一個指標數組,可以寫成char *(arr[4]),不過在定義之前一定要清楚自己定義的變數,如果目的是一個數組,那就把arr[4]括起來,如果是一個指標,就把*arr括起來。如果是看到一段這樣的代碼,可以從他的初始化來分別它是數組還是指標,很明顯,我這定義的是一個數組,如果是指標,會用NULL來初始化。
       這個指標數組有多大呢。答案是16個位元組,因為它是一個指標數組。每當出現這些問題時,腦子裡一定要第一時間反應出記憶體映像圖。

       這裡最左側一列是一個很簡陋但能說明意思的記憶體配置圖,一般情況下,從棧區到代碼區,是從高地址到低地址。棧向下增長,堆向上增長。

       arr[4]是一個在主函數定義的數組。把它對應到對應到記憶體中,arr是一個在棧區,有四個元素的數組,而每一個數組又是一個指標,所以說它的四個元素各佔四個位元組,所以變數arr的大小是16個位元組。

       初始化arr的{“hello”, “world”, “shannxi”, “xian”};的這四個存在在記憶體中,只是跟arr這個變數不在同一段空間,它們被分配在唯讀資料區,數組arr[4]的四個指標元素,分別存放著這四個字串的首地址,想象一下,從棧區有四隻無形的手指向資料區的空間。arr+1會跳過四個位元組,。也就是一個指標的大小
這就相當與定義char *p1 = “hello”,char *p1 = “world”,char *p3 = “shannxi”, char *p4 = “xian”,這是四個指標,每個指標存放一個字串首地址,然後用arr[4]這個數組分別存放這四個指標,就形成了指標數組。 (3)指標數組排序


指標數組的排序非常有趣,因為這個數組中存放的是指標,通過比較指標指向的字串的字典序,排序這些指標。函數實現如下:

void sort(char **pa, int n)//冒泡排序{    int i, j;    char *tmp = NULL;    for(i = 0; i < n-1; i++){        for(j = 0; j < n-1-i; j++){            if(strcmp(*(pa+j), *(pa+j+1)) > 0){                tmp = *(pa + j);                *(pa + j) = *(pa + j + 1);                *(pa + j + 1) = tmp;            }        }    }}
3、聲明返回數組指標的函數 1、數組不能被拷貝,函數不能返回數組,只能返回數組的指標或者引用。
typedet int arr[10]; //arr是類型別名,表示的類型含有10個整數的數組  using arr=int[10];    //與上面等效
int arr[10];   //arr是一個含有10個整數的數組  int *p1[10];  //p1和[ ]的結合度要高,所以p1首先是一個10個大小的數組,即這裡的p是一個數組名,其次是與*結合,表示數組中每個元素都是整型指標  int (*p)[10]=&arr;  //由於括弧p首先與*結合,即p是一個指標,然後才與[ ]結合,說明p指標指向大小為10的一個數組,且p指標初始化,p是一個數組指標 
2、聲明返回數組的指標

①返回函數指標的函數形式如下:

Type(*function(parameter_list))[dimension] int (*func(int i))[10];
func(int i) 意味著調用func函數時需要一個int類型的實參 (*func(int)) 意味著對函數調用的結果是一個指標 (*func(int i))[10] 意味著對函數調用結果的指標是一個指向數組,數組大小為10 int (*func(int))[10] 意味著對函數調用結果的指標指向的數組中,數組元素都是整型的。

但如果我們使用類型別名,聲明一個返回數組指標的函數的函數就看起來要優雅多了

using arrT=int[10]; //arr是大小為10的數組的一個別名,即相當於把int[10]看成是一種類型,該類型是一個整型數組,大小為10  arrT* func(int i);  
3、使用尾置傳回型別

       任何函數的定義都能使用尾置返回,它在形參列表後以一個 -> 符號開頭,為表示函數真正的傳回型別在形參列表之後,我們在最前放置一個auto,比如:

auto func(int i)->int(*)[10];  //func接受一個int類型的實參,返回一個指標,指標指向10個整數的數組 

於是現在就可以清楚地看到func函數返回的是一個指標,該指標指向10個整數的數組。 4、使用decltype

       如果知道函數返回的指標指向哪個數組還可以使用decltype關鍵字聲明傳回型別,比如一個典型的例子:

#include<iostream>  int odd[] = { 1, 3, 5, 7, 9 };  int even[] = { 0, 2, 4, 6, 8 };  decltype(odd)* func(int i)  {      return (i & 1) ? &odd : &even;  }  int main()  {      std::cout << (*func(1))[2]<< std::endl;      std::cout << (*func(2))[2] << std::endl;  }  


deltype的作用只是負責推匯出運算式的類型,並不負責將數群組類型轉換成對應的指標,在這裡是推匯出odd的類型是一個大小為5的數組,但只是數組這種類型,要讓成為一個指向這個類型的的指標,和正常一樣加上*即可。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.