程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言-指針,c語言指針

C語言-指針,c語言指針

編輯:關於C語言

C語言-指針,c語言指針


無指針,不自由

----------------------------

--1-- 為什麼要使用指針1.1 指針的基本概念1.2 使用指針的好處1.3 變量的存儲方式--2-- 指針變量2.1 指針變量2.2 定義一個指針變量2.3 指針變量的初始化方法2.4 使用*獲取指針對應存儲區域的內容--3-- 存儲細節3.1 變量及指針變量--4-- 常見的應用場景4.1 指針常見的應用場景--5-- 多級指針介紹5.1 二級指針5.2 多級指針介紹

----------------------------

 

【寫在開頭:】

『生活中的指針:

沒錯,就是一個門牌號。

指針是C語言中最重要的內容之一。

為什麼要使用指針?

如果你想要查找一篇資料,給你一本厚重的百科全書,而你只需要其中第3001頁的內容。

那麼,3001頁,就是指針。如果沒有這個指針...好吧,我去旁邊哭會兒...

 

 

--1-- 為什麼要使用指針

1.1 指針的基本概念

內存單元的編號也叫做地址,根據內存單元的編號或地址就就可以找到所需的內存單元。

所以通常也把這個地址稱為指針

 

1.2 使用指針的好處

1)為函數提供修改調用變量的靈活手段

2)讓函數有多個返回值

3)可以改善程序的效率

  在數據傳遞時,如果數據塊較大(比如數據緩沖區或比較大的結構),這時就可以使用指針傳遞地址而不是實際數據,既提高傳輸速度,又節省了大量的內存

4)為動態數據結構(如二叉數,鏈表等)提供支持

 

1.3 變量的存儲方式

變量存取的方式有兩種:直接存取和間接存取

1)直接存取:變量的賦值和取值

2)間接存取:通過指針(地址)間接操作完成

指針最大的作用之一就是通過地址來操作(存取)變量、數組等

 

--2-- 指針變量

 2.1 指針變量

在C語言中,允許用一個變量來存放指針,這個變量稱為指針變量。

指針變量存放的是一個地址,是一個變量

 

2.2 定義一個指針變量

指針變量的定義包括三個內容:

1)指針類型說明,即定義變量為一個指針變量

2)指針變量名

3)變量值(地址)


一般形式:

類型說明符   *變量名 = 地址;

        int *p;  //定義了一個指針變量,變量名是p int表示p指向的是一個int類型的變量空間
        char *p1;   //變量名是p1 char表示p1指向的是一個char類型的變量空間

 

其中

類型說明符表示本指針變量所指向的變量的數據類型

*表示這是一個指針變量

變量名即為定義的指針變量名

 

注意:

1)在定義指針時,*表示定義的變量是一個指針變量(如果沒有*就和普通變量沒有區別了)

2)指針變量能用來存放數組或字符之類?-->不能(存儲的是地址)

3)一個類型的指針只能指向同類型的變量,不能指向其他類型的變量

4)指針變量,歸根結底還是一個變量,也有全局和局部之分

 

2.3 指針變量的初始化方法

指針變量應該用地址初始化

兩種初始化的方式:

定義的同時初始化、先定義後初始化

1)定義的同時初始化

    //完全初始化
    int a = 3;
    int b = 4;
    int *P = &a; //用a的地址初始化p這個指針變量(也稱為p指向了a))
    int *p1 = &a, *p2 = &a;  //p1,p2都指向了a

 

 

2)先定義後初始化

    //部分初始化
    int *p3 = &b, *p4; //定義了兩個指針變量 p3和p4 p4未初始化
    p4 = &b;

 

2.4 使用*獲取指針對應存儲區域的內容

指針變量同普通變量一樣,使用之前不僅要定義說明,而且必須賦予其具體的值。

未經賦值的指針變量不能使用,否則將造成系統混亂,甚至死機(野指針)。指針變量的賦值只能賦予地址,不能賦予任何其他的數據,否則將引起錯誤。

在C語言中,變量的地址是由編譯系統分配的,對用戶完全透明,用戶事先並不知道變量的具體地址(但可以知道區域位置)。

 

兩個相關的運算符:

  &:取地址運算符;

  *:指針運算符(或稱“間接訪問”運算符);

C語言提供了地址運算符"&"來表示變量的地址,一般形式為:&變量名;

獲取指針變量指向的存儲空間的內容:*指針變量名

*運算符和&運算符恰好相反。&運算符接收一個數據,然後告訴你這個數據保存在哪裡;*運算符接收一個地址,然後告訴你這個地址中保存的是什麼數據。

因為指針有時也叫引用,所以*運算符也可以描述成對指針進行解引用。

        int a = 3;
        int b = 4;
        int *p1 = &a;
        int *p2 = &b;
        
        //*指針變量  作用:獲取指針變量指向的內存空間的內容(值)再賦值給value
        int value = *p1;  //3
        *p1 = 100;   //改變空間的值
        value = *p2;  //4
        printf("*p1 = %d\n", *p1); //100
        printf("value = %d\n",value );   //4

 

 

