c語言中認識指針

地址和變量的概念

指針

作用:
1、表示複雜的數據結果(eg:鏈表、樹、)
2、能動態分配內存
3、方便的使用字符串
4、有效而方便使用字符串
5、有效而方便的使用數組
&&&調用函數的時候能夠獲得1 個以上的結果。
6、能夠直接處理單元地址等

總結:可以看到可以很直接的接觸到計算機的硬件的內容進行操作。

1、數據的存儲和讀取:
定義一個變量,程序在編譯的時候,會給這個變量分配內存單元。
(依據:系統會根據程序中定義的變量的類型,分配一定的長度空間。eg:32位機,int分配2位字節,char分配1位字節,浮點型分配4個字節,內存中每一個字節都有一個編號,這個就是“地址”,地址標誌內存單元,而內存單元是用來存放數據的。)

內存單元的內存和內存單元的地址的區別:
程序:
int i,j,k;
編譯的時候,分配內存:
2000,2001分配給i,
2002,2003分給給j,
2004,2005分配給k;
即爲:內存單元的內容就是地址中存放的數據,而地址就是2000~2005等。

在程序中,一般是“通過變量名”來對內存單元進行存取操作的。(程序員對變量以及方法的使用)
實際上,計算機中的實際運行爲:計算機編譯程序之後,將變量名轉化爲變量的地址,對變量的存取都是通過地址來進行的。
總結:從程序員的角度可以看到一種別名的方式,從計算機的角度上看是實際的操作。
eg:
printf("%d",i);
(編譯的時候會將i這個變量,編譯成爲一個對應的地址)
找到i變量的地址(2000),從2000開始的兩個字節取出數據,然後輸出。
scanf("%d",&i);
將鍵盤中輸入的值存放到i對應的地址上(i整形變量的地址爲:2000,2001)。

若是:
k = i+ j;
將i(2000,2001)存放的值和j(2002,2003)存放的值進行相加,送到k所佔用的內存地址爲2004,2005的內存地址上。
這種變量地址存取變量值的方式成爲“直接訪問”方式。

總結:我們可以回顧一個“微機”課程上的彙編的集中方式。

另一種訪問的方式:
簡介訪問:即爲將變量的地址存放在另外一個變量中。
(c語言中的類型變量的定義)c語言中,程序可以定義整形變量、字符變量、實型變量。
同時也是可以定義這樣的一個變量的,就是用它來存放地址。
eg:我們定義一個變量t_pointer 用來存放整形的變量地址。它被分配爲3010,3011這兩個字節,可以通過下面的語句將i的地址(2000)存放在這個變量中。
t_pointer = &i;所以這個時候的t_pointer的值就是2000(即爲它的值就是i的變量的地址的起始地址2000);
下面來了解一下簡介方式進行對數值進行存儲:
先找到i的地址存放的遍歷t_pointer,然後從裏面獲取i的地址(2000),然後懂啊2000,2001裏面獲取相應的i的值。
這個就是中間多了一個變量。============>(間接存儲(地址變量))

總結一下:i的變量
1)、直接方式,就是知道i它的地址,然後直接獲取i的值;直接通過i的變量的i的地址量進行對i的值得訪問。
2)、將i的變量的地址,存放到另外一個專門是用來存放地址的變量中。所以在訪問的時候需要通過存放地址的-變量獲取到相應的的地址 ,然後通過地址來獲取i值。

(所謂的“指向”,就是存放內存的地址來進行相應的指定,這樣就可以通過這個變量來訪問它所指向的地址的位置。)
通常:
我們經常會說,通過地址指向能夠找到所需要的單元,可以說地址指向待單元變量。
因此:地址形象化爲指針。意思即爲:通過它能夠找到以它爲地址的內存單元。(eg:根據地址2000就能夠找到變量i的存儲單元,從而讀取其中的值。)
一個變量的地址稱爲這個變量的指針。上述:2000是i的指針,t_pointer就是一個指針變量。 指針變量的值就是地址(或者說是:指針)
區分指針變量和指針:
eg:變量i的指針是2000,而不能夠說i的指針變量是2000,i的指針變量是t_pointer。明白啥爲變量。

3)、指針就是一個地址,而指針變量就是一個存放地址的變量。、

再一次總結:
(1)指針(地址)同意概念,指針變量就是存放地址的變量。

(2)直接存儲不存在指針變量的問題,而間接存儲需要涉及到變量。


變量的指針和指向變量的指針變量


變量的指針就是變量的地址,存放變量的地址的變量就是指向變量的指針變量。

爲了表述指針變量和 它所指向的變量的關係,可以使用“*”來表示。
eg:(*t_pointer )是t_pointer所指向的變量。

