指針

  • 指針

指針是C語言中一個重要的概念也是一個重要的特色。

正確而靈活的運用它,可以有效的表示複雜的數據結構,能動態的分配內存;能方便的使用字符串;有效而方便的使用數組。

掌握指針的應用,可以使程序簡潔、緊湊、高效。可以說,不掌握指針就是沒有掌握C語言的精華。

7、1地址與指針的概念

爲了說清楚什麼是指針,必須弄清楚數據在內存中是如何存儲的,又是如何讀取的。

地址

內存

0

...

 

2000

5

2001

6

2002

7

2003

 

...

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

在C語言中,對變量的訪問有兩種方式,直接訪問和間接訪問。

直接訪問: 如 a=5

  系統在編譯的時候,已經對變量分配了地址,例如,若變量分配的地址是2000,則該語句的作用就是把常數5保存在地址爲2000的單元中。

間接訪問 :scanf(“%d”,&a);

 調用函數的時候,把變量a的地址傳遞給函數Scanf函數首先把該地址保存到一個單元中,然後把從鍵盤接收的數據通過所存儲的地址保存到a變量中。

7、1、1初識指針

在C語言中,指針是一種特殊的變量,它是存放地址的。假設我們定義了一個指針變量

 int* i_pointer用來存放整型變量i的地址。可以通過語句i_pointer = &i;

7、1、2初識兩個操作符

*:叫做取值操作符   

   注意:如果這樣寫 int *p;則*代表的是指針的定義操作

        如果這樣寫 int i= 2000;  int *p=&i;  printf(“%d\n”,*p); //此處的*代表的是取值操作。

&:叫做取地址操作符

7、1、3指針與指針變量

知道了一個變量的地址,就可以通過這個地址來訪問變量,因此,又把變量的地址稱之爲該變量的“指針”。

C語言中可以定義一類特殊的變量,這些變量專門用來存放變量的地址,稱之爲指針變量

注意:指針變量的值(即指針變量中存放的值)是地址(即指針)。請區分“指針”和“指針變量”

7、1、4定義一個指針變量

下面都是合法的定義

float* pointer_3;  //pointer_3是指向float型變量的指針變量

char *pointer_4; //pointer_4是指向字符型變量的指針變量

可以用賦值語句使一個指針變量得到另一個變量的地址,從而使它指向一個該變量。

在定義指針變量的時候要注意兩點:

  • 指針變量前面的“*”,表示該變量的類型爲指針型變量。其一般形式爲:

   類型說明符 *變量名;

  其中,*表示一個指針變量,變量名即爲定義的指針變量名,類型說明符表示本指針變量所指向的變量的數據類型。

  例如:float* pointer_1;

   指針變量名是pointer_1,而不是*pointer_1;

  • 在定義指針變量時要注意兩點

  需要特別注意的是,只有整型變量的地址才能放到指向整型變量的指針變量中。下面的賦值是錯誤的。

float a;

int *pointer_1;

Pointer_1=&a;

/*

將float型變量的地址放到指向整型變量的指針變量中,錯誤*/

7、2對&與“*”運算符再做一些說明

1)如果已經執行了 pointer_1=&a;    int *p=&a;  == int *p;p=&a;

那麼&*pointer_1的含義是什麼?

&a  a的地址

如果有pointer_2 = &*pointer_1;

它的作用是將&a(a的地址)賦給了pointer_2,如果pointer_2原來指向b,經過重新賦值後它已經不再指向b了,而是指向a.

2)*&a的含義是什麼?

a的值

先進行&a運算,得到a的地址,在進行*運算。即&a所指向的變量,也就是變量a。

3)(*pointer_1)++相當於a++

注意括號是必要的,如果沒有的話就是按照自右向左的運算規則,從附錄可知:++和*爲同一優先級。

7、3數組與指針

一個變量有地址,一個數組包含若干個元素,每個數組包含若干元素,每個數組元素都在內存中佔用存儲單元,它們都有相應的地址。

指針變量既然可以指向變量,當然也可以指向數組元素(把某一個元素的地址放到一個指針變量中)。

7、3、1指向數組元素的指針

 定義一個指向數組元素的指針的變量的方法,與以前介紹的指向變量的指針變量相同。

例如:

int a[10];(定義a爲包含10個整型數據的數組)

int *p;(定義p爲指向整型變量的指針變量)

應當注意,如果數組爲int型,則指針變量的基類型也應該是int型

P=&a[0];

把a[0]元素的地址賦值給指針變量p。

也就是說使p指向a數組的第0號元素。

引用一個數組元素,可以使用

  1. 下標法,例如a[i]形式
  2. 指針法,如*(a+i)或者*(p+i)

其中的a是數組名,P是指向數組元素的指針變量,其初值爲p =a;

注意:數組名即“翻譯成數組的第一個元素的地址!”

7、3、2用函數名作函數參數

f(int arr[],int n) 但是在編譯的時候是將arr按照指針變量處理的,相當於將函數f的首部寫成f(int *arr,int n)以上兩種寫法是等價的。

 

需要說明的是:C語言調用函數的時候虛實結合的方法都是採用“值傳遞”方式,當用變量名作爲函數參數的時候傳遞的是變量的值,當用數組名作爲函數參數的時候,由於數組名代表的是數組首元素地址,因此傳遞的值是地址,所以要求形參爲指針變量。

7、3、3指針做參數

