首頁 現(xiàn)實

程序媛養(yǎng)成計劃

第五十一章 指針(六)

程序媛養(yǎng)成計劃 任煦之秋 1899 2020-05-24 23:47:30

  「哦,曉得了。」

  老爹說這些的確是現(xiàn)實中存在的問題,班上就有很多同學(xué)的家長不讓他們玩兒手機(jī)和電腦,說是會影響到學(xué)習(xí)。一方為了防止對方玩兒手機(jī),另一方想突破對方的封鎖,于是雙方展開了一場場斗智斗勇,各有輸贏。

  這大概就和老爹說的一樣吧,不能單純地從某個方面來看待這件事情。學(xué)習(xí)成績好的人有玩兒手機(jī)和電腦的,學(xué)習(xí)成績不好的也有不玩兒手機(jī)和電腦的,關(guān)鍵還是在于使用者如何使用吧。

  當(dāng)然了,一般來說小孩兒的自制能力比較差,這個時候就需要家長合理的管控了。毋庸置疑的是,老爹在這一點做得非常好。

  「好了好了,閑話就說到這里,咱們還是繼續(xù)說函數(shù)和指針之間那點事兒。其實函數(shù)和指針的關(guān)系也挺簡單的,無非就三種情況:指針作為函數(shù)參數(shù),函數(shù)返回值為指針。

  其中指針作為函數(shù)參數(shù)又有兩種情況,第一是指針變量指向的是數(shù)據(jù),如int、double以及結(jié)構(gòu)體或者枚舉這種,還有一種特例,那就是指針變量指向的是一個函數(shù),我們把一個函數(shù)A的指針作為參數(shù)傳給另一個函數(shù)B,這樣在函數(shù)B中就可以通過這個指針調(diào)用函數(shù)A了,這就是所謂的回調(diào)函數(shù)。

  概念性的東西咱們就先說到這里,還是以實際的例子來說明吧。

  首先說普通指針作為函數(shù)的參數(shù),其實這種情況你們已經(jīng)見識過了,我一開始說到的swap函數(shù)就是這樣了。我相信通過之前的講解,你們對這個函數(shù)的理解已經(jīng)算是比較透徹了,這里我們就不再贅述。

  所以我們接下來看看當(dāng)指針作為一個函數(shù)的返回值的這種情況,比如說我們來實現(xiàn)一個函數(shù),功能是把給定的字符串轉(zhuǎn)成大寫的,并把轉(zhuǎn)換后的字符串返回。

  由于字符串是一個char*,正好滿足指針作為返回值。

  typedef char* String;

  String toUpperCase(String str)

  {

  const char delta ='A'-'a';

  String temp = str;

  while (*temp !='\0')

  {

  if ('a'<=*temp &&*temp <='z')

  {

  *temp =*temp + delta;

  }

  temp++;

  }

  return str;

  }

  因為我們已經(jīng)給char*定義了一個String別名,所以我們在代碼中就使用它,比較利于閱讀理解。

  在使用這個函數(shù)的時候,我們就能夠體會到char*和char[]的區(qū)別了。

  String str =“hello world“;

  String result = toUpperCase(str);

  將會報錯,而

  char[] str =“hello world“;

  String result = toUpperCase(str);

  卻能夠得到正確的結(jié)果,至于為什么會這樣,結(jié)合字符串是常量的概念,以你們現(xiàn)在的水品來說,應(yīng)該是能夠明白這其中的道理的?!?p>  老爹笑了笑。

  「第一種情況str是一個指針,它直接指向了一個常量,而toUpperCase()卻試圖修改一個常量的值,所以在運行的時候報錯了。

  但是第二種情況str是一個數(shù)組,沒有任何限制,在函數(shù)中temp獲取了這個數(shù)組的指針地址,然后對其修改,自然不會出任何問題?!?p>  小弦子不愧是小弦子,我都還沒有來得及嘗試運行代碼,他居然憑空推算出來了結(jié)果,不佩服真的不行。

  「嗯,不錯,的確是這樣。這就是指針作為返回值的用法,應(yīng)該沒有什么難度吧?」

  若是按照老爹例程代碼來看,好像確實沒有什么難度。

  「不過返回一個指針,一定要確保這個指針是可用的,如果你返回的指針地址是函數(shù)中的一個局部變量,就可能引發(fā)不可預(yù)知的錯誤。

  因為局部變量在函數(shù)執(zhí)行結(jié)束后就被回收了,這時如果通過指針來訪問一個被釋放的了內(nèi)存,會引發(fā)的后果是真的無法預(yù)料?!?p>  我和小弦子都深以為然地點了點頭,畢竟類似的問題老爹已經(jīng)強(qiáng)調(diào)過好多遍了。

  「好了,那我們就來講講最后一種情況,一個指針指向一個函數(shù)。先說如何定義一個函數(shù)指針:

  返回值類型(*fp_name)(參數(shù)類型1,參數(shù)類型2……)

  例如:

  int (*fp)(int,int)

  就聲明了一個函數(shù)指針變量,它可以指向返回值為int類型,參數(shù)列表為兩個int類型的所有函數(shù)。

  int max(int a, int b)

  {

  return a > b ? a : b;

  }

  int min(int a, int b)

  {

  return a > b ? b : a;

  }

  比如說這里的max和min都符合條件,所以我們就可以這樣:

  int (*fp_max)(int,int);

  int (*fp_min)(int,int);

  fp_max = max;

  fp_min = min;

  如果要使用函數(shù)指針來執(zhí)行指向的函數(shù),就需要這樣:

  int maxValue =(*fp_max)(3,4);

  int minValue =(*fp_min)(1,2);」

  「看上去就好復(fù)雜的樣子……」

  我皺著眉頭看著老爹幻燈片上敲出來的這些內(nèi)容,突然覺得腦袋運轉(zhuǎn)都幾乎停滯了。

  「既然如此,那我們就來解析一下。我們在聲明一個變量時,會使用int、

  double等類型描述符,其本質(zhì)在于告訴計算機(jī)這個變量的內(nèi)存占用情況,以及讀寫時的規(guī)則。是這樣的吧?」

  我和小弦子點了點了點頭。

  「那么我們聲明這些變量的指針的時候,是不是也要聲明使用指針讀寫數(shù)據(jù)時的規(guī)則呢?」

  「嗯嗯~」

  「同樣的,我們在定義一個函數(shù)的時候,是不是要告訴計算機(jī)這個函數(shù)的返回值、參數(shù)列表?那么同樣的,我們聲明一個函數(shù)指針也要具備這些啊。

  在聲明一個指針變量的時候我們是不是會用到『*』?」

  「是的~」

  「同理,函數(shù)指針?biāo)彩且粋€指針,那它憑哪樣搞特殊不使用『*』來自報家門,告訴計算機(jī)自己是一個指針變量呢?

  再問,當(dāng)我們要訪問一個指針的指向的地址中的內(nèi)容是,會使用什么?」

  「*」

  「那不就結(jié)了么?那函數(shù)指針雖然指向的是一個函數(shù),那么我們要訪問這個函數(shù),不得也用『*』么?

  按照這個思路,你們再去看看上面的代碼,是不是就能夠明白其中的含義了呢?」

  「臥槽,有道理啊!」

  還別說,經(jīng)過老爹這么解釋,似乎還真的有那么一些道理。

  「其實啊,這種格式看上去的確是麻煩,而且fp_max和fp_min除了指針名字不一樣之外,其它都完全一樣,這不是重復(fù)代碼么?所以我們得像個辦法把這個問題給解決了,不然以后我們要聲明很多類似函數(shù)指針的時候還不得累死。

  要是后面再修改,比如說修改返回值類型,或者修改參數(shù)列表類型……」

按 “鍵盤左鍵←” 返回上一章  按 “鍵盤右鍵→” 進(jìn)入下一章  按 “空格鍵” 向下滾動
目錄
目錄
設(shè)置
設(shè)置
書架
加入書架
書頁
返回書頁
指南