C語(yǔ)言指針概念的理解

前言

最近真的是忙的不可開交,公司一直給安排任務(wù)推汽,連學(xué)習(xí)和寫筆記的時(shí)間都沒有了补疑,落下好幾次課的筆記都沒有寫,所以我抽空把目前的進(jìn)度給追上來歹撒,不然會(huì)越落越多莲组。加油吧~(感覺身體都要被掏空了)

指針##

我們通過指針,可以簡(jiǎn)化一些 C 編程任務(wù)的執(zhí)行暖夭,還有一些任務(wù)锹杈,如動(dòng)態(tài)內(nèi)存分配,沒有指針是無法執(zhí)行的迈着。所以竭望,學(xué)習(xí)指針是很有必要的。
正如您所知道的裕菠,每一個(gè)變量都有一個(gè)內(nèi)存位置咬清,每一個(gè)內(nèi)存位置都定義了可使用連字號(hào)(&)運(yùn)算符訪問的地址,它表示了在內(nèi)存中的一個(gè)地址奴潘。請(qǐng)看下面的實(shí)例旧烧,它將輸出定義的變量地址:

#include <stdio.h>

int main ()
{
   int  var1;
   char var2[10];

   printf("var1 變量的地址: %x\n", &var1  );
   printf("var2 變量的地址: %x\n", &var2  );

   return 0;
}

當(dāng)上面的代碼被編譯和執(zhí)行時(shí),它會(huì)產(chǎn)生下列結(jié)果:

var1 變量的地址: bff5a400
var2 變量的地址: bff5a3f6

通過上面的栗子画髓,我們了解了什么是內(nèi)存地址以及如何訪問它掘剪。接下來讓我們看看什么是指針吧!

什么是指針奈虾?

指針是一個(gè)變量夺谁,其值為另一個(gè)變量的地址廉赔,即內(nèi)存位置的直接地址。就像其他變量或常量一樣匾鸥,您必須在使用指針存儲(chǔ)其他變量地址之前蜡塌,對(duì)其進(jìn)行聲明。指針變量聲明的一般形式為:

type *name;

這里的type 是指針的基類型扫腺,它必須是一個(gè)有效的 C 數(shù)據(jù)類型岗照,name 是指針變量的名稱村象。用來聲明指針的星號(hào) * 與乘法中使用的星號(hào)是相同的笆环。但是,在這個(gè)語(yǔ)句中厚者,星號(hào)是用來指定一個(gè)變量是指針。以下是有效的指針聲明:

int    *ip;    /* 一個(gè)整型的指針 */
double *dp;    /* 一個(gè) double 型的指針 */
float  *fp;    /* 一個(gè)浮點(diǎn)型的指針 */
char   *ch     /* 一個(gè)字符型的指針 */

所有指針的值的實(shí)際數(shù)據(jù)類型库菲,不管是整型账忘、浮點(diǎn)型熙宇、字符型鳖擒,還是其他的數(shù)據(jù)類型期升,都是一樣的,都是一個(gè)代表內(nèi)存地址的長(zhǎng)的十六進(jìn)制數(shù)。不同數(shù)據(jù)類型的指針之間唯一的不同是房维,指針?biāo)赶虻淖兞炕虺A康臄?shù)據(jù)類型不同坛猪。

如何使用指針洋机?

  • 使用指針時(shí)會(huì)頻繁進(jìn)行以下幾個(gè)操作:定義一個(gè)指針變量谨垃、把變量地址賦值給指針、訪問指針變量中可用地址的值匙隔。這些是通過使用一元運(yùn)算符 * 來返回位于操作數(shù)所指定地址的變量的值。下面的實(shí)例涉及到了這些操作:
#include <stdio.h>
//指針
//指針存儲(chǔ)的是變量的內(nèi)存地址
//內(nèi)存地址纷责,系統(tǒng)給數(shù)據(jù)分配的編號(hào)(門牌號(hào))

