午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

從*p++說指針,數(shù)組,結(jié)構(gòu)和函數(shù)

 心不留意外塵 2016-05-16

http://blog.csdn.net/unix21/article/details/16116737

2013

說明文中*p++和*s++都是一個東西,不做字面上的統(tǒng)一了。

因為右結(jié)合性,*p++ 其實就是 *(p++) 


1.strlen的實現(xiàn)

  1. #include <stdio.h>  
  2. main(){  
  3.     char str[]= "Abcde";  
  4.     printf("\n string = %s length = %d \n",str,str_length(str));  
  5. }  
  6.   
  7. int str_length (const char *s){  
  8.     int length = 0;  
  9.     while (*s++){  
  10.         length++;  
  11.     }  
  12.     return (length);  
  13. }  
其實*s++的過程




遞增到最后一位就是\0,也就是“”.


注意:*s已經(jīng)指向后面的內(nèi)容了,就是亂碼了



2.數(shù)組和指針這2種方式表示字符串的差異
  1. #include <stdio.h>  
  2. main( )  
  3. {  
  4.     char  str[]= "Abcde";  
  5.     char*  ptr = "12345";  
  6.     *ptr++;  
  7.     printf ("\n string = %s length = %d \n",ptr,str_length (ptr));  
  8.     printf ("\n string = %s length = %d \n",str,str_length (str));  
  9. }  
  10.   
  11. int str_length (const char  *s)  
  12. {  
  13.     int length = 0;  
  14.     while (*s++)  
  15.     {  
  16.         length++ ;  
  17.     }  
  18.     return (length) ;  
  19. }  
輸出:


2.1 數(shù)組不能直接當(dāng)指針用,數(shù)組名不能指針運算
也就是說數(shù)組名代表數(shù)組的首元素,它是一個指針常量,它的值在程序運行期間是固定不變的,  *str++是不可以的;
ptr是指針變量當(dāng)然可以實現(xiàn)ptr++的運算但是指針自然可以指針運算。


直接數(shù)組名++就報錯了:


2.2 數(shù)組名不能直接賦值,但是指針可以

給數(shù)組名賦值就報錯了:


第1次指針地址是:0x010f5860


第2次指針地址是:0x010f5861


第3次指針地址是:0x010f5868


第4次指針地址還是:0x010f5868


下面是《明解C語言》書的截圖:


3.  int下*s++,(*s)++,++*s,++(*s)的差異
首先 如果*s是指針,那么*s++就不是將*s的值加1,而是將*s指向的地址加同一個單位大小。所以為了避免類似問題,需要的時候要加括號。

--出自《C語言入門經(jīng)典 第4版》

  1. #include <stdio.h>  
  2. void add(int *s)  
  3. {  
  4.     *s++;  
  5. }  
  6.   
  7. int str_length (char  *s)  
  8. {  
  9.     int length = 0;  
  10.     while (*s++)  
  11.     {  
  12.         length++ ;  
  13.     }  
  14.     return (length) ;  
  15. }  
  16.   
  17. main( )  
  18. {  
  19.     int a=1;  
  20.     int *b=&a;  
  21.     char  str[]= "Abcde";  
  22.     char*  ptr = "12345";  
  23.     *ptr++;  
  24.     ptr="def";  
  25.     add(b);  
  26.     printf ("\n string = %s length = %d \n",ptr,str_length (ptr));  
  27.     printf ("\n string = %s length = %d \n",str,str_length (str));  
  28. }  


第1次*s++之前的地址是:0x002afc98


第2次*s++之前的地址是:0x002afc9c
fc9c-fc98=4  就是一個int的大小
*s++只是對s的地址遞增然后解引用,得到-858993460,并沒有改變*s的值!


跳出函數(shù)a沒有變化


所以要想得到Int型值的遞增可以這樣寫即可:
  1. void add(int *s)  
  2. {  
  3.     (*s)++;  
  4. }  

