1. 程式人生 > >陣列 與 指標 之間的關係 分析

陣列 與 指標 之間的關係 分析

陣列的本質

陣列是一段連續的記憶體空間
陣列的空間大小為:sizeof(array_type) * array_size
陣列名可看做指向陣列第一個元素的常量指標

指標的運算

指標是一種特殊的變數,既然是變數就可以參與運算。
與整數的運算規則為:
這裡寫圖片描述

當指標p指向一個同類型的陣列的元素時:p+1將指向當前元素的下一個元素;p-1將指向當前元素的上一個元素。

指標之間只支援減法運算且必須參與運算的指標型別必須相同
這裡寫圖片描述

只有當兩個指標指向同一個陣列中的元素時,指標相減才有意義,其意義為指標所指元素的下標差。
當兩個指標指向的元素不在同一個陣列中時,結果未定義,沒有意義。

舉例說明:

#include <stdio.h>
#include <malloc.h>

int main()
{
    char s1[] = {'H', 'e', 'l', 'l', 'o'};
    int i = 0;
    char s2[] = {'W', 'o', 'r', 'l', 'd'};
    char* p0 = s1;
    char* p1 = &s1[3];
    char* p2 = s2;
    int* p = &i;

    printf("%d\n", p0 - p1);//-3
    printf
("%d\n", p0 + p2);//報錯 printf("%d\n", p0 - p2);//不確定 printf("%d\n", p0 - p); //報錯 printf("%d\n", p0 * p2);//報錯 printf("%d\n", p0 / p2);//報錯 return 0; }

指標的比較

指標也可以進行關係運算 <, <=, >, >=
指標關係運算的前提是同時指向同一個陣列中的元素
任意兩個指標之間的比較運算(==, !=)無限制

舉例說明:

#include <stdio.h>
#include <malloc.h>
#define DIM(a) (sizeof(a) / sizeof(*a)) int main() { char s[] = {'H', 'e', 'l', 'l', 'o'}; char* pBegin = s; char* pEnd = s + DIM(s); char* p = NULL; for(p=pBegin; p<pEnd; p++) { printf("%c", *p); } printf("\n"); return 0; }

陣列的訪問

陣列的下標可以為負數,編譯可通過,只是無意義
以下標的形式訪問陣列中的元素:
這裡寫圖片描述

以指標的形式訪問陣列中的元素:
這裡寫圖片描述

從理論上而言,當指標以固定增量在陣列中移動時,其效率高於下標產生的程式碼
當指標增量為1且硬體具有硬體增量模型時,表現更佳。

現代編譯器的生成程式碼優化率已大大提高,在固定增量時,下標形式的效率已經和指標形式相當;但從可讀性和程式碼維護的角度來看,下標形式更優。

a和&a的區別(a為陣列)

a為陣列是陣列首元素的地址
&a為整個陣列的地址
a和&a的意義不同其區別在於指標運算

這裡寫圖片描述

例題分析

#include <stdio.h>

int main()
{
    int a[5] = {1, 2, 3, 4, 5};
    int* p1 = (int*)(&a + 1); 
    int* p2 = (int*)((int)a + 1);
    int* p3 = (int*)(a + 1);

    printf("%d, %d, %d\n", p1[-1], p2[0], p3[1]);

    return 0;
}
//有下列選項:
// A. 陣列下標不能是負數,程式無法執行
// B. p1[-1]將輸出隨機數,p2[0]輸出2, p3[1]輸出3
// C. p1[-1]將輸出亂碼, p2[0]和p3[1]輸出2

陣列的下標可以為負數,上述ABC都不對
這裡寫圖片描述

這裡寫圖片描述

p1[-1] = a[4] = 5
p2[0] = 0x 02 00 00 00 = 33554432
p3[1] = 3 此處注意p3[1]不是p3[0]

陣列作為函式的引數

C語言中,陣列作為函式引數時,編譯器將其編譯成對應的指標,所以本質上說,沒有陣列引數,只有指標引數。
這裡寫圖片描述

結論:
一般情況下,當定義的函式中有陣列引數時,需要定義另一個引數來標示陣列的大小。

舉例說明:

#include <stdio.h>

int f(int* a,int c)
{
    return *(a+c-1);
}

int main()
{
    int a[5] = {0,1,2,3,4};    
    int b = f(a,5); 
    printf("%d\n", b);//輸出4
    return 0;
}

指標和陣列的對比

陣列宣告時編譯器自動分配一片連續記憶體空間。
指標宣告時只分配了用於容納指標的4位元組空間。

在作為函式引數時,陣列引數和指標引數等價。

陣列名在多數情況可以看做常量指標,其儲存的地址值不能改變。
指標的本質是變數,儲存的值被看做記憶體中的地址