linux下c語言指針部分的一個總結

1、指針的定義與初始化

如何理解指針? 首先要在回答指針是什麼時一定要說指針是變量,這樣的話,指針就有了變量的特性。 
(1) 系統爲指針分配內存空間; 
(2) 指針有自己的地址; 
(3)指針能夠存值,但這個值比較特殊–地址。 
指針的字節長度: 任何類型指針的長度都是4個字節(32)系統,指針變量是一個地址,在操作系統中地址的長度是固定的。

2、* 與&運算符詳解(用於取內容(*)和取地址(&)兩種運算。)

  1. 指針的類型和指針所指向的類型 
    (1)指針的類型 
    從語法的角度看,你只要把指針聲明語句裏的指針名字去掉,剩下的部分就是這個指針的類型,這是指針本身所具有的類型。讓我們看看例子中各個指針的類型。 
    (1)int * ptr; //指針的類型是int* 
    (2)char * ptr; //指針的類型是char* 
    (3)int *ptr; //指針的類型是int 
    (4)int (* ptr)[3]; //指針的類型是int(*)[3] 
    (5)int * (* ptr)[4]; //指針的類型是int*( *)[4]

    (2)指針所指向的類型 
    當你通過指針來訪問指針所指向的內存區時,指針所指向的類型決定了編譯器將把那片內存區裏的內容當作什麼來看待。從語法上看,只須把指針聲明語句中的指針名字和名字左邊的指針聲明符“*”去掉,剩下的就是指針所指向的類型。例如: 
    (1)int*ptr; //指針所指向的類型是int 
    (2)char*ptr; //指針所指向的的類型是char 
    (3)int * * ptr; //指針所指向的的類型是int* 
    (4)int (*ptr)[3]; //指針所指向的的類型是int()[3] 
    (5)int* (* ptr)[4]; //指針所指向的的類型是int*()[4]

  2. 指針的值 
    指針的值也叫作指針所指向的內存區或地址。指針的值是指針本身存儲的數值,這個值將被編譯器當作一個地址,而不是一個一般的數值。在32位程序裏,所有類型的指針的值都是一個32位整數,因爲32位程序裏內存地址全都是32位長。指針所指向的內存區就是從指針的值所代表的那個內存地址開始,長度爲sizeof(指針所指向的類型)的一片內存區。以後,我們說一個指針的值是XX,就相當於說該指針指向了以XX爲首地址的一片內存區域;我們說一個指針指向了某塊內存區域,就相當於說該指針的值是這塊內存區域的首地址。

3、指針運算

  1. 指針的賦值運算

指針也是一個變量,它自己佔據一個4個字節的地址空間(由於程序的尋址空間是2^32次方,即4GB,所以用4個字節表示指針就已經能指向任何程序能夠尋址到的空間了,所以指針的大小爲4字節),指針的值是另一個東西的地址,這個東西可以是普通變量,結構體,還可以是個函數等等。由於,指針的大小是4字節,所以,我們可以將指針強制轉換成int型或者其他類型。同樣,我們也可以將任何一個常數轉換成int型再賦值給指針。所有的指針所佔的空間大小都是4字節,他們只是聲明的類型不同,他們的值都是地址指向某個東西,他們對於機器來說沒有本質差別,他們之間可以進行強制類型轉換。

C語言中,任何一個變量都必須佔有一個地址,而這個地址空間內的0-1代碼就是這個變量的值。不同的數據類型佔有的空間大小不一,但是他們都必須有個地址,而這個地址就是硬件訪問的依據,而名字只是提供給程序員的一種記住這個地址的方便一點的方法。但是,不同的變量在機器中都是0-1代碼,所以,我們不能簡單的通過檢查一個值的位來判斷它的類型。 
不同類型指針的轉換涉及到強制類型轉換

指針 to 指針的強制類型轉換是指將指針所指的內容的類型由原先的類型轉換爲後面的類型。 
int a = 1; 
int *p = & a; 
float * p1 = (float*)p; 
則p和p1的值都是&a,但是* p是將&a地址中的值按照int型變量進行解釋,而*p1則是將&a地址中的值按照float型變量進行解釋。

//指針類型強制轉換:
int m;
int *pm = &m;
char *cp = (char *)&m;
//pm指向一個整型,cp指向整型數的第一個字節
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

下面的例子說明了指針的步長問題。