由于char*大小正好是1個字節(jié),所以char*的++正好指向下一個字符!
所以在字符串的操作中正好可以用*s++,如果使用了括號,(*s)++這樣的話反而會引起內(nèi)存錯誤。

4.字符串復(fù)制
  1. #include <stdio.h>  
  2.   
  3. void xstrcpy ( char  *t, char  *s ){  
  4.     while ( *s != '\0' )  
  5.     {  
  6.         *t = *s ;  
  7.         s++ ;  
  8.         t++ ;  
  9.     }  
  10.     *t = '\0' ;  
  11. }  
  12.   
  13. void strcpy(char *s,char *t){  
  14.     //while((*s++=*t++)!='\0')  
  15.     //表達式通'\0'的比較是多余的,因為只需要判斷表達式的值是否為0即可。  
  16.     while(*s++=*t++)  
  17.         ;  
  18. }  
  19.   
  20. //標(biāo)準(zhǔn)庫實現(xiàn)  
  21. char * strcpy2(char *s,char *t){  
  22. char *r=s;  
  23.     while(*s++=*t++)  
  24.         ;  
  25.     return r;  
  26. }  
  27.   
  28. void main()  
  29. {  
  30.     char  source[] = "Abcde" ;  
  31.     char  target[20] ;  
  32.   
  33.     strcpy ( target, source ) ;  
  34.     printf ( "\nsource string = %s", source ) ;  
  35.     printf ( "\ntarget string = %s", target ) ;  
  36. }  
  37. /* 
  38. 想經(jīng)過函數(shù)調(diào)用改變某個變量的值,就要傳入變量的地址。 
  39.  如果變量是基本類型,要傳入對應(yīng)的指針類型。 
  40.  如果變量是指針,要傳入指針的指針。 
  41.  */  


--出自《C語言程序設(shè)計語言 第2版》



5.說清楚函數(shù)傳遞參數(shù)


一開始我們會想既然已經(jīng)在函數(shù)中*s++了,而且也確實改變了指針的位置,但是為什么一回到調(diào)用函數(shù)中,*s就又復(fù)原了?
不是說傳指針是按引用傳遞的么?

其實,誤區(qū)也正在于此,函數(shù)還是傳值的,傳遞的都是原值的拷貝,如果傳遞指針,在調(diào)用函數(shù)中使用*解引用,可以改變指針指向的值,但是不能改變指針的內(nèi)容,因為函數(shù)調(diào)用只是傳遞了原始指針指向值地址的拷貝,就是說原始地址拷貝了2份,所以在函數(shù)中改變是改變了地址,但是沒有意義。


int a = 0x55aa;

change_value(&a, 0xaa55);

這樣a的值改變了,真正的情況是參數(shù)傳遞后,編譯器做了一個參數(shù)拷貝過程,比如聲明一個整型指針pCopy = &a;

這樣,pCopy只是傳進來參數(shù)&a的一份拷貝,但是他們都指向了a的地址,因此用這種方法可以改變a 的值。


那么現(xiàn)在有個問題,通過傳遞一個指針,可以改變該指針?biāo)赶虻刂返膬?nèi)容,那么如何改變指針本身呢?
該怎么做才能改變ptr呢?

既然ptr也是一個變量,我要在函數(shù)內(nèi)部改變它,那么就傳遞一個指向ptr的指針!也就是二級指針!



6.函數(shù)返回指針

絕不返回函數(shù)中本地變量的地址。


函數(shù)返回指針可以用如下方法:

1.可以用malloc分配內(nèi)存,并返回這個內(nèi)存的地址

2.返回指針參數(shù)


注意函數(shù)中可以聲明一個新的結(jié)構(gòu)struct,然后返回結(jié)構(gòu),但是不可以返回臨時指針



7.數(shù)組和指針的差異
數(shù)組不是指針,作為參數(shù)傳遞的數(shù)組會退化為指針。





為什么C語言把數(shù)組形參當(dāng)做指針?



再來看看《你必須知道的495個C語言問題》



