C語言學習趣事:關於C語言中複雜型別定義

說到C語言, 很多人都是又愛又恨啊,既感到用C語言給了程式設計師極大的開放度和自由度,同時又對C語言的靈活性和高難度性。讓我們一起來看看下面這則關於C語言的趣事吧!

C語言學習趣事:關於C語言中複雜型別定義

  C語言學習趣事:關於C語言中複雜型別定義

就目前中國教育做法來說吧,估計大部分高校給學生選的入門級語言就是C語言, 然而經過大學幾年的學習,大部分的學生也只能做到寫個“HelloWord” 這樣的程式碼。即便是計算機專業的畢業生,在離開學校後,大部分也是對C語言的掌握也只是停留在簡單的應用,更不用說非計算機專業的學生了, 就像我這樣非計算機專業畢業的,到現在也不會用C語言編寫一個具有實際應用意義的程式。

估計C語言中最難讓人擺平的估計要算是指標了, 不但難以捉摸,同時又非常複雜。尤其是當具有複雜的資料型別定義的時候。

  1、指標

何謂指標,這個問題估計不需要說明了。從硬體角度來看,指標應該指的是CPU地址總線上呈現的電平狀態的數字化表示,估計大家都知道經典8051中的定址過程, 通過地址匯流排選擇需要操作的儲存地址;在8051中我們知道共有16根地址匯流排, 因此具有2^16方的可定址空間,就是具有64K的定址空間。當所有地址匯流排呈現低電平時選擇的是0000_0000_0000_0000,即0000H的地址;而當地址匯流排全部呈現高電平狀態則選擇的是1111_1111_1111_1111,即FFFFH的地址。這個同樣適合8086架構下的定址, 如果用匯編語言編寫程式,就可以直接指定要操作的地址,或者說可以直接定址地址。

  2、C語言中的指標

C語言高效的一個原因就在於可以直接對地址進行操作,雖然不如組合語言那樣的直接,但是相對於其他一些語言例如VB等語言來說,C的指標操作已經非常“高階”了。C語言的發明者真夠神的, 發明了指標這樣難以駕馭的指標,但是C語言中指標的定義則非常的簡單。

  3、C語言中指標型別定義

定義語法:

指標指向的基型別 * 指標識別符號

例如: int * pValue; 這樣就定義了一個可以指向int型別變數的指標,哈哈,還真神奇,這樣就可以控制硬體的連線上的電平了,

  4、指標用法




  5、複雜指標定義:

指標常量和常量指標:


int const * p; // 定義一個指向常量的指標, 這個指標可以隨意改變指向

int * const p; //定義一個指標常量, 這個指標只能指向一個變數,並且指向後不能在改變

const int * const p; //定義一個指向常量的指標常量, 指標變數本身的值不可修改,並且指標指向的變數也不能被修改。

例如:

int * const pconst=&test; //這裡定義的pconst指標就不能再指向別的整型變數

const int constvalue=50; //定義一個整型常量, 等價於 int const constvalue

int const *constvar=&constvalue; //定義一個指向整型常量的指標, 指標指向的變數值不可修改,但是指標指向可以更改

const int * const constpvar=&constvalue; //定義一個指向整型常量的指標, 指標的`指向不可修改。

這類指標定義的一個簡單的閱讀方法就看: const修飾的是什麼, 當其修飾資料型別的時候則定義的是資料型別的變數不能修改;

當修飾的是指標變數的時候則指標的指向不可改變。

從上面的例項可以看出: 當沒有指標存在的時候,const 的位置不會影響變數的使用,但是也可以根據其修飾的物件來理解。

  指標陣列和陣列指標

int *p[];

int (*p)[];

這兩類指標的定義著實非常令人糾結啊, 到底怎麼解釋和理解呢? 一團霧水啊...........

首先看第一個: int *p[ ];

如上定義: p 的左右各有一個運算子, *和[]; 指標運算子和陣列運算子, 在C規範裡面, 陣列運算子的優先級別高於指標運算子。

在這裡同樣可以利用運算子的優先順序來理解這個指標,

因為[ ]的優先順序高於 * ,引起p應該先和[ ]結合,這裡就是可以看出,p是一個數組, 然後p再與* 結合,可以看出p是一個指標,最後看資料基型別,p的資料基型別是int型的;綜合上面的描述可以知道: p被定義為一個儲存int型指標的陣列。 即p是一個數組,其陣列元素的型別是int型指標。

如果要引用其指向的變數的內容的話,可以這樣使用: int sizex=*p[0]; 這就是指標陣列, 就是說陣列元素全是指標。

接下來看第二個:

int (*p)[];

同樣可以利用優先級別來理解: ()和[ ]具有相同的優先順序, 因此 p 是一個指標, 然後再用 [ ]來修飾p; 則可以看出p將指向一個數組型別資料,這就是說 int (*p)[]是指向int型陣列的指標。這個指標不能指向別的陣列。

例如:

int iArray[4][5];

int (*pArray)[5];

pArray=iArray; //這樣可以編譯成功, 因為pArray的型別是 : int (*) [] ; 而 iArray 的型別是 int [4][5]; 可以進行資料型別的轉換

但是如果:

pArray=&iArray; //編譯不成功,為什麼呢? 因為pArray的型別是 : int (*) [] ; 而&iArray 的型別是 int *[][];很顯然資料型別不一樣

如果:

pArray=&iArray[0]; // 編譯成功。

我們知道在二維陣列中, 可以這樣理解:其行元素相當於指標,即 iArray[0]、 iArray[1]、 iArray[2]、iArray[3], 但是其儲存的並不是指標,其儲存的是一個具有5個元素陣列的首地址。但是需要這樣才能 iArray=&iArray[0]; (這裡二維陣列的首地址與 iArray[0] 的地址相同 )。

對於陣列指標的理解,可以將變數去除後然後進行剝離得出其資料型別然後進行理解。例如:

pArray: int (*)[];

&iArray[0]: int (*)[ ];

特殊的引用方式:

int iArray[4];

int (*pArray)[4]=NULL; //指定義不初始化同樣可以,但是為了防止出現遊離指標,最好用NULL初始化;

pArray=&iArray; // 這個編譯成功

指向函式的陣列指標

int (*a[10])(int); // 這個定義一個數組,陣列共有10個元素,每個元素儲存一個指向 int (*)(int )函式的指標, 同樣利用優先順序來理解。

  指標的指標