/*指針的移動有個步長,步長等於sizeof(指針指向的元素類型) */
#include<stdio.h>
int main(void)
{ 
    int a[5] = {1, 2, 3, 4, 5}; 
    int *ptr1 = (int*)(&a + 1); //&a(數組指針)指針指向的元素爲整個數組,故加爲sizeof(數組) 
    int *ptr2 = (int*)((int)a + 1); //a地址再加一個字節,直接地址值相加而不是指針 
    int *ptr3 = (int*)(a + 1); //a爲數組首元素的地址,a+1爲數組第二個元素的地址
/* 數組a在內存的存放形式爲 *01000000 020000000 03000000 04000000 05000000 
*ptr2指向01000000的第二個字節,故*ptr2=00000002 * */ 
printf("%x %x %x\n", ptr1[-1], *ptr2, *ptr3); 
return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

這裏寫圖片描述

賦值運算遇到的三個問題

  1. NULL(空指針)
  2. 野指針
  3. 指針變量的之間的賦值

(1)NULL指針:NULL 是一個標準規定的宏定義,用來表示空指針常量。

#define   NULL   (void *)0
  • 1
  • 2
  • 1
  • 2

空指針在計算機中就是0地址,不容許對0地址做任何操作。 
int *p =NULL;更容易使讀程序的人意識到這裏是一個指針賦值。

(2)野指針 
野指針問題及如何避免

野指針主要由下面兩種原因導致的。

  1. 指針變量沒有被初始化。指針變量在定義後如果沒有初始化是野指針,其值不爲NULL;
  2. 指針 p 被 free 或者 delete 之後,沒有置爲 NULL;

因此,對症下藥,在編程過程上遵循如下原則:

1)凡是定義的指針變量初始化爲NULL;

2)指針 p 被 free 或者 delete 之後將其值賦爲NULL;

野指針:指向不確定地址的指針變量。(即沒有初始化)使用野指針易因內存泄露出現段錯誤。而造成內存泄露的原因有兩個:

  1. 訪問了沒有權限的內存(平時我們正確使用指針的時候,系統應經將相應的內存分配給用戶,但是如果指向沒有分配的內存,系統會判定我們沒有權限)
  2. 訪問了已經釋放了的內存。

因爲野指針主要是因爲我們平時編程習慣造成的,因此我們只能避免野指針的出現,而不能杜絕。

在我們在編程時,做到以下幾點可以有效地避免野指針的出現。

第一,當一個指針沒有指向時,我們一般默認指向NULL。(NULL代表內存的0地址,並且NULL是不允許做任何操作的)

第二,使用malloc分配內存。(在堆空間裏分配內存)

#difine  MAX_SIZE  1024;
char *ptr = (char *) maollc  (sizeofchar) * MAX_SIZE);
  • 1
  • 2
  • 1
  • 2

如何避免野指針? 
說先應該說養成良好的編碼習慣。 
1、當指針沒有指向時,應該將指針初始化爲NULL. 
2、檢查是否分配空間,如果沒有則要分配內存。(分配成功,返回內存的首地址;分配不成功,返回NULL)。 
3.檢查是否分配成功(若失敗,則 exit(1) 退出程序)。 
4.初始化內存空間,清空內存中的數據 (malloc分配的空間裏可能存在垃圾值,因此我們需要清空,可以用到memset或bzero 函數)。 
4.使用內存後,釋放內存(free,這時ptr又變成野指針)。 
6.free之後將指針再次置爲NULL。

當看到指針指向NULL時: 
①注意不能對指針指向的空間做操作 
②提醒這是一個野指針

(3)指針變量的之間的賦值 
不同指針類型變量賦值導致的問題: 
長指針賦值給短指針,數據丟失。(長短指的是步長); 
短指針賦值給長指針,數據多取。

《void * 的概念》 
鑑於指針之間這種靈活的強制類型轉換的需求和出於簡化代碼的考慮,ANSI C引入了空指針即void*。void指針又名萬能指針,在現在的很多程序中,當參數不確定時就用萬能指針代替,這一類的指針在線程\進程函數裏特別常見。 
ANSI C規定,void指針可以複製給其他任意類型的指針,其他任意類型的指針也可以複製給void指針,他們之間複製不需要強制類型轉換。當然任何地址也可以複製給void型指針。

2、指針的算術運算

int a[10] = {1,2,3,4,5,6,7,8,9,10};
int *ptr = &a[0];
int *str = &a[5];

printf("%d\n",*(ptr + 1));
printf("%d\n",str - ptr);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

結果:*(ptr + 1)= 2; str- ptr = 5;

這裏寫圖片描述

指針之間只有減法,且同時必須同時指向同一個空間。

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