i = 3;
*t_pointer = 3; 即爲:將3賦值給指針變量t_pointer所指向的變量。

1、定義一個指針變量
(c語言(強類型語言)固定每一個變量在使用之前必須先定義,指定類型,並且按此來分配內存單元)
指針變量定義爲指針類型。
eg:
一般的:int i,j;  //定義兩個整形變量i,j
指針的: int *t_pointer_1,*t_pointer_2;//定義兩個指針變量,
指針類型中:左端的int是在定義指針變量的時候,必須指定的“基本類型”,指針變量的“基本類型”用來規定了指針變量可以指向的變量的類型。上面的兩個指針可以指向基本類型爲int的,而不能夠指向浮點類型的數據。

第一的格式:
基本類型 * 指針變量名;
eg:
float * pointer_3;
char * pointer_4;

指針變量之間的的賦值。
如何使指針指向另外一個變量呢?
eg:
t_pointer_1 = &i;
t_pointer_2 = &j;
所以:將變量i的地址存放在指針變量t_pointer_1中,因此,pointer_1就指向了變量 i;j也是同樣。
這個時候*t_pointer_1 就表示是i的值。

定義指針變量的時候注意兩點:
(1)指針變量的前面的“ * ”表示該變量的類型爲指針型變量。指針變量名是t_pointer_1,而不是(*t_pointer_1),這個和其他的基本類型的定義不同。
(2)定義指針變量的時候,必須指定基本的類型。
原因:不同的基本的類型,指針所指向的位置的移動等等操作是不一樣的。
eg:如果指針指向的是“整形變量”,那麼使“指針移動一個位置”意味着移動2個字節;使指針+1 意味着地址的值加2個字節。如果指針-指向的是浮點型,那麼指針增加的不是2而是4。
同時,指針變量只能夠指向一種類型的變量,不能夠指向其他類型的變量。
下面的錯誤的例子:
float a;
int *pointer ;
pointer = &a;(錯誤的)

總結:
1)、指針變量的定義以及符號“*”的含義。
2)、定義指針變量的時候定義好基本的類型,並且一種類型的指針只能夠指向它當前類型的指針,可以聯想指針的增減操作。


2、指針變量的引用
兩個有關的運算符:
(1)& :取地址運算符
(2)* :指針運算符(或者“簡介訪問”運算符),取其指向的內容。
eg:&a 爲變量a的地址,*p爲指針變量p所指向的存儲單元的內容(即:p所指向的值)。
eg:如下代碼

#include <stdio.h>
void main()
{
    int a,b;
    int *pointer_1,*pointer_2;
    a = 100;b=10;
    pointer_1 = &a;//把變量a地址賦值給pointer_1
    pointer_2 = &b;//把變量b的地址賦值給pointer_2
    printf("%d,%d \n",a,b);
    printf("%d,%d \  n",*pointer_1,*pointer_2);
}

結果:
100,10
100,10

說明:
(1)&*pointer的含義是什麼?(pointer是指針變量)“&”和“*”兩個雲算符的優先等級是相同的,但是按照自右邊而左邊方向結合。因而先進行*pointer,在執行&,相當於&(*pointer)一般是這樣寫,結果即爲:a的地址。
(2)*&a的含義是什麼?先進行&a(a爲基本的類型),即爲a的地址,然後在進行*運算,就是a地址指向的變量a。結果即爲:a的值。
即爲上面的兩個是等價的。
(3)(*pointer)++ 相當於a++,括號是必要的。沒有括號爲:*pointer++ (++ 和* 是等級是相同的),結合運算是自右向左的。所以相當於*(pointer++)。由於++在pointer的值是改變的,這樣pointer不再指向a了。
代碼:
#include <stdio.h>
void main()
{
    int *p1,*p2,*p,a,b;
    scanf("%d,%d",&a,&b);
    p1 = &a; p2 = &b;
    if(a<b){
    p = p1;
    p1 = p2;
    p2 = p;
    }
    printf("a=%d,b=%d \n\n",a,b);
    printf("max=%d,min=%d \n",*p1,*p2);
}
結果:
5,9  //輸入
a=5,b=9   //輸出
max=9,min=5

說明:a和b並沒有交換,他們依舊保持原值。但是p1和p2的值改變了。p1的開始是&a,後來是&b。p2原來的值是&b,後來的值是&a。
(這個方法不是交換兩個整形變量的值,而是交換兩個指針變量的值)

總結:
1)、指針變量的使用,注意它的的操作符號。
2)、指針的變量操作的時候,改變的是指針變量中存放的地址。而不會直接去改變它所指向的變量的值,像上面。
除非使用*符號來獲取值進行改變。