void main(){
    int i = 90;
    //指針變量捍掺,創(chuàng)建一個(gè)int類型的指針
    int* p = &i; //p的值就是i這個(gè)變量的內(nèi)存地址
    printf("%#x\n",p);

    float f = 89.5f;
    //創(chuàng)建一個(gè)float類型的指針
    float *fp = &f;
    printf("%#x\n", fp);

    system("pause");
}

上面的代碼被編譯和執(zhí)行時(shí),運(yùn)行的結(jié)果:

0xeffb30
0xeffb18
請(qǐng)按任意鍵繼續(xù). . .
  • 對(duì)指針存的地址指向的變量進(jìn)行操作
#include <stdio.h>

void change(int* p){
    *p = 300;
}

//變量名再膳,對(duì)內(nèi)存空間上的一段數(shù)據(jù)的抽象
void main(){
    int i = 90;
    //i = 89;
    //創(chuàng)建一個(gè)int類型的指針
    int *p = &i;
    //輸出地址
    printf("p的地址:%#x\n",&p);
    printf("i的地址:%#x\n",&i);
    printf("i的值為:%d\n", i);
    //間接賦值 i = 200;

    //對(duì)p存的地址指向的變量進(jìn)行操作
    //*p = 200;
    //change(p);
    change(&i);  // int *p = &i;
    printf("i的值為:%d\n",i);

    system("pause");
}

上面代碼編譯執(zhí)行結(jié)果如下:

p的地址:0x6ffdb0
i的地址:0x6ffdbc
i的值為:90
i的值為:300
請(qǐng)按任意鍵繼續(xù). . .

通過上面栗子挺勿,我們可以看出,指針?biāo)赶虻淖兞恐狄呀?jīng)被更改了喂柒。

C中的NULL 指針

在變量聲明的時(shí)候不瓶,如果沒有確切的地址可以賦值禾嫉,為指針變量賦一個(gè) NULL 值是一個(gè)良好的編程習(xí)慣。賦為 NULL 值的指針被稱為空指針蚊丐。
NULL 指針是一個(gè)定義在標(biāo)準(zhǔn)庫(kù)中的值為零的常量熙参。請(qǐng)看下面的程序:

#include <stdio.h>

int main ()
{
   int  *ptr = NULL;

   printf("ptr 的值是 %x\n", ptr  );
 
   return 0;
}

運(yùn)行結(jié)果為:

ptr 的值是 0

在大多數(shù)的操作系統(tǒng)上,程序不允許訪問地址為 0 的內(nèi)存麦备,因?yàn)樵搩?nèi)存是操作系統(tǒng)保留的孽椰。然而,內(nèi)存地址 0 有特別重要的意義凛篙,它表明該指針不指向一個(gè)可訪問的內(nèi)存位置黍匾。但按照慣例,如果指針包含空值(零值)鞋诗,則假定它不指向任何東西膀捷。
如需檢查一個(gè)空指針迈嘹,您可以使用 if 語(yǔ)句削彬,如下所示:

#include <stdio.h>

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

  char *s = "hello";

  if (!s) {
    fprintf(stderr, "s is null\n");
  } else {
    fprintf(stderr, "%s\n", s);
  }

  if (s == NULL) {
    fprintf(stderr, "s is null\n");
  } else {
    fprintf(stderr, "%s\n", s);
  }


  return 0;
}

這兩種方法都能判斷字符指針是否為空,但推薦使用前者秀仲。"NULL" 的本質(zhì)是個(gè)宏融痛,并非是個(gè)常量,C99 中甚至可以自行定義神僵,故盡量避免使用它去判斷雁刷,當(dāng) !s 與 s == NULL 表示同一含義的時(shí)候,使用前者吧保礼!

C中的二級(jí)指針(多級(jí)指針)

指針可以指向一份普通類型的數(shù)據(jù)沛励,例如 int、double炮障、char 等目派,也可以指向一份指針類型的數(shù)據(jù),例如 int *胁赢、double *企蹭、char * 等。

