指標,指標數組,數組指標,函數指標

來源:互聯網
上載者:User

################################
#                              #
#       基本知識               #
#                              #
################################

當然我們一切都是從最簡單的內建類型開始,最後我會做一些推廣。
先看一下基本的形式,我們從這裡起步!

--------------指標----------------
int a=10;
int *p=&a;

-------------指標的指標-----------
int b=20;
int *p=&b;
int **p2p=&p;

-------------簡單數組-----------------
int c[10];//整數數組,含有10個整數元素
            //也就是說每一個元素都是整數
         
--------------指標數組--------------------
int *p[10];//指標數組,含有10個指標元素
            //也就是說每一個元素都是指標
           
--------------數組指標--------------------
int (*p)[10];//數組指標,這個指標可以用來指向
                 //含有10個元素的整數數組

上面這些簡單的形式是我們必須要首先理解,這個是基本的知識。
同時我們從上面也要得出一個很重要的知識提示:c++語言層面上
關於變數聲明的部分,尾碼結合變數的優先順序比首碼要高的。
看我們上面的例子的最後兩個就明白了,我們為了實現數組指標的
聲明我們不得不變通一下。我們採用()來實現優先順序的改變,實現了
數組指標的聲明。

註:在C語言中[ ]的優先順序為1,*的優先順序為2,這樣[ ]的優先順序比*的要高,這樣就是先p[10]結合聲明一個數組名為p的數組,後再與*結合後為*p[10],其數組元數為 int類型指標,這樣就可以知道int *p[10]就定義了一個指標數組,用來存放unsigned char類型地址,編譯器為該一維數組分配了10個sizeof(int *)的空間.;

對於int (*p)[10],( )的優先順序[ ]相等,這樣就是從左至右結合.就是先(*p)結合聲明一個p的指標,後再與[10]結合聲明一個數組指標後(*p)[10],其p指向10個數組元素,這樣就可以知道int (*p)[10]就定義了一個數組指標,編譯器為p分配了一個指標空間,因為其不是一個數組只是指向數組元素,所以編譯器不為其分得一個數組空間。

################################
#                              #
#      進一步提高知識          #
#                              #
################################

數組,數組的指標,指標的數組,概念太多了。我接受概念一多的
時候,我就想把這些複雜的東西簡單一下。因為我太懶了,概念簡化
一下,記住更容易一點。所以我們這裡要認識一下上面這些概念本質。
這樣可以簡化概念,減少記憶的難度。

先看一段程式。
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
 int vInt=10;
 int arr[2]={10,20};
 
 int *p=&vInt;
 int **p2p=&p;
 
 int *parr[2]={&vInt,&vInt};
 int (*p2arr)[2]=&arr;

 cout<<"Declaration [int vInt=10] type=="<<typeid(vInt).name()<<endl;
 cout<<"Declaration [arr[2]={10,20}] type=="<<typeid(arr).name()<<endl;
 cout<<"Declaration [int *p=&vInt] type=="<<typeid(p).name()<<endl;
 cout<<"Declaration [int **p2p=&p] type=="<<typeid(p2p).name()<<endl;
 cout<<"Declaration [int *parr[2]={&vInt,&vInt}] type=="<<typeid(parr).name()<<endl;
 cout<<"Declaration [int (*p2arr)[2]=&arr] type=="<<typeid(p2arr).name()<<endl;

 return 0;
}

