C++指針

引言:運行下列代碼。

#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
int t=7;
int *a;//這顯然是定義了一個指針,int* a等價於int *a
a=new int;
a=&t;
printf("%d ",*a);
        printf("%p",a);
        delete a;
return 0;
}

    運行結果,在我的電腦上是7 0023FF18。放着問題不說,先講結論。

    我們要研究指針,需要知道四個內容:指針的類型,指針指向的變量的類型,指針的值,指針本身佔據的內存區域(首先我們要知道指針是“指”向一個變量的變量)。

    1. 指針的類型:定義的形式在程序段中寫了。我們可以把指針的名稱去掉,看剩餘部分。下面是幾個例子。

    int *p;  int *()表示我們定義了一個指向整形的指針變量。這是一個相當單純的指針類型,那麼對於更復雜的指針類型,我們如何分析?

    int *p[3]; 首先p與“[]”結合,表明p是一個數組(“[]”的優先級比“*”高)。再與“*”結合,表明p裏面的元素是指針。最後與int結合,表明p裏面的指針元素是指向整形的。

    int (*p)(int); p先與“*”結合,表明p是一個指針,再與“()”結合,說明這是一個函數,且該函數有一個整形參數。再與最外面的int結合,說明該函數的返回值爲整形。因此p是一個指向一個有一個整形參數且返回值爲整形的函數的指針。

    2.指針指向的變量的類型:只需把指針的名稱和其左邊的“*”去掉,剩下的部分就是指針指向的變量的類型。

    3.指針的值:在這裏我終於要填坑了。之前我們有這樣一句話:a=new int; 這句話的意思是爲指針a開闢內存空間。我們知道計算機存儲數據都是需要空間的(這裏俺也知道的不多,就不細講了……)同理,我們程序中的變量也有自己的空間。計算機訪問變量是通過訪問變量所在的地址實現的。指針的“值”,也就是指針指向的變量的地址。後面我們還有一句話:delete a; 這句話的意思是釋放指針a 的內存空間,也就是說這一步之後指針a就沒有內容了。還有,之前輸出了一個指針的地址。如果你多試幾次,你會發現那個值是固定的,而且就算你關閉C++再重啓也是一樣,但如果你關機重啓,它就會是另一個固定的值了。
    我們都知道,賦值號左右的部分必須是類型相同的量。那麼這一句話:a=&t; “&”的作用就呼之欲出了,沒錯,“&t”的作用就是返回t的地址。你可能會問,爲什麼使用指針a的時候不帶“*”號?那是因爲“*”的作用是表明a是一個指針,當我們用的時候只要用指針的名稱就行了。就好像定義常量的時候我們會寫:const int a=7; 但後面用的時候我並不必帶上“const”。在回想一下其餘的部分。我們經常見到的使用“&”的時候是使用“scanf”時,現在我們知道了,是因爲“scanf”是需要用到地址。但指針本來就是一個地址,所以,如果想讀入指針,直接讀就好了。Code如下:

#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
int *a=new int;
scanf("%d",a);
printf("%d",*a);
return 0;
}

    4.指針自己所佔的內存:指針指向某個變量在內存中的地址,它自己也肯定佔一定的空間。指針本身佔了多大的內存?你只要用函數sizeof(指針的類型)測一下就知道了。在32位平臺裏,指針本身佔據了4個字節的長度。

    5.指針的算術運算

    如果你給一個指針加上或減去一個數n(咱只知道整數),那麼相當於加上或減去n*(sizeof(指針指向的變量的類型))。在數組中比較常用。

Code:

int a[20];  
int *p=a;//我略去了開空間的步驟,大家別忘啊!  
...  
//此處略去爲整型數組賦值的代碼。  
...  
for (i=1; i<=20; i++)  
{  
    (*p)++;  
    p++;  
}

上述代碼可以用來給整個數組中的元素加1。是不是有點danteng……不要在意這些細節啦。

    6.指針與數組名

    數組名其實也就是一個指針。所以我們可以這樣:

value=a[0];//也可寫成:value=*a;  
value=a[3];//也可寫成:value=*(a+3);  
value=a[4];//也可寫成:value=*(a+4); 

    值得注意的是數組名有雙重含義,所以a++之類的操作是不行的。

    7.指針與結構類型

    我們看下面的代碼:

struct node  
{  
int a,b,c;  
};  

node ss={20,30,40};//聲明瞭結構對象ss,並把ss的三個成員初始化爲20,30和40。
node *p1=&ss;//聲明瞭一個指向結構對象ss的指針。它的類型是node*,它指向的類型是node。
int *p2=(int*)&ss;//聲明瞭一個指向結構對象ss的指針。但是它的類型和它指向的類型和ptr是不同的。

    我們怎麼用指針p1和p2訪問ss的三個成員呢?

p1->a;
p1->b;
p1->c;
*p2;//訪問了ss的成員a。  
*(p2+1);//訪問了ss的成員b。  
*(p2+2)//訪問了ss的成員c。

    但其實p2的方法是不規範的。爲什麼呢?

    所有的C/C++編譯器在排列數組的單元時,總是把各個數組單元存放在連續的存儲區裏,單元和單元之間沒有空隙。但在存放結構對象的各個成員時,在某種編譯環境下,可能會需要字對齊或雙字對齊或者是別的什麼對齊,需要在相鄰兩個成員之間加若干個“填充字節”,這就導致各個成員之間可能會有若干個字節的空隙。如果你直接訪問的話,那麼你就有很大的可能會訪問到填充字節。









     

     

      

      


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章