內存變量簡稱變量,在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程序運行了兩次,每次輸出的結果不同,緣由很簡單,程序每次運行的時候,向系統申請內存,系統隨機分配內存,就像您去賓館開房,若是您不提早預定指定房號,每次獲得的房間編號大機率不會相同。操作系統
指針是一種特別變量,全稱是指針變量,專用於存放其它變量在內存中的地址編號,指針在使用以前要先聲明,語法是:.net
datatype *varname;
datatype 是指針的基類型,它必須是一個有效的C數據類型(int、char、double或其它自定義的數據類型),varname 是指針的名稱。用來聲明指針的星號 * 與乘法中使用的星號是相同的。可是,在這個場景中,星號是用來表示這個變量是指針。如下是有效的指針聲明:3d
int *ip; // 一個整型的指針 char *cp; // 一個字符型的指針 double *dp; // 一個 double 型的指針
不論是整型、浮點型、字符型,仍是其餘的數據類型的內存變量,它的地址都是一個十六進制數,能夠理解爲內存單元的編號。咱們用整數型指針存放整數型變量的地址;用字符型指針存放字符型變量的地址;用雙精度型指針存放雙精度型變量的地址,用自定義數據類型指針存放自定義數據類型變量的地址。指針
把指針指向具體的內存變量的地址,就是對指針賦值。
示例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); }
運行效果
定義了指針變量,並指向了內存變量的地址,就能夠經過指針來操做內存變量(在指針前加星號*),效果與使用變量名相同。
示例(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); }
運行效果
在咱們以前講的函數的參數章節中,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函數根據傳進去的地址直接操做內存,改變內存中的值,完成了對變量的賦值。
空指針就是說指針沒有指向任何內存變量,指針的值是空,因此不能操做內存,不然可能會引發程序的崩潰。
示例(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),就是程序崩潰掉了。
在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]); }
運行效果
從以上的示例能夠看出,數組名、對數組取地址和數組元素的首地址是同一回事。在應用開發中,程序員通常用數組名,書寫最簡單。
地址能夠用加(+)和減(-)來運算,加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。
在應用開發中,地址的運算很重要,主要用於字符串操做,在之後的字符串章節中我將詳細介紹。
指針也是一種內存變量,是內存變量就要佔用內存空間,在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。
本章節介紹的知識已經包括了指針99%的用法,還有一些的知識點如指針的指針、函數指針等,這些概念難以理解,應用場景極少。學習的方法應該是按部就班,等功力增加以後,那些複雜的概念其實也很容易。若是在這裏就把人搞暈了,就沒辦法繼續學習下去。
操做變量能夠用變量名,也能夠用變量的地址。
指針用一句話能夠歸納,就是用來存放變量的地址,是一種中間狀態的變量。
變量的地址是變量的地址,指針是指針,地址和指針之間的關係像水與水桶的關係,表達的時候要嚴謹一些,不要把地址說成指針,也不要把指針說成地址。
指針就這麼簡單,您本身不要把本身暈了就行。
一、編寫示例程序,把本章節的知識所有演示一遍,必須充分理解每個細節,指針對C/C++程序員極其重要,沒有指針,程序無法寫。
二、系統會爲變量分配內存,也會爲常量分配內存,有內存就有地址,試試如下代碼,若是不能理解就跳過。
char *pstr="西施"; printf("pstr=%p\n",pstr); printf("pstr=%s\n",pstr); // 不會出現段錯誤(Core dump) strcpy(pstr,"楊玉環"); // 會出現段錯誤(Core dump)
C語言技術網原創文章,轉載請說明文章的來源、做者和原文的連接。
來源:C語言技術網(www.freecplus.net)
做者:碼農有道
若是這篇文章對您有幫助,請點贊支持,或在您的博客中轉發個人文章,謝謝!!!若是文章有錯別字,或者內容有錯誤,或其餘的建議和意見,請您留言指正,很是感謝!!!