指針的魅力

指針說:love me,love me!

但是他對指針說:I hate u,I hate u!

……

?

指針僅僅是作為指針,我們可以把它當做有用的工具,為我們提供便利與好處。說起工具不得不讓我想起一樣東西——鋤頭,因為原人類有了鋤頭才使人類文明進入了開荒造田的農業時代,解決了溫飽,開啟了人類新紀元。可以這么說吧鋤頭使人類文明得到進步,沒有鋤頭也就沒有今天的我們,其地位與重要性可想而知。那么我們的指針何以能發揮像鋤頭那樣驚人的魅力呢?

?

魅力1 算法之找我的名字——簡單,靈活,快捷

以下算法功能是在一個字符串中查找長度為8的一個字符子串,比如我的名字“ZhanHang”就是一個8長度的字串。算法解釋:因為字串myname的長度為8,也就是它是一個8字節的內存連續的數組,而myname指向這一段內存。又Long long 指針類型是一個指向8字節內存的類型,因此就可以將myname轉換成long long 類型指針,如此在進行子串的比較時,就可以直接比較兩個long long 類型的變量即可,免去了對子串進行遍歷的麻煩。詳情請看代碼。

view plain
  1. #include?<stdio.h>??
  2. ??
  3. int?find_my_name(const?char*?str,?int?str_len,?const?char*?myname)??
  4. {??
  5. ????long?long?*pkey?=?(long?long*)myname;??
  6. ????long?long?*curr_str?=?NULL;??
  7. ????str_len?=?str_len?-?sizeof(long?long);?//此處是為了for循環作的優化處理,因為后面7個字符不需要遍歷檢測了??
  8. ????for(int?i=0;?i<=str_len;?i++)??
  9. ????{??
  10. ????????curr_str?=?(long?long*)&str[i];?//得到一個新的子串??
  11. ????????if(?*pkey?==??*curr_str?)?//判斷兩個字串是否相等??
  12. ????????????return?i+1;??//返回子串在字串中的位置??
  13. ????}??
  14. }??
  15. /**?
  16. Author:花心龜?
  17. Blog:http://blog.csdn.net/zhanxinhang?
  18. **/???
  19. int?main()??
  20. {??
  21. ????char?str[]="alZhanhangadf";??
  22. ????char?myname[]="Zhanhang";??
  23. ????printf("my?name?at?%d\n",find_my_name(str,sizeof(str)/sizeof(char),myname));//輸出結果是3??
  24. ??????
  25. ????return?0;??
  26. }??
小結:指針實際上指向一內存空間,其內存空間的大小由指針類型而定。靈活的應用指針是能夠為編程帶來便利的。

(題外語:作者使用此實例旨在通過靈活應用指針的例子,幫助理解指針,并通過理解指針作為本文介紹指針魅力的起點,實際工程中并不贊同此方法,因為本方法存在擴展性差,移植性差等問題。)



魅力2 迭代器——高效

“迭代”一詞在漢語里面是“更替”的意思,也就是說“迭代器”的意思就是指用來做更替操作的工具。實例:實現算法使一個字符串顛倒順序,實現步驟:構建兩個迭代器p 和 q ,在一次遍歷中,p的位置從字串開頭向中間不斷更替,q從字串末尾向中間不斷更替,

然后每次交換p和q所指向的內容即可,直到p和q在中間相遇,這時循環次數剛好等于字串的長度_l/2。

實現代碼:

view plain
  1. void?reverse(char?*_str,int?_l)?//反轉函數,_l指要反轉字串的長度??
  2. {??
  3. ?char?*p=_str,*q=_str+_l-1,temp;??
  4. ??
  5. ?while(q>p)??
  6. ???{???
  7. ?????temp=*p;??
  8. ?????*p=*q;??
  9. ?????*q=temp;??
  10. ???
  11. ?????p++;??
  12. ?????q--;??
  13. ???}??
  14. }??

我若不用迭代器p和q呢?用兩個變量i和j作為str的下標,也就是說訪問元素的方式變為:str[i],str[j],如下

