1. 程式人生 > >成為C++高手之指標與陣列

成為C++高手之指標與陣列

指標初步

定義一個指標變數:int * a=NULL; int 是指標的型別,其實應該說是指標指向的資料的型別。

程式執行時,資料都是放在記憶體中的,既然在記憶體中,就處於記憶體中的某個位置,這就是資料的地址。指標中儲存的就是這個地址。所以不論什麼型別的指標,指標變數本身之間並沒有區別,值都是一個整數值。32位程式中這個整數是32位的,64位程式中這個整數是64位的。其實指標變數與整型變數之間跟本沒有區別,就看你怎麼解釋它了。一個整數你可以把它解釋為指標也可以解釋為整數,所以指標與整數之間可以輕鬆轉換。

你完全可以定義指標時直接給它賦一個整數值,表示這個指標指向這個整數所代表的地址位置,而這個位置的資料如何去解釋它呢?就看指標的型別了。但是一般我們不能這樣做,這樣容易崩潰,因為你隨便指定的這個位置不是一個有效的位置。所以在使用指標之前要讓指標指向一個有效的位置,比如 a=&b;

b是一個int型變數。“&”是取得b的地址,此時a就指向了一個有效的地址。

使用指標所指向的資料,需要“*a”的方式,比如 *a=100; 這樣看起來很像以間接的方式使用變數b。我們的計算器程式中用到的scanf()函式,其接收使用者輸入值的引數是一個指標,但這個指標必須指向有效的記憶體才能接收到資料,否則會引起崩潰。

要區分好指標與指標指向的資料之間的區別。指標本身佔4個位元組或8個位元組,而指標指向的資料不一定佔多少位元組。比如指向一個char型資料,那麼指標指向的內容只佔一位元組。指標也可能指向了一大塊記憶體,比如用malloc在堆中申請的記憶體。

指標變數本身的銷燬不影響指標指向記憶體,就是說它們倆的生命期是完全沒關係的。一般指標都是臨時變數(在棧中分配),如果指標指向的記憶體是堆中分配的話,當函式返回時指標變數會被自動銷燬,而其指向的記憶體卻沒有被釋放,那麼那塊記憶體就再也不能被釋放了,於是它就成了記憶體漏洞。

指標與所指向內容的關係,如下:

這裡寫圖片描述

中間紅色是指標d的值,正好是變數a的首位元組的地址,也就是a的地址。這是64位程式的情況,可以看到地址佔了8個位元組。

以上是VS中的樣子,QtCreator中是這樣的:

這裡寫圖片描述

注意這個是兩個程式,所以a在記憶體中的位置不一樣,所以d的值不一樣。

陣列變數本身其實也是一個指標。但是編譯器把它當陣列對待,比如sizeof()計算一個指標時得到的是不是4就是8,而計算一個數組時,得到的是整個陣列所佔的位元組數。而同時陣列變數又完全可以當作指標使用。

陣列

陣列是一坨型別相同的資料排列在一起組成的,因為每一個元素佔用的位元組數相同,所以跟據一個元素的序號就可以計算出它在記憶體中的位置,所以陣列元素可以用序號來訪問。

    //定義一個float型陣列,陣列的型別表示其每一項都是一個float型值
    //陣列有19項,這個陣列 佔19x4 個位元組。沒有初始化,陣列每一項的值都是隨機值
    float farr[19];
    //沒有在中括號中指定陣列的數量,但對陣列進行了初始化,從大括號中可以
    //數出陣列的項數。
    float farr1[] = {55.3, 44.2, 5, 33.3};

為什麼要用陣列呢? 比如要寫一個函式,求10個數的平均數,那麼這個函式就要有10個引數。如果求100個數的平均數呢?難不成給它100個引數?這肯定不現實。我們如果把這一百個數放到陣列中,然後把陣列傳給函式,那麼只需要一個引數就夠了。如下:

#include <stdio.h>

//前置宣告
float average(int numbers[]);

//入口函式
int main(int argc, char *argv[])
{
    //定義一個數組,給10個元素
    int arr[] = {1,22,3,4,76,443,32,45,34,23};

    //呼叫求平均數函式
    float avg = average(arr);
    //列印平均值
    printf("%f\n",avg);

    return 0;
}

//求平均值函式,引數是一個數組
float average(int numbers[10]){
    //先求陣列中各元素的和
    int he =numbers[0]+numbers[1]+numbers[2]+numbers[3]+
            numbers[4]+numbers[5]+numbers[6]+numbers[7]+
            numbers[8]+numbers[9];
    //求平均值 
    float ret = he/10.0f;

    //返回結果
    return ret;
}