大家好,這里是小編的博客頻道
小編的博客:就愛學編程
很高興在
CSDN
這個大家庭與大家相識,希望能在這里與大家共同進步,共同收獲更好的自己!!!
本文目錄
- 引言
- 正文
- (1)內置數據類型指針
- (2) 自定義類型指針
- 1.數組指針與指針數組
- 2. 結構體指針
- 3.聯合體指針
- (1)聯合體指針的定義
- (2)聯合體指針的使用
- (3)聯合體指針的注意事項
- (3)函數指針
- 1.函數指針的定義
- 2.函數指針的賦值
- 3.函數指針的使用
- 4.函數指針作為參數
- 5.函數指針作為返回值
- 6.函數指針的注意事項
- (4)空指針(`NULL`)
- (1)空指針的使用
- (2)空指針與空字符
- (3)空指針的注意事項
- (5)二級指針
- (1)二級指針的定義
- (2)二級指針的內存分配
- (3)二級指針的使用
- (4)二級指針作為函數參數
- (5)二級指針的注意事項
- (6)常量指針與指向常量的指針(const 的用法)
- 1.指向常量的指針(Pointer to a Constant)
- 2.常量指針(Constant Pointer)
- 3.常量指針指向常量(Constant Pointer to a Constant)
- 4.使用場景和注意事項
- 快樂的時光總是短暫,咱們下篇博文再見啦!!!不要忘了,給小編點點贊和收藏支持一下,在此非常感謝!!!
引言
指針作為C語言語法學習中的一塊既極重要又極難懂的知識點,讓初學C語言的我們常常苦不堪言。而本文就是為了讓像曾經的作者一樣的寶子們深刻理解指針這一章節的內容而作,那接下來就跟隨作者的視角,一起把各種類型的指針理解透徹!
那接下來就讓我們開始遨游在知識的海洋!
正文
指針的類型繁復,為了避免出現知識點的遺漏,這里小編采根據指向的內容進行分類,把指針分為了以下6種。讓我們一一來學習吧!!
內置類型數據是我們最為常用的數據類型,所以指針的學習我們就從它開始。
(1)內置數據類型指針
顧名思義,這些指針指向內置類型的變量,如整型指針,字符指針等。
詳見:
類型 | 內涵及應用 |
---|---|
整型指針int* | 指向整數的指針 |
浮點型指針float* ,double* | 指向浮點數的指針 |
字符(型)指針char* | 指向字符的指針,常用于字符串處理 |
布爾型指針bool* | 指向布爾值的指針 |
其次就是自定義類型指針,一起來看看吧!!
(2) 自定義類型指針
自定義類型數據類型有:數組,結構體,枚舉,聯合體。但是枚舉沒有對應的枚舉指針變量。
這里小編先從數組與指針開始講起。
1.數組指針與指針數組
數組指針和指針數組是C編程中兩個重要的概念,它們雖然名字相似,但含義和用法卻有很大的不同。我們先來看看這兩個的定義:
- 數組指針指的是指向數組的指針。它是一個指針,指向一個數組類型的數據。聲明一個數組指針時,需要指定數組的元素類型和大小。例如,
int (*arrayPtr)[10]
表示一個指向包含10個整數的數組的指針。使用數組指針時,可以通過(*arrayPtr)[index]
來訪問數組中的元素。
- 指針數組則是指存儲指針的數組。它是一個數組,其中的每個元素都是指針。聲明指針數組時,需要指定數組的大小和指針指向的類型。例如,
int *pointerArray[10]
表示一個包含10個指向整數的指針的數組。訪問指針數組中的元素,可以直接使用pointerArray[index]
,然后通過解引用來訪問指針指向的數據。
主要區別在于它們的使用場景和內存布局。
數組指針通常用于函數參數,以傳遞多維數組,而指針數組則常用于創建動態的數據結構,如鏈表和樹。
在內存中,數組指針指向的是連續的內存塊,而指針數組中的每個指針可以指向任意位置的內存。因此,數組指針在內存訪問上更為高效,而指針數組則在數據組織上更為靈活。
- 總之,理解數組指針和指針數組的區別對于編寫高效的C語言程序至關重要。掌握它們各自的特性和適用場景,可以幫助我們更好地設計和實現程序。
2. 結構體指針
定義:結構體指針允許我們通過指針來訪問和操作結構體中的數據。結構體是一種復合數據類型,它允許我們將多個不同類型的數據項組合成一個單一的類型。結構體指針則是指向這種復合數據類型的指針。
在C中,結構體指針的聲明方式是在結構體類型的前面加上一個星號()。例如,如果有一個名為
Person
的結構體,聲明一個指向該結構體的指針可以寫作Person *ptr;
。這個指針可以用來指向一個Person
類型的結構體實例。
我們以一個代碼為例:
#include<stdio.h>
struct book {char name[20];char author[20];int prince;
};
void print(struct book* p) {printf("%s %s %d\n", (*p).name, (*p).author, (*p).prince);printf("%s %s %d\n", p->name, p->author, p->prince); //“->”操作符可用在:結構體指針指向我們想要訪問的結構體中的元素;
}int main() {struct book b1 = {"C語言", "張三", 10};printf("%s %s %d\n", b1.name, b1.author, b1.prince); //“.”操作符可用在:找到我們想要訪問的結構體的元素。print(&b1);return 0;
}
這里的struct book* p
就是一個結構體指針變量
主要優點:是它們提供了一種通過內存地址間接訪問和修改結構體成員的方法。這在處理大型數據結構時尤其有用,因為它們可以減少內存復制,提高程序的效率。
使用結構體指針時,我們可以通過箭頭操作符(->)來訪問結構體的成員。例如,如果
Person
結構體有一個名為name
的成員,我們可以通過ptr->name
來訪問或修改它。
結構體指針也常用于動態內存分配。使用
new
關鍵字可以動態創建結構體實例,并返回指向該實例的指針。例如,Person *ptr = new Person;
會創建一個新的Person
結構體,并使ptr
指向它。當不再需要這個結構體時,應該使用delete
來釋放內存,避免內存泄漏。
結構體指針還可以作為函數參數,允許函數直接修改傳入的結構體實例。這在設計模塊化和可重用代碼時非常有用,因為它允許函數與調用者共享數據,而無需復制整個結構體。
- 總之,結構體指針提供了一種高效、靈活的方式來訪問和操作結構體數據,是編寫高效、模塊化代碼的關鍵。理解結構體指針的工作原理和正確使用它們,對于任何C/C++程序員來說都是一項基本技能。
3.聯合體指針
聯合體(Union)指針是指向聯合體類型的指針。聯合體是一種特殊的數據結構,允許在相同的內存位置存儲不同的數據類型。這使得聯合體成為一種節省空間的數據類型,因為聯合體的大小等于其最大成員的大小,而不是所有成員的總和。
(1)聯合體指針的定義
在C/C++中,聯合體指針的聲明方式是在聯合體類型的前面加上一個星號()。例如,如果有一個名為
Data
的聯合體,聲明一個指向該聯合體的指針可以寫作Data *ptr;
。這個指針可以用來指向一個Data
類型的聯合體實例。
(2)聯合體指針的使用
使用聯合體指針時,我們可以通過箭頭操作符(->)來訪問聯合體的成員。例如,如果
Data
聯合體有一個名為num
的成員,我們可以通過ptr->num
來訪問或修改它。
聯合體指針的使用特點:
- 內存共享:聯合體指針允許我們通過指針訪問聯合體成員,這些成員共享相同的內存位置。這意味著對一個成員的修改會影響其他成員。
- 類型安全:盡管聯合體可以存儲不同類型的數據,但使用聯合體指針時,編譯器會根據聯合體的聲明來檢查成員訪問的類型安全。
- 動態內存分配:與結構體類似,聯合體指針也常用于動態內存分配。使用
new
關鍵字可以動態創建聯合體實例,并返回指向該實例的指針。
- 靈活性:聯合體指針提供了一種靈活的方式來處理不同類型的數據,尤其是在需要節省空間或者需要通過同一個內存位置存儲不同類型數據的場景中。
(3)聯合體指針的注意事項
- 初始化:在使用聯合體指針之前,應該確保指針已經被正確初始化,指向一個有效的聯合體實例。
- 內存釋放:如果使用
new
動態分配了聯合體實例,那么在不再需要時,應該使用delete
來釋放內存,避免內存泄漏。
- 成員訪問:在使用聯合體指針訪問成員時,必須確保訪問的是當前存儲在聯合體中的成員類型,否則可能會導致未定義行為。
- 聯合體指針提供了一種節省空間且靈活的方式來處理不同類型的數據。
(3)函數指針
函數指針是C語言中一個強大的特性,它允許將函數的地址賦給一個變量,使得可以通過這個變量來調用函數。這種機制提供了一種靈活的方式來處理函數,使得函數可以像數據一樣被傳遞和操作。
1.函數指針的定義
函數指針的聲明需要指定函數的返回類型、指針類型(即
*
),以及函數的參數列表。例如,如果有一個返回int
類型、接受兩個int
參數的函數add
,那么對應的函數指針聲明如下:int (*funcPtr)(int, int);
這里,funcPtr
是一個指向函數的指針,它可以存儲add
函數的地址。
2.函數指針的賦值
要將函數的地址賦給函數指針,可以直接使用函數名。
這是因為:在C語言中,函數名本身就是一個指向函數的指針,因此可以直接賦值給函數指針。
3.函數指針的使用
使用函數指針調用函數時,需要使用括號來包圍函數指針和參數。
例如,int result = funcPtr(5, 3); // 調用add函數
4.函數指針作為參數
函數指針常用作其他函數的參數,這使得函數可以接收另一個函數作為輸入,從而提供高度的靈活性。例如,可以定義一個接受函數指針作為參數的函數:
void applyFunction(int x, int y, int (*func)(int, int)) {int result = func(x, y);// 處理結果
}
在這個例子中,applyFunction
接受兩個int
參數和一個函數指針參數,然后調用這個函數指針指向的函數。
5.函數指針作為返回值
函數指針也可以作為函數的返回值,這允許函數返回一個函數。這種技術可以用來實現回調函數和策略模式。
小編已經在之前的函數篇提及。
6.函數指針的注意事項
- 類型匹配:函數指針必須指向與聲明匹配的函數類型,否則會導致編譯錯誤或運行時錯誤。
- 空函數指針:函數指針可以被初始化為
NULL
,表示它不指向任何函數。
- 內存管理:如果函數指針用于動態分配的函數對象,需要確保正確管理內存,避免內存泄漏。
在C語言中,空指針(Null Pointer)是一個特殊的指針值,它不指向任何有效的對象或函數。空指針的主要作用是表示“沒有指向任何東西”或“沒有有效的地址”。在C語言中,空指針常被用來表示一個指針變量尚未被分配具體的內存地址,或者用來表示某個指針變量不再指向任何對象。
(4)空指針(NULL
)
定義:在C語言中,空指針被定義為
NULL
,它是一個宏,在標準庫<stddef.h>
中定義。NULL
的具體值是0
,這意味著在大多數平臺上,空指針和數值0
是等價的。然而,NULL
的使用更加明確,因為它專門用來表示空指針,而0
可能在其他上下文中有其他含義。
(1)空指針的使用
空指針通常用于以下幾種情況:
- 初始化指針:在聲明指針變量時,如果沒有立即分配內存,可以將指針初始化為
NULL
,以表明該指針當前不指向任何對象。
函數返回值:當一個函數需要返回一個指針,但沒有有效的對象可以返回時,可以返回
NULL
。
- 檢查指針有效性:在使用指針之前,檢查它是否為
NULL
是一個好習慣,這可以防止解引用空指針導致的程序崩潰。
(2)空指針與空字符
需要注意的是:空指針(NULL
)和空字符('\0'
)是兩個完全不同的概念。空指針是一個指針值,表示沒有指向任何對象,而空字符是一個字符值,通常用來表示字符串的結束。
(3)空指針的注意事項
- 空指針賦值:不要將
NULL
賦值給非指針類型的變量,這會導致編譯錯誤。
- 平臺依賴性:雖然在大多數平臺上
NULL
被定義為0
,但在某些系統上,NULL
可能有不同的定義。因此,最好始終使用NULL
而不是直接使用0
。
- 空指針與空數組:不要將空指針與空數組混淆。空數組是指一個長度為零的數組,而空指針是一個不指向任何對象的指針。
結論:
- 空指針可以幫助程序員處理指針變量的未初始化狀態和錯誤情況。
(5)二級指針
在C語言中,二級指針(Double Pointer)是指指向指針的指針。它是一個指針變量,存儲的值是另一個指針變量的地址。二級指針在處理動態內存分配、多維數組、函數參數傳遞等方面非常有用。理解二級指針對于深入掌握C語言的指針操作至關重要。
(1)二級指針的定義
二級指針的聲明涉及到兩個星號()。例如,
int **ptr;
聲明了一個指向int
類型指針的指針。這里,ptr
是一個二級指針,它可以存儲一個int*
類型的地址。
(2)二級指針的內存分配
二級指針常用于動態分配多維數組。例如,創建一個二維數組可以通過分配一個指針數組(一級指針),然后為每個指針分配一個一維數組(二級指針)。
(3)二級指針的使用
使用二級指針時,可以通過連續的解引用來訪問最終指向的數據。例如,
*arr
會得到一個int*
類型的指針,而**arr
會得到一個int
類型的值。
(4)二級指針作為函數參數
二級指針也常用于函數參數,特別是需要修改指針指向的值或者需要傳遞多維數組時。
(5)二級指針的注意事項
- 初始化:在使用二級指針之前,應該確保它們已經被正確初始化,指向有效的內存地址。
- 內存釋放:如果使用
malloc
或calloc
分配了內存,應該在不再需要時使用free
來釋放內存,避免內存泄漏。
- 解引用:在使用二級指針時,必須確保已經正確解引用,否則可能會導致訪問無效內存,引起程序崩潰。
在C語言中,常量指針和指向常量的指針是兩個不同的概念,它們在聲明和使用上有所區別,但都與指針和常量的關系有關。
(6)常量指針與指向常量的指針(const 的用法)
1.指向常量的指針(Pointer to a Constant)
指向常量的指針是指指針本身可以被修改,但其指向的數據(常量)不能被修改。這種指針的聲明方式是在指針的聲明中,將
const
關鍵字放在指針的后面,緊挨著指針的類型前面。例如:const int *ptr;
這里,ptr
是一個指向int
類型的常量的指針。這意味著你可以通過ptr
來改變它所指向的地址,但是不能通過ptr
來改變所指向地址處的值。
2.常量指針(Constant Pointer)
常量指針是指指針本身的值不能被修改,即一旦指針被初始化后,就不能指向另一個地址。這種指針的聲明方式是將
const
關鍵字放在指針的聲明中,緊挨著指針變量的前面。例如:int value = 10; int *const ptr = &value;
這里,ptr
是一個常量指針,它被初始化為指向value
的地址,之后你不能再讓ptr
指向另一個地址,但可以通過ptr
來修改value
的值。
3.常量指針指向常量(Constant Pointer to a Constant)
這種指針既不能改變指向的地址,也不能通過這個指針來改變指向地址處的值。聲明時,
const
關鍵字同時放在指針類型和指針變量之間,以及指針類型和指針指向的類型之間。例如:const int *const ptr = &value;
在這個例子中,ptr
是一個常量指針,指向一個int
類型的常量。這意味著ptr
的值(即它所指向的地址)不能被改變,同時ptr
所指向的數據也不能被修改。
4.使用場景和注意事項
- 指向常量的指針:當你需要一個指針來讀取但不能修改某些數據時使用,例如,函數參數中傳遞的只讀數據。
- 常量指針:當你需要一個指針的地址固定不變時使用,例如,指向全局變量或靜態變量的指針。
- 常量指針指向常量:當你需要一個既不能改變指向地址,也不能通過指針改變數據的指針時使用,例如,防止函數內部修改傳入的參數。
- 常量指針與指向常量的指針提供了不同的保護級別,幫助程序員控制數據的訪問和修改。