如果一個(gè)指針指向的是另外一個(gè)指針智末,我們就稱它為二級(jí)指針谅摄,或者指向指針的指針。
假設(shè)有一個(gè) int 類型的變量 a系馆,p1是指向 a 的指針變量送漠,p2 又是指向 p1 的指針變量,它們的關(guān)系如下圖所示:

這里寫圖片描述

用代碼表示為:

int a =100;
int *p1 = &a;
int **p2 = &p1;

指針變量也是一種變量由蘑,也會(huì)占用存儲(chǔ)空間闽寡,也可以使用&獲取它的地址棒厘。C語(yǔ)言不限制指針的級(jí)數(shù),每增加一級(jí)指針下隧,在定義指針變量時(shí)就得增加一個(gè)星號(hào) * 奢人。p1 是一級(jí)指針,指向普通類型的數(shù)據(jù)淆院,定義時(shí)有一個(gè) * 何乎;p2 是二級(jí)指針,指向一級(jí)指針 p1土辩,定義時(shí)有兩個(gè)*支救。

如果再定義一個(gè)三級(jí)指針 p3,讓它指向 p2拷淘,那么可以這樣寫:

int ***p3 = &p2;

四級(jí)指針:

int ****p4 = &p3;

等等各墨,以此類推。启涯。贬堵。
不過,經(jīng)常使用的也就是一級(jí)指針和二級(jí)指針了结洼。
在獲取指針指向的數(shù)據(jù)時(shí)黎做,一級(jí)指針加一個(gè) * ,二級(jí)指針加兩個(gè) * 松忍,三級(jí)指針加三個(gè) *蒸殿,以此類推,請(qǐng)看代碼:

#include <stdio.h>
int main(){
    int a =100;
    int *p1 = &a;
    int **p2 = &p1;
    int ***p3 = &p2;
    printf("%d, %d, %d, %d\n", a, *p1, **p2, ***p3);
    printf("&p2 = %#X, p3 = %#X\n", &p2, p3);
    printf("&p1 = %#X, p2 = %#X, *p3 = %#X\n", &p1, p2, *p3);
    printf(" &a = %#X, p1 = %#X, *p2 = %#X, **p3 = %#X\n", &a, p1, *p2, **p3);
    return 0;
}

編譯并運(yùn)行結(jié)果如下:


這里寫圖片描述

以三級(jí)指針 p3 為例來分析上面的代碼鸣峭。*** p3等價(jià)于 * ( * (* p3))宏所。* p3 得到的是 p2 的值,也即 p1 的地址摊溶;* ( * p3) 得到的是 p1 的值爬骤,也即 a 的地址;經(jīng)過三次“取值”操作后更扁,* ( *(p3)) 得到的才是 a 的值盖腕。

假設(shè) a、p1浓镜、p2溃列、p3 的地址分別是 0X00A0、0X1000膛薛、0X2000听隐、0X3000,它們之間的關(guān)系可以用下圖來描述:

這里寫圖片描述

方框里面是變量本身的值哄啄,方框下面是變量的地址雅任。

C中指針的運(yùn)算

指針變量保存的是地址风范,本質(zhì)上是一個(gè)整數(shù),可以進(jìn)行部分運(yùn)算沪么,例如加法硼婿、減法、比較等禽车,請(qǐng)看下面的代碼:


#include <stdio.h>
//指針的運(yùn)算寇漫,一般在數(shù)組遍歷時(shí)才有意義,基于數(shù)組在內(nèi)存中線性排列的方式
void main(){
    //數(shù)組在內(nèi)存中連續(xù)存儲(chǔ)
    int ids[] = { 78, 90, 23, 65, 19 };
    //數(shù)組變量名:ids就是數(shù)組的首地址
    printf("%#x\n",ids);
    printf("%#x\n",&ids);
    printf("%#x\n",&ids[0]);
    //指針變量
    int *p = ids;
    printf("%d\n",*p);
    //指針的加法
    p++; //p++向前移動(dòng)sizeof(數(shù)據(jù)類型)個(gè)字節(jié)
    printf("p的值:%#x\n", p);
    //p--;
    printf("%d\n", *p);
    getchar();
}

