C語言指針

1、變量的地址

內存變量簡稱變量,在C語言中,每定義一個變量,系統就會給變量分配一塊內存,而內存是有地址的。若是把計算機的內存區域比喻成一個大賓館,每塊內存的地址就像賓館房間的編號。程序員

C語言採用運算符&來獲取變量的地址。請看下面的示例。數組

示例(book50.c)markdown

/*
 * 程序名:book50.c,此程序用於演示獲取變量的地址
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h> 

int main() 
{ 
  int    ii=10;
  char   cc='A';
  double dd=100.56;

  printf("變量ii的地址是:%p\n",&ii);
  printf("變量cc的地址是:%p\n",&cc);
  printf("變量dd的地址是:%p\n",&dd);

  return 0;
}

運行效果ide

在這裏插入圖片描述

注意:函數

1)在printf函數中,輸出內存地址的格式控制符是%p,地址採用十六進制的數字顯示。學習

2)book50程序運行了兩次,每次輸出的結果不同,緣由很簡單,程序每次運行的時候,向系統申請內存,系統隨機分配內存,就像您去賓館開房,若是您不提早預定指定房號,每次獲得的房間編號大機率不會相同。操作系統

2、指針

指針是一種特別變量,全稱是指針變量,專用於存放其它變量在內存中的地址編號,指針在使用以前要先聲明,語法是:.net

datatype *varname;

datatype 是指針的基類型,它必須是一個有效的C數據類型(int、char、double或其它自定義的數據類型),varname 是指針的名稱。用來聲明指針的星號 * 與乘法中使用的星號是相同的。可是,在這個場景中,星號是用來表示這個變量是指針。如下是有效的指針聲明:3d

int     *ip;    // 一個整型的指針
char    *cp;   // 一個字符型的指針
double *dp;   // 一個 double 型的指針

3、對指針賦值

不論是整型、浮點型、字符型,仍是其餘的數據類型的內存變量,它的地址都是一個十六進制數,能夠理解爲內存單元的編號。咱們用整數型指針存放整數型變量的地址;用字符型指針存放字符型變量的地址;用雙精度型指針存放雙精度型變量的地址,用自定義數據類型指針存放自定義數據類型變量的地址。指針

把指針指向具體的內存變量的地址,就是對指針賦值。

示例book51.c

/*
 * 程序名:book51.c,此程序用於演示指針變量
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h> 

int main() 
{ 
  int    ii=10;
  char   cc='A';
  double dd=100.56;

  int    *pii=0;  // 定義整數型指針並初始化
  char   *pcc=0;  // 定義字符型指針並初始化
  double *pdd=0;  // 定義雙精度型指針並初始化

  pii=ⅈ  // 數型指針並指向變量ii
  pcc=&cc;  // 字符型指針並指向變量cc
  pdd=ⅆ  // 雙精度型指針並指向變量dd

  // 輸出指針變量的值
  printf("pii的值是:%p\n",pii);
  printf("pcc的值是:%p\n",pcc);
  printf("pdd的值是:%p\n",pdd);
}

運行效果

在這裏插入圖片描述

4、經過指針操做內存變量

定義了指針變量,並指向了內存變量的地址,就能夠經過指針來操做內存變量(在指針前加星號*),效果與使用變量名相同。

示例(book52.c)

/*
 * 程序名:book52.c,此程序演示指針的使用。
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>

int main()
{
  int    ii=10;

  int    *pii=0;  // 定義整數型指針並初始化

  pii=ⅈ  // 數型指針指向變量ii

  // 經過指針操做內存變量,改變內存變量的值
  *pii=20;    // 同ii=20;

  printf("pii的值是:%p\n",pii);
  printf("*pii的值是:%d\n",*pii);
  printf("ii的值是:%d\n",ii);
}

運行效果

在這裏插入圖片描述

5、再來討論函數的參數傳遞

在咱們以前講的函數的參數章節中,book49.c演示了函數的參數傳遞,主程序調用funcld函數的時候,傳遞的是變量的值,如今把它修改一下。

示例(book55.c)

/*
 * 程序名:book55.c,此程序演示函數參數的傳遞和指針
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h> 

// 聲明funcld函數,p是一個指針變量
void funcld(int *p);   

int main() 
{ 
  int a=10;

  printf("位置一:a是一個變量,變量的地址是%p,a的值是 %d\n",&a,a);
  funcld(&a);   // 調用函數,傳遞變量a的地址的值
  printf("位置二:a是一個變量,變量的地址是%p,a的值是 %d\n",&a,a);
}

void funcld(int *p)
{
  printf("位置三:p是一個指針 %p, 指向的內存的地址是 %d\n",p,*p);
  *p=20;   
  printf("位置四:p是一個指針 %p, 指向的內存的地址是 %d\n",p,*p);
}

運行效果

在這裏插入圖片描述

book55.c演示了函數參數和指針的使用,主程序把變量a的地址傳遞給函數funcld,funcld函數的參數p是一個指針,接存放變量a的地址。在函數funcld中,根據指針中的地址直接操做內存,從而修改了主程序中變量a的值。

咱們已經使用scanf函數不少次了,調用scanf函數的時候,須要在變量前面加符號&,其實就是把變量的地址傳給scanf函數,scanf函數根據傳進去的地址直接操做內存,改變內存中的值,完成了對變量的賦值。

6、空指針

空指針就是說指針沒有指向任何內存變量,指針的值是空,因此不能操做內存,不然可能會引發程序的崩潰。

示例(book56.c)

/*
 * 程序名:book56.c,此程序演示操做空指針引發程序的崩潰
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>

int main()
{
  int *pi=0;  // 定義一個指針

  printf("pi的值是 %p\n",pi);

  *pi=10;  // 試圖對空指針進行賦值操做,必將引發程序的崩潰

  return 0;
}

運行效果

在這裏插入圖片描述

段錯誤(Core Dump),就是程序崩潰掉了。

7、數組的地址

在C語言中,數組佔用的內存空間是連續的,數組名是數組元素的首地址,也是數組的地址。

示例(book57.c)

/*
 * 程序名:book57.c,此程序數組的地址
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

int main()
{
  char name[51];
  strcpy(name,"C語言技術網(www.freecplus.net)");

  printf("%p\n",name);
  printf("%p\n",&name);
  printf("%p\n",&name[0]);

  printf("%s\n",name);
  printf("%s\n",&name);
  printf("%s\n",&name[0]);
}

運行效果

在這裏插入圖片描述

從以上的示例能夠看出,數組名、對數組取地址和數組元素的首地址是同一回事。在應用開發中,程序員通常用數組名,書寫最簡單。

8、地址的運算

地址能夠用加(+)和減(-)來運算,加1表示下一個存儲單元的地址,減1表示上一個存儲單元的地址,通常狀況下,地址的運算適用於數組,對單個變量的地址運算沒有意義。

示例(book58.c)

/*
 * 程序名:book58.c,此程序演示地址的運算。
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>

int main()
{
  char   cc[4];   // 字符數組
  int    ii[4];   // 整數數組
  double dd[4];   // 浮點數組

  // 用地址相加的方式顯示數組所有元素的的址
  printf("%p %p %p %p\n",cc,cc+1,cc+2,cc+3);
  printf("%p %p %p %p\n",ii,ii+1,ii+2,ii+3);
  printf("%p %p %p %p\n",dd,dd+1,dd+2,dd+3);
}

運行效果

在這裏插入圖片描述

你們請注意,第一行輸出的每一個地址的增量是1,第二行的每一個地址的增量是4,第三行的每一個地址的增量是8,爲何會這樣?由於數組cc是char型,一個存儲單元是1個字節,數組ii是int型,一個存儲單元是4個字節,數組ll是long型,一個存儲單元是8個字節,地址加1指的是下一個存儲單元,不是數學意義中的1。

在應用開發中,地址的運算很重要,主要用於字符串操做,在之後的字符串章節中我將詳細介紹。

9、指針佔用內存狀況

指針也是一種內存變量,是內存變量就要佔用內存空間,在C語言中,任何類型的指針佔用8字節的內存(32位操做系統4字節)。

printf("sizeof(int *) is %d.\n",sizeof(int *));        // 輸出:sizeof(int *) is 8
  printf("sizeof(char *) is %d.\n",sizeof(char *));      // 輸出:sizeof(char *) is 8
  printf("sizeof(double *) is %d.\n",sizeof(double *));  // 輸出:sizeof(double *) is 8

輸出的結果都是8。

10、指針的其它知識

本章節介紹的知識已經包括了指針99%的用法,還有一些的知識點如指針的指針、函數指針等,這些概念難以理解,應用場景極少。學習的方法應該是按部就班,等功力增加以後,那些複雜的概念其實也很容易。若是在這裏就把人搞暈了,就沒辦法繼續學習下去。

11、小結

操做變量能夠用變量名,也能夠用變量的地址。

指針用一句話能夠歸納,就是用來存放變量的地址,是一種中間狀態的變量。

變量的地址是變量的地址,指針是指針,地址和指針之間的關係像水與水桶的關係,表達的時候要嚴謹一些,不要把地址說成指針,也不要把指針說成地址。

指針就這麼簡單,您本身不要把本身暈了就行。

12、課後做業

一、編寫示例程序,把本章節的知識所有演示一遍,必須充分理解每個細節,指針對C/C++程序員極其重要,沒有指針,程序無法寫。

二、系統會爲變量分配內存,也會爲常量分配內存,有內存就有地址,試試如下代碼,若是不能理解就跳過。

char *pstr="西施";
  printf("pstr=%p\n",pstr);
  printf("pstr=%s\n",pstr);     // 不會出現段錯誤(Core dump)
  strcpy(pstr,"楊玉環");          // 會出現段錯誤(Core dump)

十3、版權聲明

C語言技術網原創文章,轉載請說明文章的來源、做者和原文的連接。
來源:C語言技術網(www.freecplus.net)
做者:碼農有道

若是這篇文章對您有幫助,請點贊支持,或在您的博客中轉發個人文章,謝謝!!!若是文章有錯別字,或者內容有錯誤,或其餘的建議和意見,請您留言指正,很是感謝!!!

相關文章
相關標籤/搜索