3、指針變量作爲函數的參數

函數的參數不經可以是整型、浮點型、字符型等數據,還可以是指針類型。
所用是:將一個變量的地址傳送到另一個函數中。

代碼:
#include <stdio.h>
void swap(int *p1,int *p2);
int main()
{
    int a,b;
    int *pointer_1,*pointer_2;    
    scanf("%d,%d",&a,&b);
    pointer_1 = &a;
    pointer_2 = &b;
    if(a<b) swap(pointer_1,pointer_2);
    printf("%d,%d \n",a,b);
    return 0;
}
(1)
void swap(int *p1,int *p2)
{
    int temp;
    temp = *p1;  
    *p1 = *p2;//這種方式改變該地址指向的變量的值
    *p2 = temp;
}
結果:
5,6  //輸入
6,5  //輸出

說明;
實參pointer_1 、pointer_2是指針變量,在函數調用的時候,將實參的變量的值傳給形參變量,採取的依然是“值傳遞”方式,這裏的“值傳遞”中的值是地址值。
虛實結合了之後,p1的值是&a,p2的值是&b。這個時候p1和pointer_1是指向同一個變量a,p2和pointer_2同樣指向一個變量b。
swap函數體內,使*p1 和*p2 的值互換。也就是a,b的值交換。函數結束了之後p1,p2 銷燬,所以交換了數值。
(注意:這裏交換的是a,b的值,而不是p1,p2的值。) 這個改變不是通過形參傳回給實參實現的,而是通過形參的地址變量和實參指向同一個變量來實現的。

(2)有問題的代碼:
void swap(int *p1,int *p2){
    int *temp;
    *temp = *p1;
    *p1 = *p2;
    *p2 = *temp;
}
運行結果:
5,9
Segmentation fault (core dumped) 分割故障(核心轉儲)

原因:*temp是指針變量temp所指向的變量。但temp中並無確定的值(它的值是不可預見的),因此temp所直線的單元也是不可以預見的。(也即是temp裏面存放的值是不確定,隨時改變,如果*temp存放了值之後,再來取不一定是原來的值)
因此,對*temp賦值有可能給一個存儲重要數據的存儲單元賦值。這樣會破壞系統的正常工作狀況。所以,應該講*p1的值賦值給一個臨時變量實現。

(3)
void swap(int x,int y ){
    int temp;
    temp = x;
    x =y;
    y = temp;
}
這裏的結果是不會改變的,因爲函數是單向傳遞值的,這裏並沒有地址等概念,只是存儲的數值的單向傳遞。即爲函數調用結束了之後,就會銷燬。

解說一下(1)的原理:用指針變量所謂函數參數,在函數執行的過程中使指針變量所指向的變量值發生變化,函數調用結束後,這些變量值得變化依然保留下來,這樣就實現了“通過調用函數使變量的值發生變化,而主函數可以使用這些改變了的值”。

(4)注意不要企圖改變指針形參的值而是指針的實參的值改變。
void swap(int *p1, int *p2){
    int *p;
    p = p1;
    p1 = p2;
    p2 = p;
}
編程者的思想:交換pointer_1 和 pointer_2 的值,是pointer_1指向值大的變量。
設想:
(1》》先是pointer_1指向a,pointer_2指向b,
(2》》調用swap函數,將pointer_1 的值傳給p1,pointer_2的值傳給p2;
(3》》在swap函數裏面,使p1與p2的值交換。
(4》》形參p1,p2將地址傳回實參pointer_1,pointer_2,想得到輸出:9,5 。
但是,不行的。程序輸出的結果還是:5,9;
問題出現在第4步:
c語言中實參變量和形參變量之間的數據傳遞是單向的“值傳遞”方式,指針變量作爲參數也是要遵循這個原則。
不可能通過調用函數來改變實參指針變量的值,但可以改變實參指針變量所指變量的值,像(1)。

使用函數只能夠得到一個返回值,而運用指針變量做參數,可以得到多個變化的值(如:(1)所示)[因爲它相當於在另外一個入口進行對同一個變量的值操作]。

總結:
(1)指針變量作爲參數,同樣是“值傳遞”,單向傳遞。不過這裏傳的是指針的值。
(2)函數只可以返回一個值,而指針作爲參數,可以對多個值的改變。是通過指針變量所指向的變量的值的而改變。


總結

(1)知道指針、地址、指針變量等等概念。

(2)指針的定義以及符號的使用

(3)指針作爲函數的參數進行傳遞,可以改變多個值。解決了一個函數只能夠返回一個值的作用。


發佈了144 篇原創文章 · 獲贊 11 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章