摘要:如果我們要將的地址保存到中,我們需要我們給指針變量相應的類型。類型的指針是為了存放類型變量的地址這里可以看到,指針的定義方式是類型名指針變量名。如下最后本文介紹的是指針的基礎知識,往后還會繼續深入講解指
指針是C語言中的一個重要概念。正確而靈活的運用指針,可以使程序間接、緊湊、高效。每一個學習和使用C語言的人,都應當深入地學習和掌握指針。
提示:以下是本篇文章正文內容,下面案例可供參考
指針是包含內存地址的變量,這個地址是內存中另一個對象(通常是另一個變量)的位置。例如如果一個變量包含另一個變量的地址,我們說第一個變量指向第二個變量。
相信大家看到上面這段話,可能有點懵,不急,我稍后再給大家解釋。在這里,我先給大家講述一下,數據在內存中是如何存儲和讀取的?
如果在程序中定義了一個變量,在對程序進行編譯的時候,系統就會給這個變量分配內存單元。編譯系統根據程序中的定義的變量類型,分配一定長度的空間
那么,這些字節在內存中被分配到哪里?我們如何找到呢?
為了解決這個問題,我們就給內存區的每一個字節一個編號,這個就是它們的“地址”。它相當于旅館中的房間號,在地址所標志的內存單元中存放的數據則相當于旅館房間中居住的旅客。
所以指針是個變量,存放內存單元的地址(編號)
1、對于32位的機器,假設有32根地址線,那么假設每根地址線在尋址的時候產生高電平(高電壓)和低電
平(低電壓)就是(1或者0);
2根地址線上的電信號轉換成數字信號用(1/0)表示,所以可能性
00000000000000000000000000000000–11111111111111111111111111111111
也就是有2^32 編號,說明可以管理2的32次方個單元
這里就有2的32次方個地址。
每個地址標識一個字節,那我們就可以給
(2^32Byte == 2^32/1024KB == 2^32 /1024/1024MB==2^32/1024/1024/1024GB == 4GB) 4G的空閑進行編址。
按照同樣的方法,我們可以計算出64四位機器,下面就直接給結論了。
1、在32位的機器上,地址是32個0或者1組成二進制序列,那地址就得用4個字節的空間來存儲,所 以一個指針變量的大小就應該是4個字節。
2、在64位機器上,如果有64個地址線,那一個指針變量的大小是8個字節,才能存放一個地址指針的大小在32位平臺是4個字節,在64位平臺是8個字節。
思考一個問題,在編譯器中,如何把3賦值給i這個變量中?
第一種作法,把3直接送到i所表示的單元中,例如“i=3”;
int main(){ int i=3; return 0;}
第二種方法,把3送到變量p所指向的單元(即變量i的存儲單元,也就是地址,如p=3,其中i表示p指向的對象)
int main(){ int i; //int i = 3;//第一種方法 int *p = &i;//第二種方法 //這里我們對變量a,取出它的地址,可以使用&操作符。 //將i的地址存放在p變量中,p就是一個指針變量。 *p = 3; printf("%d/n", i); return 0;}
思考一個問題:
把int型變量a和float型變量b先后分配到2000開始的存儲單元中,&a和&b的信息完全相同嗎?
答案是不相同的,因為雖然存儲單元的編號相同,但他們的數據類型不同。
此外,還因為數據類型的不同,無法確定是從一個字節中取信息(字符數據),還是從兩個字節取信息(短整型),抑或是從四個字節取信息(整型),不同的類型,存儲方式是不一樣的。
如果我們要將&num(num的地址)保存到p中,我們需要我們給指針變量相應的類型。
如下:
char *pc = NULL;//har* 類型的指針是為了存放 char 類型變量的地址。int *pi = NULL;//int* 類型的指針是為了存放 int 類型變量的地址。short *ps = NULL;//short* 類型的指針是為了存放 short 類型變量的地址long *pl = NULL;float *pf = NULL;double *pd = NULL;
這里可以看到,指針的定義方式是: 類型名 * 指針變量名 。
【總結】
C語言中的地址包括位置信息(內存編號,或稱純地址)和它所指向的數據的類型信息,或者說它是“帶類型的地址”,如&a,一般稱它位“變量a的地址”,但是確切地說,它是“整型變量a的地址”
作用一:
指針類型決定了指針解引用操作的時候,一次訪問幾個字節(訪問內存的大小)
int main(){ int a = 0x11223344; int* pa = &a; *pa = 0; return 0;}
int main(){ int a = 0x11223344;/* int* pa = &a; *pa = 0;*/ char* pc = &a;//int* *pc = 0; return 0;}
指針類型的意義1
指針類型決定了指針解引用操作的時候,一次訪問幾個字節(訪問內存的大小)
char* 指針解引用訪問1個字節
int* 指針解引用訪問4個字節
作用二:
指針類型決定了,指針±整數的時候的步長(指針±整數的時候,跳過幾個字節)
int main(){ int a = 10; int * pa=&a; char *pc = &a; printf("%p/n", pa); printf("%p/n", pc); printf("%p/n", pa+1);//如果是整型指針int*,+1則跳過4個字節、 printf("%p/n", pc+1);//char* 指針+1,跳過1個字節 return 0;}
概念: 野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)
什么意思?舉個例子
就是你撿到一把鑰匙,但是不知道它可以開那道門。
指針沒有初始化,里面放的是隨機值
#include int main(){ int *p;//局部變量指針未初始化,默認為隨機值 *p = 20;//通過p中存的隨機值作為地址,找到一個空間,這個空間不屬于我們當前的程序,就造成了非法訪問//如果非法訪問了,p就是野指針 return 0; }
指針越界造成野指針問題
int main(){ int arr[10] = 0; int i = 0; int * p = arr; for (i = 0; i <= 10; i++)//這里循環了11次,當指針指向的范圍超出數組arr的范圍時,p就是野指針 { *p = 1; p++; } return 0;}
當一個指針指向的空間釋放了,這個指針就變成野指針了
int* test(){ int a = 10; return &a; //int *,生命周期,出來就銷毀了}int main(){ int *p = test(); //printf("不愧是你/n");//加入這里加了一條語句,下面的值就變了 printf("%d/n", *p);//編譯出10是因為編譯器會對值做一次保留。所以能訪問到上面函數不一定是對的 return 0;}
- 指針初始化
- 小心指針越界
- 指針指向空間釋放即使置NULL
- 避免返回局部變量的地址
- 指針使用之前檢查有效性
//規避野指針int main(){ int a = 10; int * p = &a;//1、明確初始化,確定指向 int * p2 = NULL;//NULL本質是0,2、不知道一個指針當前應該指向哪里是,可以初始化位NULL //*p2 = 100;//err,對于空指針,是不能直接解引用的 //如何規避? if (p2 != NULL)//先判斷是不是空指針 { *p2 = 100;//這樣才對 }}
int main(){ float arr[5]; float *p; for (p = &arr[0]; p < &arr[5];) { *p++ = 0;//對一個指針加1使它指向數組中的下一個元素,把指針指向的內容全部賦值給0 } return 0;}
也就說,如果加2使它向右移動2個元素的位置,依次類推。把一個指針減去2使它向左移動2個元素的位置。
1、指針減去指針的前提,是兩個指針指向同一塊區域
2、指針減去指針,得到數字的絕對值,是指針和指針之間元素的個數
int main(){ int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; char ch[5] = { 0 }; //printf("%d/n", &arr[9] - &ch[0]);//這種算法是錯誤的 printf("%d/n", &arr[9] - &arr[0]);//算出的是元素的個數 printf("%d/n", &arr[0] - &arr[9]);// //指針減去指針的前提,是兩個指針指向同一塊區域 //指針減去指針,得到數字的絕對值,是指針和指針之間元素的個數 return 0;}
【注意】
指針與指針之間不能進行加法運算,因為進行加法后,得到的結果指向一個不知所向的地方,沒有實際意義
什么意思,舉個例子。
一個變量有地址,一個數組包含若干元素,每個數組元素都在內存中占用存儲單元,它們都有相應的地址。
指針變量既然可以指向變量,當然也可以指向數組元素,也就是把某一元素地址放到一個指針變量中。
所謂數組元素的指針就是數組元素的地址
(1)用一個指針變量指向一個數組元素
int main(){ int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; int* p;//定義p位指向整型變量的指針變量 p = &arr[0];//把a[0]元素的地址賦給指針變量p return 0;}
以上是使指針變量p指向a數組的第0號元素
(1)下標法,如a[i]形式
(2)指針法,如*(a+i)
下標法:
int main(){ int arr[10]; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); printf("%d/n", sz); printf("%p/n", arr);//數組名就是首元素地址 //下標法 printf("%p/n", &arr[0]); int* p=&arr[5];//整型地址放在整型指針上,從而讓指針跟數組建立聯系 //數組名確實是首元素地址, //但是有兩個例外 //1.sizeof(數組名),這里的數組名不是首元素地址,是表示整個數組,計算的是整個數組的大小,單位是字節 //2.&數組名,拿到的是整個數組的地址 return 0; }
指針法:
int main(){ int arr[10]; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); int* p=&arr[0];//整型地址放在整型指針上,從而讓指針跟數組建立聯系 //指針法 for (i = 0; i < sz; i++) { *(p + i) = i;// p+i 其實計算的是數組 arr 下標為i的地址。 } for (i = 0; i < sz; i++) { printf("%d ", *(p + i)); } return 0; }
一個小知識:
int main(){ int arr[10] = { 0 }; arr;//數組名 &arr[0];//取出首元素地址 &arr;//取出整個數組的地址 printf("%d/n", &arr[0]); printf("%d/n", &arr); return 0;}
指針變量的地址二級指針
什么意思?舉個例子
int main(){ int a = 10;//4byte,向內存申請4個字節 int* p=&a;//p指向a,稱為一級指針 int* *pp=&p;//pp就是二級指針,pp存放的是一級指針的地址 * *pp = 20;//需兩層解引用 printf("%d/n", a); //int** * ppp = &pp;//ppp就是三級指針 return 0;}
存放指針的數組就是指針數組
int main(){ int arr[10];//整型數組,存放整型的數組就是整型數組 char ch[5];//字符數組,存放字符的數組就是字符數組 //指針數組,存放指針的數組就是指針數組 //int* 整型指針的數組 //char* 字符指針的數組 int* parr[5];//整型指針的數組,存放的類型都是int* char* pc[6];//字符指針的數組 return 0;}
我們也可以用同樣的方式來訪問指針數組。
如下
int main(){ int a = 10; int b = 20; int c = 30; int * arr[3] = { &a, &b, &c }; int i = 0; for (i = 0; i < 3; i++) { printf("%d/n",*(arr[i])); } int *pa = &a; int *pb = &b; int *pc = &c; return 0;}
本文介紹的是指針的基礎知識,往后還會繼續深入講解指針更深入的知識。此外,本文參考了譚浩強《C語言設計》(第五版),以及網上的部分資料,加之自己在學習聽課時的筆記,梳理而成,花費了我很多心思。當文章寫成之時,時間已過去4個多小時!
希望能對看到的大家有所幫助!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/120824.html
摘要:函數的返回值為指針就按照字面意思,指針函數的定義顧名思義,指針函數即返回指針的函數。 目錄 前言指針與函數函數的返回值為指針作為函數參數的指針指針函數可以改變變量...
摘要:一結構體的聲明與定義結構體的聲明結構是一些值的集合,這些值稱為成員變量。但是結構體變量的變量名并不是指向該結構體的地址,所以要使用取地址運算符才能獲取其地址。因此,結構體傳參的時候,要傳結構體的地址。 ...
摘要:一指針概述指針是個變量存放內存單元的地址編號。即存放指針變量的地址的指針二級指針指向的空間的值是一個一級指針。總結指針是語言非常重要的一部分內容繁多不易懂本文僅介紹了一些基本知識后續還會深入了解指針。 ...
閱讀 4933·2021-11-25 09:43
閱讀 1186·2021-11-24 09:38
閱讀 1892·2021-09-30 09:54
閱讀 2800·2021-09-23 11:21
閱讀 2366·2021-09-10 10:51
閱讀 2368·2021-09-03 10:45
閱讀 1163·2019-08-30 15:52
閱讀 1766·2019-08-30 14:13