啟動並執行結果如下:(我在前面加了行號#XX)
#01 Declaration [int vInt=10] type==int
#02 Declaration [arr[2]={10,20}] type==int *
#03 Declaration [int *p=&vInt] type==int *
#04 Declaration [int **p2p=&p] type==int * *
#05 Declaration [int *parr[2]={&vInt,&vInt}] type==int **
#06 Declaration [int (*p2arr)[2]=&arr] type==int (*)[2]

現在我們來分析一下結果。因為我們已經具有了第一部分的基本知識,我們現在
可以很明確區別出來我們聲明的類型。這裡主要有兩個很重要的部分,我們不過
是就事講事情,編譯器是如何?的原理不在這裡討論之列。

--------#02:數組------------

現在看#02,想到了什麼沒有呀?在編譯器看來數組只是相對應類型的指標類型。
當我們把數組傳遞給函數作為參數的時候,傳遞的是指標,所以我們可以利用
參數來修改數組元素。這個轉化是編譯器自動完成的。

void f(int[]);
int a[2]={10,20};
f(a);//這行等價於編譯器完成的函數轉化f(int *p)

也就是說這裡編譯器自動完成了int[]類型到int *的轉化,
注意是編譯器完成的,也可以說是語言本身實現的,我們
對此只有接受的份了。

-------#05:指標數組---------------

指標數組的編譯器內部表示也是對應類型的指標。

------#06:數組指標----------------
數組指標的編譯器內部表示就是有一點特別了。
編譯器(或者說是語言本身)有數組指標這個內部表示。
由於c++語言的類型嚴格檢查的語言(當然還有一些是存在隱式類型轉化的)

所以我們下面的寫法是不能編譯通過的。
{
file://---------編譯不能通過--------------
int arr[3]={10,20};//注意是3個元素數組
int (*p2arr)[2]=&arr;//注意是指向2個元素數組的指標
file://---------編譯不能通過--------------
}

################################
#                              #
#      初步小結                #
#                              #
################################

通過上面兩個小節的內容,大家應該基本明白了,
數組,指標,指標數組,數組指標到底是怎麼一回事情了吧。

-----------補充開始-----------------------
關於數組和指標的轉化,以及我們使用指標(++,--)等來運算元組,
是基於數組在記憶體中是連續分布的。

但是我們使用“迭代器”的時候,情況是不一樣的。
這個問題本文不討論。

-----------補充結束---------------------

函數指標數組與返回數組指標的函數
int (*a[])(int);
int (*p())[10];
第一種情況為數組裡面是函數指標的情況,因為(int (*)(int))是一個強制轉換方式, 將裡面的a[]這個數群組轉換成了一個函數指標的數組, 並且該函數是一個帶一個整型變數,並且返回一個整型的函數.
第二種情況為函數返回的為指向一個一維數組的指標的情況. 因為(int (*)[10])將其強制轉換成了一個指標,而該指標則是一個指向一維數組的指標.
分別舉兩個例子進行說明:
對於第一種函數指標數組的情況,如下:
#include<stdio.h>
int fun(int a)
{
        return a+1;
}
int main()
{
        int (*p[10])(int);
        int i;
        p[0] = fun;
        i = (p[0])(10);
        printf("i=%d\n", i);
        return 0;
}
p[10]為一個指標數組,而該指標數組裡面的值為函數指標類型.讓p[0]指向fun()函數.然後再進行調用,就可以調用到fun()這個函數了.

對於第二種返回數組指標的函數,如下:
#include<stdio.h>
#include<stdlib.h>
int (*p())[10]
{
 int (*m)[10];
 int i;
 m = (int (*)[10])malloc(10, sizeof(int));
 if (m == NULL)
 {
  printf("calloc error\n");
  exit(1);
 }
 for (i = 0; i < 10; i++)
  *(*m+i) = i+1;
 return m;
}

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

其實int (*m)[10];這種方式一般是用來指向一個二維數組的,例如
int b[4][10];
int (*m)[10] = b;
其指向二維數組中的一維.
使用*(*(m+i)+j);這種方式就可以訪問b[i][j]這個元素.而上面的是使用這種方式來指向一個一維數組,同樣也是一樣的.只是前面的*(m+i)中的i變為0了.因為只有一維大小.即
int a[10];
int (*m)[10] = &a;
就使得m指向了a這個數組了.而平時所用的int *p = a;只是讓p指向了a的第一個元素.比前面的指向一維數組的指標少了一維.前面的m+1跳過的是10個整型的長度.而後面的p+1則只是跳過了1個整型的長度.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.