C語言入門第十六篇,再議指針

前面我們介紹了指針的基本性質,今天我們再深入的研究指針的內容。
我們之前瞭解了指針就是指向變量,那些只是皮毛,想要真正掌握指針就看下面的內容理解的怎麼樣了。
指針和數組
之前介紹了指針可以通過自己地址的加和減去訪問其他地址裏面的變量內容,其中一種場景就是指針指向了數組(指針並不能隨意的去訪問內存地址中的內容,這設計到了操作系統的知識,這裏不再贅述),下面我們來看看實際的例子:

#include<stdio.h>
int main()
{
    int a[5]={1,2,3,4,5};
    int i;
    int *p;
    p=a;
    for(i=0;i<5;i++){
        printf("%d\n",*p);
        p++;
    }
    return 0;
} 

上面的代碼可以看出,指針指向數組的情況,指針會指向數組的頭部,如下圖所示
指針指向數組
上圖應該很清楚的表達了這個程序的過程,指針p指向了數組頭部,通過循環將指針自家,指針不斷的指向下一個元素,並輸出。
這時你也可以通過下標引用的方式,來訪問指針所指向的元素。上面的循環也可以寫成下面的樣子。

for(i=0;i<5;i++){
        printf("%d\n",p[i]);
    }

這時指針就類似數組,但是這樣用也有點危險,因爲如果指針越界的話,會帶來未知的錯誤,所以在用指針的時候,一定要在自己的可控範圍內。

指針和函數
個人理解的指針和函數分爲兩種,函數指針和指針函數。
函數指針
函數指針的意思是指向函數的指針,這個在實際的應用中最常見的就是回調函數和轉換表。
我們先來講講回調函數。有時候我們在編寫程序的時候需要傳入是一個函數作爲參數。具體我以例子來說明:

#include<stdio.h>
int main()
{
    int max(int ,int );
    int min(int ,int );
    int sum(int ,int );
    int process(int ,int ,int(*fun)(int ,int ) );
    int a,b;
    printf("please enter two number:");
    scanf("%d%d",&a,&b);
    printf("max is ");
    process(a,b,max);
    printf("min is ");
    process(a,b,min);
    printf("sum is ");
    process(a,b,sum);
}
int max(int x,int y)
{
    int z;
    if(x<y)
    {
        z=y;
    }
    else
    {
        z=x;    
    }
    return z;
}
int min(int x,int y)
{
    int z;
    if(x<y)
    {
        z=x;
    }
    else
    {
        z=y;
    }
    return z; 
}
int sum(int x,int y)
{
    int z;
    z=x+y;
    return z;
}
int process(int x,int y,int (*fun)(int x,int y))
{
    int z;
    z=(*fun)(x,y);
    printf("%d\n",z);   
}

大家運行一下這個程序,其實很容易明白,我們通過傳入不同的函數的指針,讓process函數實現求最大值,最小值,求和這些操作,爲什麼叫做回調函數呢?因爲process去回調了,我自己寫的max,min,sum函數。這裏需要注意,傳入process的時候直接寫的就是函數名,因爲函數名就代表該函數的開頭指針。
指針函數
指針函數的概念相對於函數指針來說要簡單一些,指針函數表示函數返回一個指針,寫法如下:

int *f(int);

這個函數返回一個指向整形變量的指針。下面我們來看看具體例子:

#include<stdio.h>
int main()
{
    int a[][4]={{40,50,60,70},{41,50,60,70},{42,50,60,70},{43,50,60,70}};
    int *search(int (*p)[4],int m);
    int *q;
    int b,i;
    printf("please enter number you want search:");
    scanf("%d",&b);
    q=search(a,b);
    for(i=0;i<4;i++)
    {
        printf("%d\t",*(q+i));
    }
    return 0;
} 
int *search(int (*p)[4],int m)
{
    int *temp;
    temp=*(p+m);
    return temp;
}