歸納總結:

   如果有一個實參數組,想在函數中改變此數組中的元素的值,實參與形參的對應關係有以下4種情況:(注意:這裏要注意形參與實參數組與變量的區別)

  1. 形參和實參都用數組名
  2. 實參採用數組,形參使用指針變量
  3. 實參與形參都是指針變量
  4. 實參爲指針變量,形參爲數組名

7、4多維數組與指針

用指針變量可以指向一維數組中的元素,也可以指向多維數組中的元素。在概念和使用上,多維數組要複雜一些。

7、4、1多維數組元素的地址

五種方法來確定元素的地址:

int a[][]={};

a,*a,a[0],&a[0],&a[0][0]  這五個表示第一行第一個元素的地址

(說明:*a 的值爲數組,因此數組名爲第一個元素的地址)

(a+1),*(a+1),a[1],&a[1],&a[1][0] 這五個表示第二行第一個元素的地址

7、4、2指向多維數組元素的指針變量

把二維數組a分解爲一維數組a[0],a[1],a[2]之後,設P爲指向二維數組的指針變量。

可定義爲:int (*p)[4];

它表示p是一個指針變量,它指向包含4個元素的一維數組。若指向第一個一維數組a[0],其值等於a,a[0],或者&a[0][0]等。

 

從前面的分析可以得出*(p+i)+j是二維數組i行j列的元素的地址,而*(*(p+i)+j)則是i行j列元素的值。

 

二維數組指針變量說明的形式爲:

類型說明符(*指針變量名)[長度]

其中“類型說明符”爲所指的數組的數據類型。“*”表示其後的變量是指針類型。“長度”表示二維數組分解爲多個一維數組時,一維數組的長度,也就是二維數組的列數。

7、5字符串與指針

  1. 用字符數組存放一個字符串,然後輸出該字符串。

 例題1:定義一個字符數組,對它初始化,然後輸出該字符串

  1. 用字符指針指向一個字符串

7、5、1字符串中字符的存取方法

對字符串中字符的存取,可以使用下標的方法,也可以使用指針的方法。

7、5、2用字符指針作函數的參數

【存儲的說明】在C/C++中,內存分成5個區,他們分別是堆、棧、自由存儲區,全局、靜態存儲區和常量存儲區。

:就是那些由編譯器在需要的時候分配,再不需要的時候自動清除的變量的存儲區。裏面的變量通常是局部變量、函數參數等。

:就是那些由new分配的內存塊,他們的釋放編譯器不去管,由我們的應用程序去控制,一般一個new就要對應一個delete。如果程序員沒有釋放掉,那麼程序結束後,操作系統就會自動回收。

自由存儲區:就是那些由malloc等分配的內存塊,它和堆是十分相似的,不過它是用free來結束自己生命的。

全局/靜態存儲區:全局變量和靜態變量被分配到同一個內存中,在以前的C語言中,全局變量又分爲初始化與未初始化的,在C++裏面沒有這個區分了,他們共同佔用同一塊內存區。

常量存儲區:這是一塊比較特殊的存儲區,他們裏面存放的是常量,不允許修改(當然,你要是通過非正常手段也可以修改,而且方法很多)

關於a[] 與 *a的一些區別:

  雖然用字符數組和字符指針變量都能實現字符串的存儲和運算,但是他們二者之間是有區別的,不要混爲一談。

主要概括起來有以下幾點:

  1. 字符數組由若干個元素組成,每個元素中放一個字符,而字符指針變量中存放的是地址(字符串第一個字符的地址),決不是將字符串放到字符指針變量中。
  2. 賦值方法的不同。對於字符數組只能是對各個元素賦值

  char str[20] ; str = “I Love Fishc.com!”;是錯誤的

   char str[20]= “I Love Fishc.com!”;是正確的

   char *str; str = “I Love Fishc.com!”; 是正確的

char *str=“I Love Fishc.com!”;是正確的

而字符變量可以,但是注意存放的是字符串的首字符的地址

  1. 如果定義了一個字符數組,在編譯時爲他分配內存單元,它有確定的地址。而定義一個字符指針變量,給指針變量分配內存單元,在其中可以放一個字符變量的地址也就是說,該指針變量可以指向一個字符型數據,但是如果未對它賦予一個地址,則它並未具體指向一個確定的字符數據。
  2. 指針變量的值是可以改變的。
  3. 使用指針定義的數組可以通過下標的方式遍歷字符串

7、6用函數指針變量調用函數

一個函數在編譯的時候被分配給一個入口地址。這個函數的入口地址就稱爲函數的指針。

1)函數指針變量常用的用途之一是把指針作爲參數傳遞到其他的函數。

2)函數的參數可以是變量、指向變量的指針變量、數組名、指向數組的指針變量等。

3)現在介紹指向函數的指針也可以作爲參數,以實現函數地址的傳遞,這樣就能夠在被調用的函數中使用實參函數。

 

7、7返回指針值的函數

這種帶回指針值的函數,一般定義形式爲:

例如:

int *a(int x,int y);

指針函數與函數指針的區別:

指針函數是指帶指針的函數。

函數指針是指向函數的變量。

指針數組和指向指針的指針

指針數組的概念:

    一個數組,若其元素均爲指針類型的數據,稱爲指針數組。

怎樣定義一個指向指針的指針?

  字符類型  **p;

P的前面有兩個*號。*號運算符的結合性是從右到左,因此**p相當於*(*p),顯然*p是指針變量的定義形式。如果沒有最前面的*,那就是定義了一個指向字符數據的指針變量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章