思考

定義如下指針

        float *pointer_3;
        char *pointer_4;
        int a,b;
        int *pointer_1 = &a, *pointer_2;

 

判斷下面的操作是否合法

        *pointer_1 = &a;
        pointer_3 = 2000;
        pointer_3 = &a;
        pointer_1 = &a;
        pointer_2 = pointer_4;

 

分析:

        *pointer_1 = &a;  //錯; *pointer_1是一個解引用,是一個值,而非地址
        pointer_3 = 2000;  //錯;pointer_3指針並未初始化,且需賦值的是一個地址
        pointer_3 = &a;  //錯; 應該賦值一個float類型的空間地址給pointer_3
        pointer_1 = &a;  //合法
        pointer_2 = pointer_4;   //錯; 類型不同

 

 

--3-- 存儲細節

3.1 變量及指針變量存儲細節

每當聲明一個變量,計算機都會在存儲器中某個地方為它創建空間。如果在函數(例如main()函數)中聲明變量,計算機會把它保存在一個叫棧(Stack)的存儲器區段中;如果你在函數以外的地方聲明變量,計算機則會把它保存在存儲器的全局量段(Globals)。

int y = 1; //位於全局量段 地址:1000 000
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        int x = 4; //位於棧區 地址:4100 000
    }
    return 0;
}

 

 

如有如下變量

int i = 200;

int *p = &i;

此時p指向了變量i的首地址&i

 

 

--4-- 常見的應用場景

4.1 指針常見的應用場景

這樣的一種場景很常見,參數在函數間進行傳遞時,要通過被調函數改變主調函數中實參變量的值

如:交換兩個變量的函數,如果不使用指針,則一般用的是臨時變量等方法

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        int x = 3, y = 4, temp;
        //臨時變量交換兩個變量的值
        temp = x;
        x = y;
        y = temp;
        printf("x = %d, y = %d\n", x, y);
    }
    return 0;
}

 

 

可是上面這樣的寫法是不好的,需要將其封裝(原諒我這裡的說法不准確,“封裝”是面向對象語言的特點)成自定義方法才好。

那麼如果封裝(習慣這樣叫了...)成自定義方法之後,如果實參傳遞的是一個變量,那麼主調函數中變量的值不會改變,因為形參實際上是又開辟了一個新的內存空間,在自定義函數中並不能修改實參的值:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        void swap(int x, int y); //函數聲明
        
        int x = 3, y = 4;
        swap(x, y); //變量作為實參並不能修改實參空間中的值
        printf("x = %d, y = %d\n", x, y); //未改變 x = 3, y = 4
    }
    return 0;
}

/**
 *  測試方法,交換變量的值
 *
 *  @param x 變量1
 *  @param y 變量2
 */
void swap(int x, int y){
    //臨時變量交換兩個變量的值
    int temp = x;
    x = y;
    y = temp;
}

 

所以要實現上面設定情景,就只能使用指針地址傳遞:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        void swap(int *x, int *y); //函數聲明
        
        int x = 3, y = 4;
        swap(&x, &y); //將地址作為形參就可以交換此處x和y的值
        printf("x = %d, y = %d\n", x, y); //x = 4, y = 3
    }
    return 0;
}

/**
 *  交換兩個變量的值
 *
 *  @param x 地址1
 *  @param y 地址2
 */
void swap(int *x, int *y){
    //臨時變量交換兩個變量的值
    int temp = *x;
    *x = *y;
    *y = temp;
}

 

 

--5-- 多級指針介紹

5.1 二級指針

如果一個指針變量存放的又是另一個指針變量的地址,則稱這個指針變量為指向指針的指針變量,也稱為“二級指針”

通過指針訪問變量稱為間接訪問,由於指針變量直接指向變量,所以稱為“一級指針”。而如果通過指向指針的指針變量來訪問變量則構成了“二級指針”

        int a = 5;
        int *p = &a;
        printf("%p\n",&a); //a的地址
        printf("%p\n",p); //指針p中存儲的是a的地址
        printf("-----\n");
        //****二級指針
        int **p1 = &p; //p1中存儲的是一個指針
        printf("p = %p\n", &p); //指針p的地址
        printf("p1 --> %p\n", p1); //p1中存儲的地址
        printf("----------------------\n");
        printf("*p = %d\n", *p); //指針p指向的地址中存儲的值
        printf("*p1 = %p\n", *p1); //p1指向的地址中存儲的指針地址
        printf("**p1 = %d\n", **p1); //p1中存儲的指針解引用

 

 5.2 多級指針介紹

同理,定義的時候有多少個*,一般也就稱為多少級的指針

 

 

【寫在結尾:】

『每個人小的時候,都應該會有一個夢想,或者,就稱為夢吧』

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved