天天看點

C指針——C語言手記

        近期敲代碼的時候。發現自己非常多東西都開始忘了。

今天最終有機會好好總結一下指針。當做個筆記同一時候也希望對大家實用。假設有不對的地方。希望大家能幫我指正一下。然後我的實驗環境是32位rhel+eclipse。

一、指針基本屬性

指針的屬性主要包含指針的類型、指針所指向的類型、指針的值。以下以一個簡單的樣例為例 int *p; 指針的類型:int * 指針所指向的類型:int 指針的值(指針所指向記憶體區的位址):野指針 總結一下,指針的類型:去掉變量名字之後的那一部分                     指針所指向的類型:去掉*變量名之後的那一部分                     指針的值:指針所指向記憶體區的位址 最後這裡另一個小點,指針是否站記憶體空間。 答案是肯定的,我們做一個簡單的實驗測試一下:
C指針——C語言手記
這裡為什麼都是4位元組呢?由于我們指針的存儲内容是記憶體位址,而我的機子是32位。 32位就是4個位元組! 注:區分指針的類型和 指針所指向的類型是精通c的關鍵

二、&和*運算符

       &運算符叫做取位址運算符。*運算符叫做間接運算符(取内容運算符)。 他們和指針結合在一起的時候,常常讓我們無比頭疼。 像段錯誤,非常多時候也是他們使用不當導緻的。這裡引用一個比較好的總結: &p的運算結果是一個指針,指針的類型是p的類型加個*。指針所指向的類型是p的類型,所指向的位址就是p1的位址。 *p的運算結果是p所指向的東西,他的類型是p指向的類型。它的位址是p所指向的位址。 理論總是難以了解的。我們來做做實驗:
C指針——C語言手記
&n的運算結果事一個指針,指針的類型是int *,指針所指向的類型是int。(和等号左邊的p資訊比對上了) &p的運算結果事一個指針。指針的類型是int **,指針所指向的類型是int *。(和等号左邊的ptr資訊比對上了) printf("the value of p is %d\n",*p); 因為之前的p=&n,是以p指向的是n的位址。可是&p(p本身自己的位址)沒有變化。是以*p的值就是p指向的位址的内容。也就是4。*p的類型是int,是以這裡用%d進行輸出。 printf("the value of ptr is %x\n",*ptr); 同理。這裡ptr指向的是p的位址。 可是&ptr(ptr本身自己的位址)沒有變化。是以*ptr的值就是ptr指向的位址(p的位址)的内容。也就是n的位址。*ptr的類型是int *。是以這裡用%x進行輸出。 更加簡單直白地說,*就是降*操作符。&是升*操作符。

三、指針和數組