編譯并運(yùn)行的結(jié)果如下:

0x5ff7d0
0x5ff7d0
0x5ff7d0
78
p的值:0x5ff7d4
90

從上面的栗子來看殉摔,數(shù)組變量名:ids就是數(shù)組的首地址州胳,指針的加法,p++就是向前移動(dòng)了sizeof(數(shù)據(jù)類型)個(gè)字節(jié)逸月。
我們知道栓撞,數(shù)組中的所有元素在內(nèi)存中是連續(xù)排列的,如果一個(gè)指針指向了數(shù)組中的某個(gè)元素碗硬,那么加 1 就表示指向下一個(gè)元素瓤湘,減 1 就表示指向上一個(gè)元素,不過C語(yǔ)言并沒有規(guī)定變量的存儲(chǔ)方式肛响,如果連續(xù)定義多個(gè)變量岭粤,它們有可能是挨著的,也有可能是分散的特笋,這取決于變量的類型、編譯器的實(shí)現(xiàn)以及具體的編譯模式巾兆,所以對(duì)于指向普通變量的指針猎物,我們往往不進(jìn)行加減運(yùn)算,雖然編譯器并不會(huì)報(bào)錯(cuò)角塑,但這樣做沒有意義蔫磨,因?yàn)椴恢浪竺嬷赶虻氖鞘裁磾?shù)據(jù)。

下面舉一個(gè)栗子圃伶,通過指針獲取下一個(gè)變量的地址:

#include <stdio.h>
int main(){
    int a = 1, b = 2, c = 3;
    int *p = &c;
    int i;
    for(i=0; i<8; i++){
        printf("%d, ", *(p+i) );
    }
    return 0;
}

編譯并運(yùn)行結(jié)果如下:

3, -858993460, -858993460, 2, -858993460, -858993460, 1, -858993460,

可以看出變量 a堤如、b、c 并不挨著窒朋,它們中間還有其他的數(shù)據(jù)搀罢。

指針變量除了可以參與加減運(yùn)算,還可以參與比較運(yùn)算侥猩。當(dāng)對(duì)指針變量進(jìn)行比較運(yùn)算時(shí)榔至,比較的是指針變量本身的值,也就是數(shù)據(jù)的地址欺劳。如果地址相等唧取,那么兩個(gè)指針就指向同一份數(shù)據(jù)铅鲤,否則就指向不同的數(shù)據(jù)。
所以總結(jié)出枫弟,不要對(duì)指向普通變量的指針進(jìn)行加減運(yùn)算邢享;另外需要說明的是,不能對(duì)指針變量進(jìn)行乘法淡诗、除法驼仪、取余等其他運(yùn)算,除了會(huì)發(fā)生語(yǔ)法錯(cuò)誤袜漩,也沒有實(shí)際的含義绪爸。

C中的指針數(shù)組

如果一個(gè)數(shù)組中的所有元素保存的都是指針,那么我們就稱它為指針數(shù)組宙攻。指針數(shù)組的定義形式一般為:

dataType *arrayName[length];

]的優(yōu)先級(jí)高于*奠货,該定義形式應(yīng)該理解為:

dataType *(arrayName[length]);

括號(hào)里面說明arrayName是一個(gè)數(shù)組,包含了length個(gè)元素座掘,括號(hào)外面說明每個(gè)元素的類型為dataType *递惋。

除了每個(gè)元素的數(shù)據(jù)類型不同,指針數(shù)組和普通數(shù)組在其他方面都是一樣的溢陪,下面是一個(gè)簡(jiǎn)單的栗子:

