(三)學習筆記 c語言基礎 指針

1.定義指針變量

數據在內存中的地址也稱爲指針,如果一個變量存儲了一份數據的指針,我們就稱它爲指針變量。

int a = 1;
int *p = &a;

通過指針變量p獲取數據:

printf("%d", *P);

星號*主要有三種用途:

1)表示乘法,例如int a = 1, b = 2, c;  c = a * b;,這是最容易理解的
2)表示定義一個指針變量,以和普通變量區分開,例如int a = 100;  int *p = &a;
3)表示獲取指針指向的數據,是一種間接操作,例如*p = 100;  b = *p;

2.指向數組的指針

Array是一系列具有相同類型的數據的集合,每一份數據叫Element(數組元素)。數組中的所有元素在內存中是連續排列的。
如:

int arr[] = {1,2,3,4,5,6};

定義數組時,要給出數組名和數組長度,數組名可以認爲時一個指針,它指向數組的第0個元素。

*(arr + 1) 獲取的數據和arr[1]等價

arr本身是一個指針,可以直接賦值給指針變量p:

int *p = arr;

指針疑惑

*p++ 等價於*(p++),表示先取得第n個元素的值,再將p指向下一個元素
*++P 等價於*(++p),會先進行++p運算,使得p的值增加,指向下一個元素,整體上相當於*(p+1)
(*p)++ 等價於對指針變量p獲取的數值做加1操作。
3.字符串指針(指向字符串的指針)

c語言沒有特定的字符串類型,我們通常時將字符串放在一個字符數組中。

int main()
{
    char str[] = "Say Hello!";
    int len = strlen(str);
    printf("%s\n", str);

    for(int i = 0; i < len; i++){
        printf("%c", str[i]);
    }
}

指針和數組的規則同樣也適用於字符數組:

int main()
{
    char *str = "Say Hello!";
    int len = strllen(str);
    printf("%s\n", str);
   
    for(int i = 0; i < len; i++){
        printf("%c", str[i]);
        //使用*(str + i)
        printf("%c", *(str + i));
    }
}

C語言有兩種表示字符串的方法,
1)是字符數組:字符數組存儲在全局數據區或棧區,使得字符數組可以讀取和修改

char str[] = "Say Hello!";
str = "you you!";        //正確
str[1] = 'A'            //正確

2)是字符串常量:字符串存儲在常量區,只能讀取不能修改

char *str = "Say Hello!";
str = "you you!";       //正確,可以更改指針變量本身的指向。
str[1] = 'A';           //錯誤,不能對常量進行寫入。
*(str + 1) = 'A';       //錯誤,不能對常量進行寫入。

4.指針變量作爲函數參數

#include <stdio.h>
void swap(int *p1, int *p2){
    int temp;  //臨時變量
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
int main(){
    int a = 1, b = 2;
    swap(&a, &b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

5.指針作爲函數返回值

C語言允許函數的返回值是一個指針(地址),我們將這樣的函數稱爲指針函數。

int *max(int *a, int *b)
{
    if (*a > *b) {
        return a;
    }
    else{
        return b;
    }
}

int main()
{
    int a = 10;
    int b = 20;
    int *c = max(&a, &b);
    printf("max num is %d\n", *c);
}

6.二級指針(指向指針的指針)

指針變量也是一種變量,也會佔用存儲空間,也可以使用&獲取它的地址。C語言不限制指針的級數,每增加一級指針,在定義指針變量時就得增加一個星號*。p1 是一級指針,指向普通類型的數據,定義時有一個*;p2 是二級指針,指向一級指針 p1,定義時有兩個*。
int main()
{
    int a = 1;
    int *p1 = &a;
    int **p2 = &p1;
    printf("%d, %d, %d", a, *p1, **p2);
}

解析:*p2指向的是指針變量p1的值,**p2是指針變量p1的獲取數據的值(*p1)

7.指針數組

如果一個數組中的所有元素保存的都是指針,那麼我們就稱它爲指針數組。

int main()
{
    //整形指針數組
    int a = 1, b = 2, c = 3;
    //定義一個指針數組
    int *arr[3] = {&a, &b, &c}; //可以不指定長度
    //定義一個指向指針數組的指針
    int **parr = arr;
    printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
    printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2));
    
    //字符串數組和指針數組
    char *str[3] = {
        "hello one!",
        "hello two!",
        "hello three!"
    }
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    
    //字符串指針數組
    char *str0 = "hello one!";
    char *str1 = "hello two!";
    char *str2 = "hello three!";
    char *str[3] = {str0, str1, str2};
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    
    return 0;
}

8.二維數組指針

int main()
{
    int a[2][2] = {{1,2}, {3,4}};
    //定義一個指向a的指針變量p;
    int (*p)[2] = a;    //括號中*表明p是一個指針,它指向一個數組。[]的優先級高於*,所以()是必須要加的。如果寫成*p[2]就成指針數組了。
    printf("%zu\n", sizeof(*(p+1)));
    
    int i,j;
    for(i=0; i<2; i++){
        for(j=0; j<2; j++) 
        printf("%2d  ",*(*(p+i)+j));
        //printf("%2d  ", (*(p + i))[j]);
        printf("\n");
    }
    return 0;
}

9.函數指針

一個函數總是佔用一段連續的內存區域,函數名在表達式中有時也會被轉換爲該函數所在內存區域的首地址,這和數組名非常類似。我們可以把函數的這個首地址(或稱入口地址)賦予一個指針變量,使指針變量指向函數所在的內存區域,然後通過指針變量就可以找到並調用該函數。這種指針就是函數指針。

#include <stdio.h>
//返回兩個數中較大的一個
int max(int a, int b){
    return a>b ? a : b;
}

int main(){
    int a = 1, b = 2;
    //定義函數指針
    int (*pmax)(int a, int b) = max;
    int maxFunc = (*pmax)(a, b);
    
    printf("maxFunc: %d\n", maxFunc);
    return 0;
}

pmax 是一個函數指針,在前面加 * 就表示對它指向的函數進行調用

注意:使用指針變量之前一定要初始化,否則就不能確定指針指向哪裏(野指針),如果它指向的內存沒有使用權限,程序就崩潰了。對於暫時沒有指向的指針,建議賦值NULL。

下一篇:(四)學習筆記 c語言基礎 結構體
上一篇:(二)學習筆記 c語言基礎 數據類型

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