view plain
  1. void?reverse(char?*_str,int?_l)?//反轉函數,_l指要反轉字串的長度??
  2. {??
  3. ??int?i=0,j=_l-1,temp;??
  4. ???
  5. ?while(j>i)??
  6. ???{???
  7. ?????temp=str[i];??
  8. ?????str[i]=str[j];??
  9. ?????str[j]=str[i];??
  10. ???
  11. ?????i++;??
  12. ?????j--;??????
  13. ???}??
  14. }??
這樣并不比上面用迭代器的情況好,而且要糟很多,因為這樣用str[i],str[j]的下標的方式訪問元素時,需要先對str所存的數組首地址進行一次加減運算才能正確得到第i個、第j個值(讀者可在任何一款編譯器上進行反匯編查看),上面一共出現了5次下標訪問str元素,情況可想而知。小結:迭代器p和q在這里起到了不可更替的作用,正是因為p和q使算法效率得到了提升。

?

?

魅力3 函數指針——高擴展性

何為函數指針:函數指針就是指向某個函數的指針,指針變量存儲的是函數的地址。

如何定義一個函數指針:定義為 [ 返回類型 (*pfun) (形參,…) ]。

如何使用函數指針:pfun(實參...) 或者(*pfun)(實參...)。

現看一個實例:

view plain
  1. #include?<stdio.h>??
  2. int?fun0(const?int?&a)//定義謂詞1?(我們把作為函數參數的函數稱為謂詞)??
  3. {??
  4. ????if(a==1)??
  5. ????????return?1;??
  6. ????else??
  7. ????????return?0;??
  8. }??
  9. int?fun1(const?int?&a)//定義謂詞2??
  10. {??
  11. ????if(a<10)??
  12. ????????return?1;??
  13. ????else??
  14. ????????return?0;??
  15. }??
  16. /*根據whatCondition函數指針所指的函數(謂詞)設置的條件打印數組*/??
  17. void?print_arr_if(const?int?*arr,?int?alen,?int(*whatCondition)(const?int&))??
  18. {??
  19. ????for(inti=0;?i<alen;?i++)??
  20. ????{??
  21. ????????if(?whatCondition(arr[i])?)??
  22. ????????????printf("%d?",arr[i]);??
  23. ????}??
  24. ????printf("\n");??
  25. }??
  26. /**?
  27. Author:花心龜?
  28. Blog:http://blog.csdn.net/zhanxinhang?
  29. **/??
  30. int?main()??
  31. {????
  32. ????int?arr[]={1,1,2,1,11,12,3,10};??
  33. ????print_arr_if(arr,sizeof(arr)/sizeof(int),fun0);?//打印結果為1?1?1??
  34. ????print_arr_if(arr,sizeof(arr)/sizeof(int),fun1);?//打印結果為1,1,2,1,3??
  35. ???
  36. ??????
  37. ????return?0;??
  38. }??

小結:以上利用whatCondition函數指針大大提高了print_arr_if函數的擴展性,通過對謂詞的定義幾乎可打印你想要的任何數組元素。

?

魅力4 函數傳遞——高效,實用

c/c++有三種函數傳遞方式,它們分別是值傳遞,指針傳遞和引用傳遞,其中指針傳遞與引用傳遞都是將地址傳進函數,基本上沒什么區別。

指針及引用作為函數傳遞類型,與值傳遞相比,是高效的。為什么高效呢?請看如下:

現有如下結構體:

view plain
  1. typedef?struct?structType??
  2. {??
  3. int?i;??
  4. char?arr[100];??
  5. }structType;??
  6. //一個print函數的定義:??
  7. void?print0(const?structType?data)??
  8. {??
  9. ???????//printf?something?about?data??
  10. }??
  11. //另一個print函數的定義:??
  12. void?print1(const?structType?*pdata)??
  13. {??
  14. ???????//printf?something?about?data??
  15. }??

通過比較發現,print1比print0有明顯的效率優勢,因為print0是值傳遞,當值傳進去時,必須要開辟一個structType那么大的內存空間來乘裝這些值,這就要相當大的一部分資源消耗,而print1是指針傳遞,傳進去的是地址,一個地址只需4字節內存空間,使用時解析其指針即可,因此它比print0更高效更實用。

再看我們如何用一個函數交換兩個變量的值:

view plain
  1. swap(int?&a,?int?&b)??
  2. {??
  3. ?????int?temp?=?a;??
  4. ?????a=?b?;??
  5. ?????a?=?temp;??
  6. }??

交換函數只有使用引用傳遞或指針傳遞才能改變形參a和b所指向的內存的值。

小結:函數的指針傳遞與引用傳遞提供了函數傳遞的一個高效的途徑,另外,若要使用某個函數來改變某一變量的值唯有使用指針傳遞或引用傳遞給該函數,這體現了實用性。



魅力5 鏈——實用

在鏈表,二叉樹等數據結構中,指針作為鏈接兩個節點的“鏈”,時刻牽絆著它們的邏輯關系。指針為這些數據結構提供了高效實現的可能,因此使我們能夠在內存世界里完成對自然事物的邏輯構造,使我們的計算機更具實用價值。

?


魅力6 動態內存分配——實用

動態內存分配離不開指針,假如把內存空間當做容器,每個程序都有它自己的容器,它如同一個容器補給器,可隨時搭載從外界而來的一個個容器,隨時為您排憂解難,為程序分憂。不僅如此,你可以通過該補給器將申請而來的容器送回去,讓它為別地應用程序所利用。

?

……


另:如何善用指針

首先看什么是野指針和空指針

空指針: 如 int *p = NULL 這就定義了一個指針,通常NULL是一個零值,操作系統定義內存64kb以下的內存單元是不可訪問的,所以像如 *p = 9 這樣給他賦值是系統不允許的,將會發生內存報錯。

野指針: 如 int *p就是一個野指針,可以看到它在創建時沒有賦初值,所以它的值是一個隨機數,也就是亂指一氣,通常都是指向了不合法的內存段,所以使用它也會內存報錯。還有指針p被free或者delete之后也會成為野指針,因為它所指的內存空間被釋放之后,變成了一個不合法內存段。野指針,它顧名思義它就是一個野指針,它是沒有主人領養的野獸,兇猛殘暴,用它你就得自食其果。

指針防災措施:一,養成好習慣,在每聲明一個指針時便對它賦初值NULL。二、養成好習慣,在指針被free或者delete之后,對其賦值為NULL。三、在一定做好一和二的基礎下,就可以在使用指針之前只用if語句判斷指針是否為空,以做到防錯。四、避免強制類型轉換指針,除非能確保轉換前后類型所占用的空間大小是一致的。詳情可看此文:http://blog.csdn.net/zhanxinhang/article/details/6719387。


總結:指針可以當做一很好的工具,只要我們好好理解它善用它,它就能發揮它所具有的魅力。也許要真正理解指針需要些許時間去磨練去思考,但是有付出總有回報,回報過后都是值得的。現如今由于java,c#等語言的盛行,似乎指針的用武之地變少了。那么是不是有了java,c#等理解指針就不重要了呢?非也,非也。我從高中就開始接觸編程,接觸指針,上到大學才開始接觸java,c#等,從中我發現這些語言沒了指針確實是會少了些煩惱,尤其是對初手。但,對指針的理解(注意指針與內存息息相關)有助于您了解java等的底層世界,如垃圾回收機制,java虛擬機等,我認為了解這些對一個走專業化道路的java程序員是必須的。多了解點底層,多一點自由,少一點束縛。雖然要說讓指針發揮得像鋤頭那樣的驚人魅力,有點大,但至少在計算機世界里,它是的,因為有了它才有了像java這樣神奇的東西。

?


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/254555.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254555.shtml
英文地址,請注明出處:http://en.pswp.cn/news/254555.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python多進程