#include <stdio.h>
int main(){
    int a = 16, b = 932, c = 100;
    //定義一個(gè)指針數(shù)組
    int *arr[3] = {&a, &b, &c};//也可以不指定長(zhǎng)度萍虽,直接寫作 int *parr[]
    //定義一個(gè)指向指針數(shù)組的指針
    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));
    return 0;
}

編譯并運(yùn)行結(jié)果如下:

16, 932, 100
16, 932, 100

arr 是一個(gè)指針數(shù)組,它包含了 3 個(gè)元素形真,每個(gè)元素都是一個(gè)指針杉编,在定義 arr 的同時(shí),我們使用變量 a咆霜、b邓馒、c 的地址對(duì)它進(jìn)行了初始化,這和普通數(shù)組是多么地類似蛾坯。

parr 是指向數(shù)組 arr 的指針光酣,確切地說是指向 arr 第一個(gè)元素的指針,它的定義形式應(yīng)該理解為int * ( * parr)脉课,括號(hào)中的 * 表示 parr 是一個(gè)指針救军,括號(hào)外面的int * 表示 parr 指向的數(shù)據(jù)的類型。arr 第一個(gè)元素的類型為 int *倘零,
所以在定義 parr 時(shí)要加兩個(gè) * (星號(hào))(MD語(yǔ)法自動(dòng)識(shí)別其他的格式了)唱遭。

第一個(gè) printf() 語(yǔ)句中,arr[i] 表示獲取第 i 個(gè)元素的值视事,該元素是一個(gè)指針胆萧,還需要在前面增加一個(gè) * 才能取得它指向的數(shù)據(jù),也即 *arr[i] 的形式。

第二個(gè) printf() 語(yǔ)句中跌穗,parr+i 表示第 i 個(gè)元素的地址订晌,* (parr+i) 表示獲取第 i 個(gè)元素的值(該元素是一個(gè)指針),**(parr+i) 表示獲取第 i 個(gè)元素指向的數(shù)據(jù)蚌吸。

通過指針給數(shù)組賦值锈拨,下面是一個(gè)簡(jiǎn)單的栗子:

#include <stdio.h>
void main(){
    int uids[5];
    //高級(jí)寫法
    //int i = 0;
    //for (; i < 5; i++){
    //  uids[i] = i;
    //}
    //早些版本的寫法
    int* p = uids;
    printf("%#x\n",p);
    int i = 0; //i是數(shù)組元素的值
    for (; p < uids + 5; p++){
        *p = i;
        i++;
    }

    getchar();
}

C中的指針與二維數(shù)組

二維數(shù)組在概念上是二維的,有行和列羹唠,但在內(nèi)存中所有的數(shù)組元素都是連續(xù)排列的奕枢,它們之間沒有“縫隙”。以下面的二維數(shù)組 a 為例:

int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };

從概念上來理解佩微,數(shù)組a 的分布如下:

0   1   2   3
4   5   6   7
8   9  10  11

但在內(nèi)存中缝彬,a 的分布是一維線性的,整個(gè)數(shù)組占用一塊連續(xù)的內(nèi)存:

這里寫圖片描述

C語(yǔ)言中的二維數(shù)組是按行排列的哺眯,也就是先存放 a[0] 行谷浅,再存放 a[1] 行,最后存放 a[2] 行奶卓;每行中的 4 個(gè)元素也是依次存放一疯。數(shù)組 a 為 int 類型,每個(gè)元素占用 4 個(gè)字節(jié)夺姑,整個(gè)數(shù)組共占用 4×(3×4) = 48 個(gè)字節(jié)墩邀。

C語(yǔ)言允許把一個(gè)二維數(shù)組分解成多個(gè)一維數(shù)組來處理。對(duì)于數(shù)組 a盏浙,它可以分解成三個(gè)一維數(shù)組眉睹,即 a[0]、a[1]只盹、a[2]辣往。每一個(gè)一維數(shù)組又包含了 4 個(gè)元素,例如 a[0] 包含 a[0][0]殖卑、a[0][1]、a[0][2]坊萝、a[0][3]孵稽。

