浅探C指针(一)--初识指针
C指針學習
前言
指針是C/C++的精華,未能很好地掌握指針,那C/C++也基本等于沒學。指針作為C語言學習中最大的障礙,可什么是指針?指針的基本概念很簡單,就是一個存放內存地址的變量。對于指針、數組和內存管理,我在學習的時候,發現很多書上都講的比較簡單,可當我們開始應用指針并試圖讀懂那些代碼時,就不知道該如何了。為掌握指針的高級應用,我開始了從簡單的知識入手,扎實基礎的學習,在C程序如何管理內存和組織方式的基礎上理解指針。
這里整理了我學習、使用指針時遇到的些許問題。
為什么要精通指針呢?可能有人說,寫程序的時候能不用指針也能實現同樣的功能。我不能說不對,可當與使用指針的同一程序相比,兩個相差幾千里。當你了解了指針你就會明白我為何會這樣說了。
- 用指針可以寫出快速高效的代碼,因為指針更接近硬件,編譯器更容易執行。
- 為解決很多類問題提供方便的途徑。像很多數據結構的實現,指針相對于其他方式(如數組)更加直觀,也更靈活。
- 支持動態內存分配。C的動態內存分配實際上就是通過使用指針實現的。
- 使表達式變得更加緊湊和簡潔。
- 提供用指針傳遞數據結構的能力而不會帶來龐大的開銷。
- 保護作為參數傳遞給函數的數據。
指針是創建和加強應用的強大工具,但使用過程中要注意,以免發生以下及其他問題。
- 訪問數組和其他數據結構時越界;
- 自動變量消失后被引用;
- 堆上分配的內存釋放后被引用;
- 內存分配之間解引指針。
可閱讀C規范(http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf)的指針的語法和語義。
一、初識指針
1.1 內存和地址
存儲器被劃分為若干個存儲單元,存儲單元從0開始順序編號。這些編號可以看作存儲單元在存儲器中的地址。CPU要從內存中讀取數據,首先要指定存儲單元的地址。也就是說它要先確定它要讀取哪一個存儲單元中的數據。
微機存儲器的容量是以字節為最小單位來計算的,也就是說一個存儲單元可以存儲一個Byte(字節),即8個二進制位(1B = 8bit,電子計算機的最小信息單位是bit(比特),即一個二進制位)。
我們把兩個或更多個字節合在一起作為一個更大的內存單位。一個內存單位可以包含多個字節,它仍然只有一個地址。至于它的地址是它最左邊那個字節的位置還是最右邊那個字節的位置,不同的機器有不同的規定。例如,許多機器以字為單位存儲整數。
計算機進行數據處理時,一次存取、加工和傳送的數據長度稱為字(word)。每個字一般由2個或4個字節組成,具體因機器決定。
1.2 地址與內容
這是一個例子,顯示了內存中5個存儲單位的內容,每個單位大小為一個字,上面數字為地址,里面的為內容。
這里顯示了5個整數,每個都位于自己的字中。如果記住了一個值的存儲地址,以后就可以根據這個地址取得這個值。
在計算機內地址也是用二進制數表示,地址是一個無符號整數,為了書寫方便和編程,在源程序中常用十六進制數或符號來表示一個存儲單元的地址。但要記住這些地址太難了,所幸的是高級語言中可以通過名字代替地址來訪問內存位置。下面這張圖與上圖相同,但這次使用名字來代替地址。
這些名字就是我們所稱的變量。名字與內存位置之間的關聯并不是硬件所提供的,它是由編譯器為我們實現的。盡管如此,硬件仍然是通過地址訪問內存位置。
1.3 指針和內存
指針:一個存放內存地址的變量。
對指針的操作實際上是對內存間接操作。
1.3.1 聲明指針變量
聲明指針變量的一般形式:
類型說明 *變量名;類名說明符表明指針所指對象的類型,星號(*)表明聲明的變量是一個指針。
星號(*)和指針名之間的空格可有可無。通常,程序員在聲明時使用空格,在解引用變量時省略空格。下面的聲明都是等價的:
int* pi; int * pi; int *pi; int*pi;現在我們來聲明一個變量和一個指針變量,看一看它們的內存分配是什么樣子的。
int num; int* pi;三個方框表示三個內存單元,每個方框左邊的數字是地址,地址旁邊的名字是持有這個地址的變量,這里的地址100只是為了說明原理。指針或其他變量的實際地址通常是未知的。三點表示未初始化的內存。
注意:
- pi的內容最終應該賦值為一個整數變量的地址;
- 這些變量沒有被初始化,所以包含的是垃圾數據;
- 指針的實現中沒有內部信息表示自己指向的是什么類型的數據或者內容是否合法;
- 指針是有類型的,如果沒有正確使用,編譯器會報錯。
1.3.2 指針變量的賦值
未經賦值的指針變量不能使用,給指針變量的賦值只能賦予地址,而不能賦予其他數據,否則將引起錯誤。
取地址操作符&,是一個單目運算符,會返回操作數的地址。變量地址的一般形式:
&變量名給一個指針變量賦值可以有以下兩種方法:
-
定義指針變量的同時就進行賦值:
- int num = 0; int* pi = #
-
先定義指針變量之后再賦值:
- int num = 0; int* pi; p = #
num 變量設為0,而pi設置為指向num的地址,如圖所示。
直接把整數賦值給指針一般都會導致警告或錯誤。
可以把整數轉換為指向整數的指針:
int num = 0; int *pi; pi = (int *)num;這樣不會產生語法錯誤,但程序運行時會因為解引地址0處的值而非正常退出。在大部分操作系統中,在程序中使用地址0是不合法的。
1.3.3 指針變量的引用
引用指針是對變量進行間接訪問的一種形式。通過一個指針訪問它所指向的地址的過程稱為間接訪問(indirection)或解引指針(dereferencing the pointer)。
對指針變量的引用形式:
*指針變量其含義是引用指針變量所指向的值。
運算符 “*“ 是單目運算符,叫作指針運算符,也叫間接引用操作符,作用是返回指定的地址內的變量的值。7
1.3.4 " &* " 和 " *& " 的區別
如有下面聲明語句:
int a; int *p = &a;“ & ” 和 “ * ” 的運算符優先級別相同,按自右而左的方向結合。因此 “ &* p ” 先進行 “ * ” 運算,“ * p ” 相當于變量a;再進行 “ & ” 運算,“ &* p ” 就相當于取變量a的地址。“ * &a ” 先進行 “ & ” 運算,“ &a ” 取變量a的地址;再進行 “ * ” 運算,“ * &a” 就相當于取變量a所在地址的值,實際就是變量a。
總結
以上是生活随笔為你收集整理的浅探C指针(一)--初识指针的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java学习笔记(八)--字符串生成器
- 下一篇: Java学习笔记(九)--数组及Arra