2019獨角獸企業重金招聘Python工程師標準>>> python多進程 進程簡介 進程是程序在計算機上的一次執行活動。當你運行一個程序&#xff0c;你就啟動了一個進程。顯然&#xff0c;程序是死的(靜態的)&#xff0c;進程是活的(動態的)。進程可以分為系統進程和用戶進程。…

halcon彩色圖像顏色處理算子,持續更新

目錄apply_color_trans_lutcfa_to_rgbtrans_to_rgbclear_color_trans_lutcreate_color_trans_lutgen_principal_comp_translinear_trans_colorprincipal_comprgb1_to_grayrgb3_to_graytrans_from_rgbapply_color_trans_lut 功能&#xff1a;申請使用顏色查找表。 cfa_to_rgb …

奪命雷公狗---node.js---20之項目的構建在node+express+mongo的博客項目5mongodb在項目中實現添加數據...

我們上一步就引入了mongodb了&#xff0c;那么下一步就要開始寫添加數據了&#xff0c;不過有個前提是先將表單的數據處理好&#xff1a; 最基本的這部現在已經成功了&#xff0c;因為最基本的這步就是先將表單處的提交方式和提交地址給處理好&#xff0c;這里和PHP的基本上是一…

重新綁定ItemsSource先設置ItemsSource = null;的原因

即報錯信息為&#xff1a;在使用 ItemsSource 之前&#xff0c;項集合必須為空。原因&#xff1a;Items和ItemSource&#xff0c;只能有一個生效&#xff0c;想用其中一個&#xff0c;另一個必須是空。重新綁定ItemSource&#xff0c;雖然綁定的集合對象Clear了&#xff0c;但是…

敏捷開發學習

Scrum 敏捷開發&#xff0c;績效管理&#xff0c;團隊管理&#xff0c;企業管理&#xff0c;ASP.net MVC 敏捷開發 培訓|咨詢 工具開發 課題研討 http://blog.csdn.net/cheny_com/article/category/794542 http://blog.csdn.net/vincetest/article/category/650747 http://blog…

Git commit后,本地代碼丟失解決方法

問題描述&#xff1a; 提交代碼時&#xff0c;rebase了兩次&#xff0c;本地代碼丟失了&#xff0c;嚇得我差點跳起來。解決方法如下&#xff1a; 1、執行命令&#xff1a; git reflog d6ea731 (HEAD -> dev, origin/dev, master) HEAD{0}: checkout: moving from master to…

Edges圖像邊緣處理halcon算子,持續更新

目錄close_edgesclose_edges_lengthderivate_gaussdiff_of_gaussedges_coloredges_color_sub_pixedges_imageedges_sub_pixfrei_ampfrei_dirhighpass_imageinfo_edgeskirsch_ampkirsch_dirlaplacelaplace_of_gaussprewitt_ampprewitt_dirrobertsrobinson_amprobinson_dirsobel_…

Android存儲數據方式

可以查看Android開發文檔中的&#xff1a;/docs/guide/topics/data/data-storage.html Android provides several options for you to save persistent application data. The solution you choose depends on your specific needs, such as whether the data should be privat…

防止cpu 一直被占用 sleep(0) 和 yield

在java的Thread類中有兩個有用的函數&#xff0c;sleep和yield&#xff0c;sleep就是線程睡眠一定的時間&#xff0c;也就是交出cpu一段時間&#xff0c;yield用來暗示系統交出cpu控制權。這兩個函數在多線程開發的時候特別有用&#xff0c;可以合理的分配cpu&#xff0c;提高程…

做一個有膽識的有為青年

1、一個年輕人&#xff0c;如果在這四年的時間里&#xff0c;沒有任何想法&#xff0c;他這一生&#xff0c;就基本這個樣子&#xff0c;沒有多大改變了。 2、成功者就是膽識加魄力&#xff0c;曾經在火車上聽人談起過溫州人的成功&#xff0c;說了這么三個字&#xff0c;“膽…