假設(shè)數(shù)組 a 中第 0 個(gè)元素的地址為 1000,那么每個(gè)一維數(shù)組的首地址如下圖所示:


這里寫圖片描述

為了更好的理解指針和二維數(shù)組的關(guān)系十偶,我們先來定義一個(gè)指向 a 的指針變量 p:

int (*p)[4] = a;

*int p[4]; //定義一個(gè)指針數(shù)組菩鲜,該數(shù)組中每個(gè)元素是一個(gè)指針,每個(gè)指針指向哪里就需要程序中后續(xù)再定義了惦积。

int (p)[4]; //定義一個(gè)數(shù)組指針接校,該指針指向含4個(gè)元素的一維數(shù)組(數(shù)組中每個(gè)元素是int型)。*

區(qū)分int *p[n]; 和int (*p)[n]; 就要看運(yùn)算符的優(yōu)先級(jí)了。
int *p[n]; 中蛛勉,運(yùn)算符[ ]優(yōu)先級(jí)高鹿寻,先與p結(jié)合成為一個(gè)數(shù)組,再由int*說明這是一個(gè)整型指針數(shù)組诽凌。
int (*p)[n]; 中( )優(yōu)先級(jí)高毡熏,首先說明p是一個(gè)指針,指向一個(gè)整型的一維數(shù)組侣诵。

對(duì)指針進(jìn)行加法(減法)運(yùn)算時(shí)痢法,它前進(jìn)(后退)的步長(zhǎng)與它指向的數(shù)據(jù)類型有關(guān),p 指向的數(shù)據(jù)類型是int [4]杜顺,那么p+1就前進(jìn) 4×4 = 16 個(gè)字節(jié)财搁,p-1就后退 16 個(gè)字節(jié),這正好是數(shù)組 a 所包含的每個(gè)一維數(shù)組的長(zhǎng)度躬络。也就是說尖奔,p+1會(huì)使得指針指向二維數(shù)組的下一行,p-1會(huì)使得指針指向數(shù)組的上一行洗鸵。

下面我們就來實(shí)現(xiàn)如何使用指針 p 來訪問二維數(shù)組中的每個(gè)元素越锈。按照上面的定義:

  • p指向數(shù)組 a 的開頭,也即第 0 行膘滨;p+1前進(jìn)一行甘凭,指向第 1 行。
  • *(p+1)表示取地址上的數(shù)據(jù)火邓,也就是整個(gè)第 1 行數(shù)據(jù)丹弱。注意是一行數(shù)據(jù),是多個(gè)數(shù)據(jù)铲咨,不是第 1 行中的第 0 個(gè)元素躲胳,下面的運(yùn)行結(jié)果有力地證明了這一點(diǎn):
#include <stdio.h>
int main(){
    int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
    int (*p)[4] = a;
    printf("%d\n", sizeof(*(p+1)));
    return 0;
}

編譯并運(yùn)行結(jié)果為:

16

那么,*(p+1)+1表示第 1 行第 1 個(gè)元素的地址纤勒。這個(gè)如何理解呢坯苹?(注意,這里的小細(xì)節(jié))

  *(p+1)單獨(dú)使用時(shí)表示的是第 1 行數(shù)據(jù)摇天,放在表達(dá)式中會(huì)被轉(zhuǎn)換為第 1 行數(shù)據(jù)的首地址粹湃,也就是第 1 行第 0 個(gè)元素的地址,因?yàn)槭褂谜袛?shù)據(jù)沒有實(shí)際的含義泉坐,編譯器遇到這種情況都會(huì)轉(zhuǎn)換為指向該行第 0 個(gè)元素的指針为鳄;就像一維數(shù)組的名字,在定義時(shí)或者和 sizeof腕让、& 一起使用時(shí)才表示整個(gè)數(shù)組孤钦,出現(xiàn)在表達(dá)式中就會(huì)被轉(zhuǎn)換為指向數(shù)組第 0 個(gè)元素的指針。