8.數(shù)組不能被賦值
數(shù)組不能賦值,可以指定數(shù)組下標(biāo)賦值,可以在函數(shù)中可以給數(shù)組賦值,因為這個時候數(shù)組退化為指針。




9.數(shù)組的大小




10.指針和結(jié)構(gòu)

結(jié)構(gòu)體指針4個字節(jié),結(jié)構(gòu)體大小要看數(shù)據(jù)對齊
分配12個字節(jié),結(jié)構(gòu)吃掉8個,當(dāng) (結(jié)構(gòu)地址+1)所以只能第一個元素可以分配到初始化的0,第二個元素就分到垃圾地址了

  1. struct tt{  
  2.     int size;  
  3.     int slabs;  
  4. };  
  5. void main()  
  6. {  
  7.     void *s=malloc(12);  
  8.     struct tt *t1;  
  9.     memset(s,0,12);  
  10.     t1=(struct tt*)s;  
  11.     t1->size=1;  
  12.     t1->slabs=2;  
  13. }  

指針不對齊8a88  和8a90差2   8a90和8a98差8    結(jié)構(gòu)有2個Int  所以結(jié)構(gòu)大小是8

結(jié)構(gòu)和指針的關(guān)系
對同一個地址可以轉(zhuǎn)換為任意結(jié)構(gòu)體,雖然數(shù)據(jù)結(jié)構(gòu)亂了,但是畢竟也是有數(shù)據(jù)。
所以使用法則也就是使用前先尋址,再強制轉(zhuǎn)換


11.變量作用域

局部變量的作用域一般認(rèn)為是在函數(shù)體內(nèi)。但是根據(jù)C99標(biāo)準(zhǔn),該說法有了變化。在新的標(biāo)準(zhǔn)中,允許即時定義局部變量,示例如下:

for( int i = 0; i < MAXSIZE; i++ )

{

….

}

例子中的局部變量i的作用域即在for循環(huán)的花括號中,當(dāng)for循環(huán)結(jié)束的時候,局部變量i的生存周期同時結(jié)束。也就是說,在下一個for循環(huán)中,你仍然可以再次重新定義并使用名為i的局部變量。該語法只能在C99之后的新的C編譯器中使用, 例如VC2005、VC2008、gcc4.2及以上版本。但是,該語法帶來了編程風(fēng)格的變化,而且變量隱含在了執(zhí)行程序中,無論是代碼的閱讀和維護都有較大的困難,因此工程項目中不建議使用該語法。


for循環(huán)中定義的pit 在離開循環(huán)以后就不存在了。


12.傳遞結(jié)構(gòu)和數(shù)組給函數(shù)的差異

為什么傳遞給函數(shù)的結(jié)構(gòu)沒有像數(shù)組一樣退化為指針,因為數(shù)組可以用指針去偏移量,但是結(jié)構(gòu)無法做到這一點,或者說非常困難。

其實函數(shù)參數(shù)默認(rèn)是通過r0,r1,r2,r3四個寄存器傳遞的,多余的參數(shù)是通過將參數(shù)壓入棧中傳遞的。同理對于一個結(jié)構(gòu)體如果其大小少于32字節(jié)(4個寄存器),按照正常的方式通過r0到r3傳遞,多于32字節(jié)則是將多余的部分在堆棧上建立個備份進行傳遞。

    所以對于在ADS編譯器下對于函數(shù)參數(shù)是結(jié)構(gòu)體的傳遞,還是傳入指針比較好。既高效(省去建立備份的時間),又節(jié)省??臻g。


13.指針大小

32位是4個字節(jié),32=4*8     

64位是8個字節(jié),64=8*8     

在64位的linux下:

而visual studio里默認(rèn)是win32平臺,指針是4個字節(jié)大?。?/p>


需要修改為x64平臺

這時候顯示指針是8個字節(jié):



14.指向數(shù)組的指針
slabclass_t *p = &slabclass[id];


 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多