多數變量都能進行算數運算,但並非全部變量均可以。幸運的是,指針變量能做算術運算操做。除了引用和解引用內存地址外這也是指針的最重要的用途之一。數組
內存是連續塊排列,這天然讓咱們想到了數組數據類型,由於數組索引也是連續排列。數據結構
數組是最基本的數據結構之一。更具定義數組是相同數據類型的集合,內存排列裏佔用連續內存單元並可經過索引進行訪問。spa
下面代碼演示的內存轉儲。3d
#include <stdio.h> #include <stdlib.h> #include <string.h> void main() { int iArray[32]; int i; for (i = 0; i < 32; i++) { iArray[i] = i; } for (i = 0; i < 32; i++) { printf("a[%d] %u %d", i, &iArray[i], iArray[i]); if ((i % 4 == 0)&&(i!=0)) printf("\n"); } }
運行結果:指針
仔細分析上面的內存轉儲,會發現每一個連續的數組索引器內存地址也是連續的。例如:第0個數組索引a[0]的地址爲7338376,第一個數組索引地址爲7338380,後一個內存地址減去前一個連續的地址(&a[1]-&a[0]=4).結果爲4.由於一個整型變量內存中佔用一個字長(32位/4字節)。因此變量a[0]內存地址爲7338376~7338380。code
字節序描述數據將存儲在內存時的格式/排列。加載/存儲指令從內存讀取數據,在運行完數據處理指令後從寄存器將數據寫會內存。blog
在存儲和加載時,CPU必須採用硬件支持的字節序格式。其可分爲大端和小端。一個字長爲4字節/32位。咱們假設將0x1234存儲到變量中。索引
(1)大端時,高字節存儲在第一個位置,次高字節存儲在存儲次鄰位置,並以此類推。ip
(2)小端是,低字節存儲在第一個位置,次高字節存儲在存儲次鄰位置並以此類推。內存
下面經過一個示例檢測咱們的系統是打斷仍是小端:
#include <stdio.h> #define BIG_ENDIAN 0 #define LITTLE_ENDIAN 1 int endian() { short int word = 0x0001; char *byte = (char*)&word; return(byte[0] ? LITTLE_ENDIAN : BIG_ENDIAN); } void main() { int value; value = endian(); if (value == 1) { printf("大端\n"); } else printf("小端\n"); }
運行結果以下:
指針運算能進行使用以下操做符:
++ -- + -
值得注意的是:不容許使用除法(/)和乘法(*)操做符。
在以前的字節序中講過了,內存中數據是連續排列的。能利用數組索引訪問內存塊中相鄰的每一個數組元素,這也是指針的一種常見操做。
例如:int arry[10]//包含10個整數的整型數組。
int* ptr; ptr=arr;//數組第一個索引的指針
+操做用於加法處理,指針指向某個數據類型時,它始終指向數據類型在內存單元中的首字節。在指針運算中,作加法運算後指針變量指向的地址取決於有數值與數據類型相乘表達式的值。下面給出一個示例:
#include <stdio.h> int main() { int i = 0; int data = 9; int *iptr; char *cptr; iptr = &data; cptr = (char*)&data; printf("value of data=%d,hex value =%x\n", data, data); printf("Address of data=%p\n", &data); printf("整型指針指向:%p\n", iptr); printf("char型指針指向:%p\n", cptr); for (i = 0; i < 4; i++) { printf("address =%p value=%x\n", cptr, *cptr); cptr++; } return 0; }
程序運行結果以下;
不難看出值爲9的int變量佔用了四個字節,從00B3FC78~00BCFC7B.這裏調用char指針來講明這個事實。
其實咱們若是查看彙編輸出咱們會發現,指針運算中編譯器會作如下轉換:
<指針變量>=<指針變量>+<增長值>
到
<指針變量>=<指針變量>+<指針變量數據類型大小>*<增長值>
值得注意的是,指針變量+指針變量是合法的,可是不容許將指針變量加入到另一個指針變量中。
同理的,指針運算中對於指針減法會作如下轉換:
<指針變量>=<指針變量>-<增長值>
到
<指針變量>=<指針變量>-<指針變量數據類型大小>*<增長值>
可是與指針加法不一樣,兩個指針變量能夠作減法,下面給出一個代碼示例:
#include <stdio.h> int main() { int data[4] = { 1,2,3,4 }; int *iptr1; int *iptr2; int val; iptr1 = &data[1]; iptr2 = &data[2]; val = iptr2 - iptr1; printf("兩個指針地址之間的距離爲:%d\n", val); return 0; }
運行結果以下:
結果爲1是由於這兩個連續位置之間只存在一個元素。當兩個指針變量分別指向數組連續內存地址的不一樣位置,讓它們彼此相減獲得的結果差表示兩個指針變量間存在的元素數目。
想要了解指針和數組之間的使用與相關性,必須探究有關數組變量經常使用語法的意義。這裏順便重提一下數組的定義:存儲在連續內存單元內的一系列的數據類型值。
前面提到的數組索引咱們知道
數字名=&數組[0]
若是咱們增長它的偏移量技能便利數組數據元素的連續地址。
咱們能夠認爲
arr_var+offset=&arr_var[offset] 和 (arr_var+offset)=arr_var[offset]
下面進行給出一個相關示例:
#include <stdio.h> int main() { int arr[4] = { 1,2,3,4 }; printf("地址爲%p\n", arr); printf("地址爲%p\n", &arr[0]); return 0; }
運行結果以下:
值得注意的是:雖然數組變量名錶明數組的第0個索引地址,但禁止修改它的值,即不能讓它指向其餘位置。以下:
int arr_var[5]; arr_var=arr_var+1;//這樣作是不容許的,由於表達式試圖將數組名指向下一個整數變量的地址。 arr_var++;//非法語句,試圖修改數組變量的起始地址
有時在數組定義時不知道要存儲的數組元素數目。程序運行時,數組元素數目可能增長也可能減小。全部咱們在數組中存儲這類元素時,數組必須是動態的,由於數組大小在運行時能改變。諸如咱們以前的定義
int arr_stat[10];
該聲明確保編譯時已知數組大小,稱爲靜態數組。
指針可以幫助咱們操做內存區域實現根據需求增長或下降內存的預期行爲。利用指針和堆實現該目標。調用malloc()在堆中分配內存。下main咱們用一個示例進行演示。
示例:需求:用戶插入數據時,適當調整內存大小以存儲數據元素。用戶刪除數據時,釋放內存。
#include <stdio.h> #include <malloc.h> int *ptr = NULL; static int count = 0; void insert(int data) { if (ptr == NULL) { ptr = (int*)malloc(sizeof(int));//從對分配空間給第一個data單元 ptr[0] = data;//利用數組符號訪問內存地址來存儲數據。 } else { ptr = (int*)realloc(ptr, sizeof(int)*(count + 1)); ptr[count] = data;//利用數組符號訪問內存地址來存儲數據。 } count++; } void show() { int i = 0; for (i = 0; i < count; i++) { printf("%d\n", ptr[i]); } } int main() { int c = 0; int data; while(c!=3) { printf("輸入選擇\n"); printf("輸入1插入數據\n"); printf("輸入2顯示數據\n"); printf("輸入3退出數據\n"); scanf("%d", &c); if (c == 3) break; switch (c) { case 1: printf("數據=\n"); scanf("%d", &data); insert(data); break; case 2: printf("數組中的數據\n"); show(); break; } } return 0; }
運行結果:
按照定義指針數組是指在連續單元內存中在儲指針變量。該數組中每一個位置包括內存中某個數據的內存地址。
指針數組聲明:<數據類型*><變量名>[數組元素數目]
int * arr_ptr[10]//指向10個整型變量
示例:
#include <stdio.h> int main() { int arr[4] = { 1,2,3,4 }; int* arr_ptr[4]; int i; for (i = 0; i < 4; i++) { arr_ptr[i] = arr + i; } printf("數組元素地址爲\n"); for (i = 0; i < 4; i++) { printf("元素%d的地址爲%p\n", i, arr + i); } printf("數組元素的值爲\n"); for (i = 0; i < 4; i++) { printf("元素%d的值爲%p\n", i, arr_ptr[i]); } return 0; }
運行結果爲:
分析上述輸出,指針數組arr_ptr包含數組arr中每一個元素的地址。
依據定義數組指針爲指向數組的指針變量。
聲明:<數據類型>(*<變量名>)[數組元素數目]
例如:
int (* ptr2arr)[4];//指向包含長度爲4數組的指針
與其餘指針變量同樣,數組指針每次僅能指向一個位置。
示例:
#include <stdio.h> int main() { int arr[4] = { 1,2,3,4 }; int(*ptr2arr) [4]; int i; int *ptr = arr; ptr2arr = &arr; for (i = 0; i < 4; i++) { printf("元素的地址爲%p\n", arr + i); } printf("值在%d\n", *(ptr2arr[0] + 1)); for (i = 0; i < 4; i++) { printf("地址%p的值爲%d\n", (ptr2arr[0] + i), *(ptr2arr[0] + i)); } return 0; }
運行結果以下;
ptr2爲數組指針,指向存儲四個整型類型的數據元素的數組。