jstack應用-查找CPU飚高的原因

場景 在系統上線后&#xff0c;經常會遇到運維的同學跑過來說&#xff1a;“這次發版后&#xff0c;cpu線程使用率到一場&#xff0c;到100%了”。這時候不要慌&#xff0c;可以使用堆轉儲來分析到底是哪個線程引起的。 查找元兇 [rootjava_mofei_01 test]# top Mem: 16333644…

Enhancement增強圖形halcon算子,持續更新

目錄coherence_enhancing_diffemphasizeequ_histo_imageilluminatemean_curvature_flowscale_image_max_shock_filtercoherence_enhancing_diff 功能&#xff1a;執行一個圖像的一個一致性增強擴散。 emphasize 功能&#xff1a;增強圖像對比度。 equ_histo_image 功能&am…

音頻中采樣位數,采樣率,比特率的名詞解釋(轉)

采樣位數&#xff08;采樣大小&#xff09;&#xff1a; 采樣位數可以理解為采集卡處理聲音的解析度。這個數值越大&#xff0c;解析度就越高&#xff0c;錄制和回放的聲音就越真實。我們首先要知道&#xff1a;電腦中的聲音文件是用數字0和1來表示的。所以在電腦上錄音的本質就…

WebSocket實時異步通信

WebSocket實時異步通信 【一】WebSocket簡介 WebSocket是HTML5推出一個協議規范&#xff0c;用來B/S模式中服務器端和客戶端之間進行實時異步通信。 眾所周知&#xff0c;傳統的HTTP協議中&#xff0c;服務器端和客戶端通信只能是在客戶端發送一個請求之后&#xff0c;服務器端…

多線程和多進程的區別(小結)

分類&#xff1a; linux 2009-06-19 09:33 11501人閱讀 評論(15) 收藏 舉報 很想寫點關于多進程和多線程的東西&#xff0c;我確實很愛他們。但是每每想動手寫點關于他們的東西&#xff0c;卻總是求全心理作祟&#xff0c;始終動不了手。 今天終于下了決心&#xff0c;寫點東西…

redis-cli使用密碼登錄

redis-cli使用密碼登錄 注意IP地址要寫正確&#xff01; 學習了: https://blog.csdn.net/lsm135/article/details/52932896 https://blog.csdn.net/zyz511919766/article/details/42268219 https://zhidao.baidu.com/question/756651357338691604.html 登錄后 auth pass 或者 r…

FFT快速傅式變換算法halcon算子,持續更新

目錄convol_fftconvol_gaborcorrelation_fftdeserialize_fft_optimization_dataenergy_gaborfft_genericfft_imagefft_image_invgen_bandfiltergen_bandpassgen_derivative_filtergen_filter_maskgen_gaborgen_gauss_filtergen_highpassgen_lowpassgen_mean_filtergen_sin_band…

仿照vue實現簡易的MVVM框架(一)

代碼github地址&#xff1a; https://github.com/susantong/myMVVM 主要的方法有&#xff1a; compile 深度遍歷前端界面的節點&#xff0c;將其復制進一個addQuene隊列中pasers 遍歷所有的節點&#xff0c;并將節點包裝成一個含有本節點、自定義屬性及屬性值的對象。要想實現雙…

tomcat 啟動時內存溢出

在tomcat_home/bin目錄下找到catalina.bat&#xff0c;用文本編輯器打開&#xff0c;加上下面一行&#xff1a; set JAVA_OPTS -Xms1024M -Xmx1024M -XX:PermSize256M -XX:MaxNewSize256M -XX:MaxPermSize256M 解釋一下各個參數&#xff1a; -Xms1024M&#xff1a;初始化堆內存…

@angular/platform-browser-dynamic

/** experimental */ export declare class JitCompilerFactory implements CompilerFactory {createCompiler(options?: CompilerOptions[]): Compiler; }export declare const platformBrowserDynamic: (extraProviders?: StaticProvider[] | undefined) > PlatformRef;…