我們來看看這個例子,這個例子其實很簡單。這個程序輸出二維數組中用戶輸入的值所在那一行的所有數。

  1. 首先程序定義了一個二維數組,聲明一個指針函數傳入二維數組和一個用戶輸入的值,定義一些變量
  2. 然後用戶輸入值,指針q接受指針函數返回的指針值
  3. 接着輸出指針q所指向的那一行。
  4. 最後我們看看這個指針函數的定義,首先明白這個函數只是返回一個指向整形變量指針的函數。
  5. 函數用temp接受了p+m的地址值,然後返回了temp;
    看起其實很簡單,這裏面還是有一些小細節,可能很多人不懂,例如int (*p)[4]這個剛剛我說了是二維數組,要結合我們剛剛講的來看這個式子,我說過指針和數組在一定情況下可以互換,所以這裏把二維數組行方向的數組換成了指針。原理和上面差不多,相當於我的指針指向了行,如下圖:
    指針指向二維數組
    當p指針自加的時候,就會指向下一行。多多運行上一個程序就好。
    指針和數組的區別
    我們本章從指針和數組開始,講到這裏我們還是要講講他們的區別。有人看到剛剛的例子就會問,二維數組是不是可以用指針的指針來表示?如果你能提出這樣的問題,那證明你已經很厲害了,對c語言有自己的見解。回答這個問題我們先來看看指針和數組的區別。
    1.數組在創建的時候就已經分配好了內存。
    這一點很重要,爲了我們後續更好的使用數組和指針必須理解這一點。我們必須明白,int a[10];這時候編譯器申請了10個整型字節的內存大小的空間(至於1個整數是多少個字節,請看前面的基礎數據類型)。數組是連續的一片存儲
    然而在指針的聲明的時候,他僅僅簡簡單單的是一個指向整型變量的一個地址
    2.指針如果無法存取,則需要申請空間。
    請看下面的代碼
#include<stdio.h>

int main()
{
    int *q;
    *q=9;
    printf("%d\n",*q);
    return 0;
} 

這樣操作是錯誤的,編譯器在運行的時候會報錯,然後下面的這種方法就可以通過編譯。

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int *q;
    q=(int *)malloc(sizeof(int));
    *q=9;
    printf("%d\n",*q);
    return 0;
} 

這裏我們使用了後面會使用很多的,malloc申請內存。其實你不要覺得他有多高級,只是簡單的把那一行看成申請內存就好了。然後因爲沒有,所以要申請,就這麼簡單。
有了申請內存我們就可以用指針的指針來表示二維數組了(當然還有其他不用申請內存的方法,用指針的指針表示二維數組就留給大家來實現啦)。其實二維數組本身就可以看成一個指針的指針。可以看看下面的代碼

#include<stdio.h>

int main()
{
    int a[][4]={{40,50,60,70},{41,50,60,70},{42,50,60,70},{43,50,60,70}};
    int i,j;
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d ",*(*(a+i)+j));
        }
        printf("\n");
    }
} 

這裏舉這麼多例子就是爲了讓大家明白數組和指針的轉化。如果不是很清楚就先多看看例子,然後去練習寫一下。
指針和函數參數
指針在作爲函數的參數的時候依然是傳值(C語言都是傳值並非傳址),所以可以先看看這篇文章C語言利用指針在函數中交換兩個數的思考
通過上面那篇文章我可以瞭解如果傳入指針的話,需要間接訪問才能去修改變量的值,所以指針作爲函數參數的時候一定要注意,不然你會發現你傳入函數的值沒有變。
總結
本篇內容有點雜,甚至我寫到後面都不知道該怎麼寫了,然後又重新整理思路。這篇相當於給大家講一些比入門要深一點的東西,相信大家一定會用到,如果現在看的有點暈的話,可以後面再來看這章。我儘量讓每一篇都相對獨立一些,這樣什麼不懂就可以再回頭看什麼。
本篇主要圍繞指針和數組,指針和函數結合的情況,討論了大家可能會遇到的情況。
1.指針和數組主要是指針和數組之間的互換,以及互相之間的應用。
2指針和函數,主要是指針函數和函數指針,以及指針作爲函數參數的時候的一些情況。

練習
1.試着用指針的指針表示一個二維數組。
2.編寫一個回調函數,這個回調函數可以實現兩個數加減乘除。

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