* ( *(p+1)+1) 表示第 1 行第 1 個(gè)元素的值。很明顯偏形,增加一個(gè) * 表示取地址上的數(shù)據(jù)静袖。

根據(jù)上面的推論,推出以下等價(jià)關(guān)系:

a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)

可能有點(diǎn)繞壳猜,不好理解勾徽,不過沒關(guān)系,多看幾遍统扳,相信你是可以的喘帚。

栗子:
使用指針遍歷二維數(shù)組

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

編譯并運(yùn)行的結(jié)果如下:

 0   1   2   3
 4   5   6   7
 8   9  10  11

指針數(shù)組和二維數(shù)組指針的區(qū)別:

指針數(shù)組和二維數(shù)組指針在定義時(shí)非常相似,只是括號(hào)的位置不同:

int *(p1[5]);  //指針數(shù)組咒钟,可以去掉括號(hào)直接寫作 int *p1[5];
int (*p2)[5];  //二維數(shù)組指針吹由,不能去掉括號(hào)

指針數(shù)組和二維數(shù)組指針有著本質(zhì)上的區(qū)別:指針數(shù)組是一個(gè)數(shù)組,只是每個(gè)元素保存的都是指針朱嘴,以上面的 p1 為例倾鲫,在32位環(huán)境下它占用 4×5 = 20 個(gè)字節(jié)的內(nèi)存。二維數(shù)組指針是一個(gè)指針萍嬉,它指向一個(gè)二維數(shù)組乌昔,以上面的 p2 為例,它占用 4 個(gè)字節(jié)的內(nèi)存壤追。

C中的函數(shù)指針

一個(gè)函數(shù)總是占用一段連續(xù)的內(nèi)存區(qū)域磕道,函數(shù)名在表達(dá)式中有時(shí)也會(huì)被轉(zhuǎn)換為該函數(shù)所在內(nèi)存區(qū)域的首地址,這和數(shù)組名非常類似行冰。我們可以把函數(shù)的這個(gè)首地址(或稱入口地址)賦予一個(gè)指針變量溺蕉,使指針變量指向函數(shù)所在的內(nèi)存區(qū)域,然后通過指針變量就可以找到并調(diào)用該函數(shù)悼做。這種指針就是函數(shù)指針疯特。

函數(shù)指針的定義形式為:

returnType (*pointerName)(param list);

returnType 為函數(shù)返回值類型,pointerNmae 為指針名稱肛走,param list 為函數(shù)參數(shù)列表漓雅。

注意:

( )的優(yōu)先級(jí)高于*,第一個(gè)括號(hào)不能省略朽色,如果寫作returnType *pointerName(paramlist);
就成了函數(shù)原型故硅,它表明函數(shù)的返回值類型為returnType *。

下面寫一個(gè)簡(jiǎn)單的栗子:

#include <stdio.h>
#include <Windows.h>

int msg(char* msg,char* title){
    MessageBox(0,msg,title,0);
    return 0;
}
void main(){
    //msg();
    printf("%#x\n",msg);
    printf("%#x\n",&msg);
    //函數(shù)指針
    //函數(shù)返回值類型纵搁,函數(shù)指針的名稱,函數(shù)的參數(shù)列表
    int(*fun_p)(char* msg, char* title) = msg;
    fun_p("消息內(nèi)容","標(biāo)題");

    getchar();
}

編譯并運(yùn)行結(jié)果如下:

這里寫圖片描述

上面對(duì)msg函數(shù)進(jìn)行了調(diào)用往踢,fun_p是一個(gè)函數(shù)指針腾誉。

總結(jié):

指針(Pointer)就是內(nèi)存的地址,C語(yǔ)言允許用一個(gè)變量來存放指針,這種變量稱為指針變量利职。指針變量可以存放基本類型數(shù)據(jù)的地址赏廓,也可以存放數(shù)組桨吊、函數(shù)以及其他指針變量的地址。

