C++的指針總結


引言

初入c++,肯定會對指針這個概念非常熟悉但是為什么c/c++要使用指針?

其實每一種編程語言都使用指針,指針並不只是C/C++的獨有特性。C++將指針暴露給了用戶(程序員),而Java和C#等語言則將指針隱藏起來了。不光如此,指針還有很多妙用,后面會着重展開詳解。 


 一,指針(*)的概念分析

指針是一個變量,其值為另一個變量的地址,即,內存位置的直接地址。就像其他變量或常量一樣,您必須在使用指針存儲其他變量地址之前,對其進行聲明。指針變量聲明的一般形式為:

指針的類型 *指針變量的名稱;
eg: int *p

要搞清一個指針需要搞清指針的四方面的內容:

  • 指針的類型
  • 指針所指向的類型
  • 指針的值或者叫指針所指向的內存區
  • 指針本身所占據的內區。 

相關鏈接:一文讓你不再害怕指針之C指針詳解(經典,非常詳細) - 知乎 (zhihu.com)

指針的類型(即指針本身的類型)和指針所指向的類型是兩個概念。必須加以區分!!!

首先,先來看幾個復雜類型的指針聲明(有難入易更容易理解)

int p; //這是一個普通的整型變量
int *p; //首先從P 處開始,先與*結合,所以說明P 是一個指針,然后再與int 結合,說明指針所指向的內容的類型為int 型.所以P是一個返回整型數據的指針
int p[3]; //首先從P 處開始,先與[]結合,說明P 是一個數組,然后與int 結合,說明數組里的元素是整型的,所以P 是一個由整型數據組成的數組
int *p[3]; //首先從P 處開始,先與[]結合,因為其優先級比*高,所以P 是一個數組,然后再與*結合,說明數組里的元素是指針類型,然后再與int 結合,說明指針所指向的內容的類型是整型的,所以P 是一個由返回整型數據的指針所組成的數組
int (*p)[3]; //首先從P 處開始,先與*結合,說明P 是一個指針然后再與[]結合(與"()"這步可以忽略,只是為了改變優先級),說明指針所指向的內容是一個數組,然后再與int 結合,說明數組里的元素是整型的.所以P 是一個指向由整型數據組成的數組的指針
int **p; //首先從P 開始,先與*結合,說是P 是一個指針,然后再與*結合,說明指針所指向的元素是指針,然后再與int 結合,說明該指針所指向的元素是整型數據.由於二級指針以及更高級的指針極少用在復雜的類型中,所以后面更復雜的類型我們就不考慮多級指針了,最多只考慮一級指針.
int p(int); //從P 處起,先與()結合,說明P 是一個函數,然后進入()里分析,說明該函數有一個整型變量的參數,然后再與外面的int 結合,說明函數的返回值是一個整型數據
Int (*p)(int); //從P 處開始,先與指針結合,說明P 是一個指針,然后與()結合,說明指針指向的是一個函數,然后再與()里的int 結合,說明函數有一個int 型的參數,再與最外層的int 結合,說明函數的返回類型是整型,所以P 是一個指向有一個整型參數且返回類型為整型的函數的指針

二,指針的算術運算

指針是一個用數值表示的地址。因此,您可以對指針執行算術運算。可以對指針進行四種算術運算:++、--、+、-。

假設 ptr 是一個指向地址 1000 的整型(int)指針,是一個 32 位的整數,讓我們對該指針執行下列的算術運算:

ptr++

在執行完上述的運算之后,ptr 將指向位置 1004。如果 ptr 指向一個地址為 1000 的字符(char),上面的運算會導致指針指向位置 1001,因為下一個字符位置是在 1001。

因為int類型在32位程序中占4個字節,字符char類型占1個字節

遞增一個指針

我們喜歡在程序中使用指針代替數組,因為變量指針可以遞增,而數組不能遞增,因為數組是一個常量指針。下面的程序:

例如,一個指向數組開頭的指針,可以通過使用指針的算術運算或數組索引來訪問數組。請看下面的程序:(遞增變量指針(ptr++),以便順序訪問數組中的每一個元素

#include <iostream>

using namespace std;
const int MAX = 3;

int main()
{
    int  var[MAX] = { 10, 100, 200 };
    int* ptr;

    // 指針中的數組地址(指針指向數組開頭)
    ptr = var;
    for (int i = 0; i < MAX; i++)
    {
        cout << "Address of var[" << i << "] = ";
        cout << ptr << endl;

        cout << "Value of var[" << i << "] = ";
        cout << *ptr << endl;

        // 移動到下一個位置
        ptr++;
    }
    return 0;
}

三,運算符&和*

C++ 提供了兩種指針運算符

  • 取地址運算符 && 是一元運算符,返回操作數的內存地址。例如,如果 var 是一個整型變量,則 &var 是它的地址。&var 的運算結果是一個指針
  • 間接尋址運算符 * 間接尋址運算符 *,它是 & 運算符的補充。* 是一元運算符,返回操作數所指定地址的變量的值。
int main ()
{
   int  var = 3000;
   int  *ptr;
   int  val;
// 獲取 var 的地址
ptr = &var; //輸出prt=0xbff64494(即3000的地址)
// 獲取 ptr 的值
val = *ptr; //輸出val=3000
}

四,數組和指針的關系

 數組的數組名其實可以看作一個指針。看下例:

int array[10]={0,1,2,3,4,5,6,7,8,9},value;  
...  
...  
value=array[0];//也可寫成:value=*array;  
value=array[3];//也可寫成:value=*(array+3);  
value=array[4];//也可寫成:value=*(array+4);  

上例中,一般而言數組名array代表數組本身,類型是int [10],但如果把array看做指針的話,它指向數組的第0個單元,類型是int *,所指向的類型是數組單元的類型即int。因此*array等於0就一點也不奇怪了。同理,array+3是一個指向數組第3個單元的指針,所以*(array+3)等於3。其它依此類推。 

 五,指針和結構類型的關系

 可以聲明一個指向結構類型對象的指針。

struct MyStruct  
{ 
       int a;  
       int b;
       int c;  
}  
MyStruct ss={20,30,40};//聲明了結構對象ss,並把ss的三個成員初始化為20,30和40。
MyStruct *ptr=&ss;//聲明了一個指向結構對象ss的指針。它的類型是MyStruct*,它指向的類型是MyStruct。

怎樣通過指針ptr來訪問ss的三個成員變量?  

ptr->a;  
ptr->b;  
ptr->c; 

 六,傳遞指針給函數

C++ 允許傳遞指針給函數,只需要簡單地聲明函數參數為指針類型即可。

下面的實例中,我們傳遞一個無符號的 long 型指針給函數,並在函數內改變這個值:

#include <iostream>
#include <ctime>

using namespace std;

// 在寫函數時應習慣性的先聲明函數,然后在定義函數
//定義一個函數(參數為指針)
void getSeconds(unsigned long* par);

int main()
{
    unsigned long sec;
    getSeconds(&sec);//獲取sec的地址
    // 輸出實際值
    cout << "Number of seconds :" << sec << endl;
    return 0;
}

void getSeconds(unsigned long* par)
{
    // 獲取當前的秒數
    *par = time(NULL);
    return;
}

 七,從函數返回指針

 C++中函數是不能直接返回一個數組的,但是數組其實就是指針,所以可以讓函數返回指針來實現:

 另外,C++ 不支持在函數外返回局部變量的地址,除非定義局部變量為 static 變量。

要想返回一個數組,使用智能指針之類的東西才是正途。(后續總結智能指針。。。)

 


免責聲明!

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



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