在有了上面的基礎之後,我們繼續來看看指針和數組。先看看以下的測試代碼:
C指針——C語言手記
     首先,我們發現對于type name[n];這種數組。我們能夠通過*(name)、*(name+1)、*(name+2)。。。。。。遞推訪問數組的每個元素。 注:這裡須要加括号進行訪問,那程式上面的和我們日常看到非常多程式中都沒有加括号。我們将在以下介紹他們的詳細差别。 由于衆所周知數組就是一個連續的記憶體塊,而name指針中存儲的是數組的記憶體塊的起始位址。是以這裡我們通過二中的間接運算符*(取内容符)擷取起始位址中的内容。 然後+1訪問第二塊位址上的内容。       可是這裡須要注意的是,這裡的1等數字不是我們了解中的int類型的數字。這裡的數字是類型的長度。以上面的int array[10]為樣例,int的長度是32位(4個位元組)。是以*array+1就是指起始位址+4位元組。也就是array[1]的存儲位址。       然後接下來,我們嘗試再複雜一點一起看看字元串數組: printf("the second char of %s is %c.\n",*team,*(*team+1)); 由于這裡是數組指針,比之前更加複雜一點。由于c語言是沒有string類型的。是以china事實上就是一個char數組。然後這裡的team數組是3個字元類型的指針。team存儲的就是這三個字元數組(china,american,japan)的起始位址。也就是china的起始位址。是以第一個參數*team得到的是字元串china。 那當我們想通過team訪問特别字元串中的指定字元怎麼辦?首先我們要區分以下的概念: *team+1和*(team+1)的差别 這裡的兩個1對編譯器來說都是不一樣的,為什麼呢?由于正如上面所說,這裡面的數字就是類型長度。可是 *(team+1)的類型長度是sizeof(char *)4位元組,而*team+1中的類型長度是sizeof(char)1位元組。 為什麼會這樣,将在以下的步長變化規則中進行介紹! 那上面為什麼能夠通過*array+1訪問到array[2]呢? 這裡的主要原因是*(array+1)中的1編譯器覺得是4位元組(sizeof(int))。而*array+1中的1編譯器覺得 是int整型1。是以當數組是{0,4,3,6,7}的話,*array+1得到的答案将是1而不是4。 步長的變化規則是什麼呢?        要了解步長的變化規律,首先我們要清晰地得到數組的元素類型。事實上也很easy。就是去掉變量名剩下的 就是數組元素類型:         char *array[10];//元素類型是char *         int test[10];//元素類型是int        那什麼是上一級元素類型,事實上就是元素類型去掉一個*。假設沒有*了,就表示已經是頂級。       char *array[10];//元素類型是char *,上級元素是char         int test[10];//元素類型是int,頂級        最後就是步長的變化規則:                              1)當變量名每和*結合一次。步長變成上級元素的長度。                              2)當頂級元素再和*結合。步長變為1,1的類型是正常的int。                              3) 初始步長為數組元素類型長度 是以,*(array+1)的步長是sizeof(char *)  //這裡由于沒有和*結合過,所這裡步長是sizeof(char *)              *array+1的步長是sizeof(char)  //這裡由于結合了一次,是以這裡的步長是上級元素類型char的長度             *(test+1)的步長是sizeof(int)  //這裡由于沒有和*結合過。是以步長是sizeof(int)             *test+1的步長是整型1。也就是說假設*test的值時4那*test+1的值就是5 //這裡由于和*結合了一次之後。發現int已經是頂級元素了。不能再更新,是以這裡編譯器把它默覺得整型。

四、指針和結構體

還是老規矩,先晾代碼再分析:
C指針——C語言手記
這裡先清晰一些概念,指針通過—>訪問結構體内部的變。而結構體本身是通過 . 來訪問自己的變量的。 是以p指向新建立結構體之後,通過printf("the content of p is %d and %x.\n",p->data,p->next);來訪問自己結構體内部的變量。 然後這裡比較複雜的可能是: content of n is %d and %x.\n",(*(p->next)).data,(*(p->next)).next); 這裡p->next指向的是n的存儲位址,然後我們用*取出了n的内容。然後通過.來訪問n自身的變量。有沒有感覺自己對指針熟悉了非常多呢?o(∩_∩)o

五、指針的強制類型轉換

C指針——C語言手記
我們要分析出為什麼能這樣做,要先了解以下幾個點: 1)結構體的構成

typedef struct node{ int data; struct node *next; }; 以這裡結構體為例,int 類型是4個位元組。 struct node*類型是指針類型是以是4位元組。 是以有了第一個輸出8. 2)強制類型轉換之後的步長 強制類型轉換之後。步長也發生了變化。由于起始元素類型(一子產品中的指針指向的變量類型)變成了int,是以這裡的步長是sizeof(int)也就是4位元組。 printf("the value of n is %d and %x.\n",*p,*(p+1)); 這裡大家注意struct node的第一個變量int的步長也是4位元組。 是以(p+1)後從開始的起始位址剛好偏移了4位元組。然後得到了變量*next的起始位址,然後通過*取出其内容。 到這來就結束啦!祝願大家早日成為c語言的高手,假設上面有不對的地方。或者看完還有什麼疑惑。都歡迎大家指出來,一起讨論讨論。 轉載請注明:javascript:void(0)

繼續閱讀