常見的指針含義:

- int *p;       p 可以指向 int 類型的數(shù)據(jù),也可以指向類似 int arr[n] 的數(shù)組坚洽。
- int **p;      p 為二級(jí)指針,指向 int * 類型的數(shù)據(jù)斗这。
- int *p[n];    p 為指針數(shù)組事扭。[ ] 的優(yōu)先級(jí)高于 *,所以應(yīng)該理解為 int *(p[n]);
- int (*p)[n];  p 為二維數(shù)組指針桶癣。
- int *p();     p 是一個(gè)函數(shù)拥褂,它的返回值類型為 int *。
- int (*p)();   p 是一個(gè)函數(shù)指針牙寞,指向原型為 int func() 的函數(shù)饺鹃。

以上就是通過學(xué)習(xí)對(duì)指針的概念的理解,不能再寫了间雀,不然又是長(zhǎng)篇大論悔详,很難讓讀者看完,(我也不喜歡)惹挟。

學(xué)習(xí)理解并整理下來的筆記茄螃。
希望大家能夠指點(diǎn)或提出寶貴意見,謝謝匪煌!一起學(xué)習(xí)责蝠。
轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/u011974987/article/details/52270018
個(gè)人站點(diǎn):xuhao.tech

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市萎庭,隨后出現(xiàn)的幾起案子霜医,更是在濱河造成了極大的恐慌,老刑警劉巖驳规,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肴敛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡吗购,警方通過查閱死者的電腦和手機(jī)医男,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捻勉,“玉大人镀梭,你說我怎么就攤上這事□馄簦” “怎么了报账?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵研底,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我透罢,道長(zhǎng)榜晦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任羽圃,我火速辦了婚禮乾胶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朽寞。我一直安慰自己识窿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布愁憔。 她就那樣靜靜地躺著腕扶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吨掌。 梳的紋絲不亂的頭發(fā)上半抱,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音膜宋,去河邊找鬼窿侈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛秋茫,可吹牛的內(nèi)容都是我干的史简。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼肛著,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼圆兵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起枢贿,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤殉农,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后局荚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體超凳,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年耀态,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了轮傍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡首装,死狀恐怖创夜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情仙逻,我是刑警寧澤挥下,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布揍魂,位于F島的核電站,受9級(jí)特大地震影響棚瘟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喜最,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一偎蘸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瞬内,春花似錦迷雪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至能真,卻和暖如春赁严,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背粉铐。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工疼约, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蝙泼。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓程剥,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親汤踏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子织鲸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 指針是C語(yǔ)言中廣泛使用的一種數(shù)據(jù)類型。 運(yùn)用指針編程是C語(yǔ)言最主要的風(fēng)格之一溪胶。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu)搂擦; ...
    朱森閱讀 3,446評(píng)論 3 44
  • 1.語(yǔ)言中變量的實(shí)質(zhì) 要理解C指針,我認(rèn)為一定要理解C中“變量”的存儲(chǔ)實(shí)質(zhì)载荔, 所以我就從“變量”這個(gè)東西開始講起吧...
    金巴多閱讀 1,781評(píng)論 0 9
  • C語(yǔ)言指針的總結(jié) 1. 變量 不同類型的變量在內(nèi)存中占據(jù)不同的字節(jié)空間盾饮。 內(nèi)存中存儲(chǔ)數(shù)據(jù)的最小基本單位是字節(jié),每一...
    xx_cc閱讀 3,751評(píng)論 11 39
  • 首先得明確一個(gè)概念懒熙,交集∩丘损,并集∪,不太理解的可以度娘一下 多選的選擇邏輯 多選分成了兩類工扎,第一種是選擇多個(gè)選項(xiàng)后...
    陌紫豐田閱讀 548評(píng)論 0 0
  • 茶厝閱讀 170評(píng)論 0 0