摘要:變量占用個字節的空間,這里是將的個字節的第一個字節的地址存放在變量中,就是一個之指針變量。是指針變量作者新曉故知總結指針變量,用來存放地址的變量。
目錄
前言:●由于作者水平有限,文章難免存在謬誤之處,敬請讀者斧正,俚語成篇,懇望指教!
???????? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ——By 作者:新曉·故知
?????????????????????????????????????????????????????????????????????????? ? ? ? ? ?——By 作者:新曉·故知
? ????????????????????????????????????????????????????????????????????????????????? ——By 作者:新曉·故知
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?——By 作者:新曉·故知
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ——By 作者:新曉·故知
????????????????????????????????????????????????????????????????????????????????? ? ——By 作者:新曉·故知
? ? ? ????????????????????????????????????????????????????? ? ? ? ??????????——Since?新曉-故知
指針
1. 指針是什么???
指針理解的2個要點:
1. 指針是內存中一個最小單元的編號,也就是地址
2. 平時口語中說的指針,通常指的是指針變量,是用來存放內存地址的變量
?總結:指針就是地址,口語中說的指針通常指的是指針變量。
?
指針變量
我們可以通過&(取地址操作符)取出變量的內存其實地址,把地址可以存放到一個變量中,這個變量就是指針變量
#include
int main(){ int a = 10; 在內存中開辟一塊空間 int *p = &a; 這里我們對變量a,取出它的地址,可以使用&操作符。 a變量占用4個字節的空間,這里是將a的4個字節的第一個字節的地址存放在p變量 中,p就是一個之指針變量。 return 0;} #include
int main(){ int a = 10; int* pa = &a; pa是指針變量 printf("%p/n", &a); return 0;} int main(){ /*char* pc; int* pa; double* pd; printf("%d/n", sizeof(pc)); printf("%d/n", sizeof(pa)); printf("%d/n", sizeof(pd));*/ int a = 0x11223344; int*pa = &a; *pa = 0; return 0;}
?
?
?
?
?
?
?
?? ? ? ???????????????????????????????????????????????????????????????????????????????????——By 作者:新曉·故知
?總結:
指針變量,用來存放地址的變量。(存放在指針中的值都被當成地址處理)。
那這里的問題是: 一個小的單元到底是多大?(1個字節) 如何編址?
經過仔細的計算和權衡我們發現一個字節給一個對應的地址是比較合適的。 對于32位的機器,假設有32根地址線,那么假設每根地址線在尋址的時候產生高電平(高電壓)和低電 平(低電壓)就是(1或者0); 那么32根地址線產生的地址就會是:
00000000 00000000 00000000 0000000000000000 00000000 00000000 00000001...11111111 11111111 11111111 11111111
這里就有2的32次方個地址。 每個地址標識一個字節,那我們就可以給 (2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB) 4G的空閑進行編址。 同樣的方法,那64位機器,如果給64根地址線,那能編址多大空間,自己計算。
這里我們就明白: 在32位的機器上,地址是32個0或者1組成二進制序列,那地址就得用4個字節的空間來存儲,所以 一個指針變量的大小就應該是4個字節。 那如果在64位機器上,如果有64個地址線,那一個指針變量的大小是8個字節,才能存放一個地 址。
總結:
指針是用來存放地址的,地址是唯一標示一塊地址空間的。 指針的大小在32位平臺是4個字節,在64位平臺是8個字節
?????????????????????????????????????????????????????????????????????????????????????????——By 作者:新曉·故知
2. 指針和指針類型
這里我們在討論一下:指針的類型 我們都知道,變量有不同的類型,整形,浮點型等。那指針有沒有類型呢? 準確的說:有的。
當有這樣的代碼:int num = 10;p = #
要將&num(num的地址)保存到p中,我們知道p就是一個指針變量,那它的類型是怎樣的呢? 我們給指針變量相應的類型。?
char *pc = NULL;int *pi = NULL;short *ps = NULL;long *pl = NULL;float *pf = NULL;double *pd = NULL;
?這里可以看到,指針的定義方式是: type + * 。 其實: char* 類型的指針是為了存放 char 類型變量的地址。 short* 類型的指針是為了存放 short 類型變量的地址。 int* 類型的指針是為了存放 int 類型變量的地址。
?那指針類型的意義是什么?
1.指針類型決定了在解引用的是一次能訪問幾個字節(指針的權限)
int* --> 4
char* --> 1
double* --> 8
2.
a. 指針類型決定了在解引用的是一次能訪問幾個字節(指針的權限)
b. 指針類型決定了指針向前或者向后走一步,走多大距離(單位是字節)? ? ??????????????????????????????????????????????????????????????????????? ????????????——By 作者:新曉·故知
int main(){ int arr[10] = { 0 }; int* p = arr; int i = 0; for (i = 0; i < 10; i++) { *(p + i) = i+1; } 倒著打印 //int*q = &arr[9]; //for (i = 0; i < 10; i++) //{ // printf("%d ", *q); // q--; //} return 0;}
int main(){ int arr[10] = { 0 }; int* p = arr; int i = 0; for (i = 0; i < 10; i++) { *(p + i) = i+1; } 倒著打印 int*q = &arr[9]; for (i = 0; i < 10; i++) { printf("%d ", *q); q--; } return 0;}
?
?
int main(){ char* pc; int* pa; double* pd; printf("%d/n", sizeof(pc)); printf("%d/n", sizeof(pa)); printf("%d/n", sizeof(pd)); return 0;}
?2.1 指針+-整數
#include
//演示實例int main(){ int n = 10; char *pc = (char*)&n; int *pi = &n; printf("%p/n", &n); printf("%p/n", pc); printf("%p/n", pc+1); printf("%p/n", pi); printf("%p/n", pi+1); return 0;} ?總結:指針的類型決定了指針向前或者向后走一步有多大(距離)。
2.2 指針的解引用
//演示實例#include
int main(){ int n = 0x11223344; char *pc = (char *)&n; int *pi = &n; *pc = 0; //重點在調試的過程中觀察內存的變化。 *pi = 0; //重點在調試的過程中觀察內存的變化。 return 0;} ?總結: 指針的類型決定了,對指針解引用的時候有多大的權限(能操作幾個字節)。 比如: char* 的指針解引用就只能訪問一個字節,而 int* 的指針的解引用就能訪問四個字節。
?????????????????????????????????????????????????????????????????????????? ? ? ? ? ?——By 作者:新曉·故知
?3. 野指針
概念: 野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)
?3.1 野指針成因
? 1. 指針未初始化
#include
int main(){ int *p;//局部變量指針未初始化,默認為隨機值 *p = 20; return 0;} ?
?2. 指針越界訪問
#include
int main(){ int arr[10] = {0}; int *p = arr; int i = 0; for(i=0; i<=11; i++) { //當指針指向的范圍超出數組arr的范圍時,p就是野指針 *(p++) = i; } return 0;} ?
? 3. 指針指向的空間釋放
這里放在動態內存開辟的時候講解,這里可以簡單提示一下
3.2 如何規避野指針
1. 指針初始化
2. 小心指針越界
3. 指針指向空間釋放即使置NULL
4. 避免返回局部變量的地址
5. 指針使用之前檢查有效性
?
?
#include
int main(){ int *p = NULL; //.... int a = 10; p = &a; if(p != NULL) { *p = 20; } return 0;} ? ????????????????????????????????????????????????????????????????????????????????? ——By 作者:新曉·故知
4. 指針運算?
??
1.指針+- 整數2.指針-指針3.指針的關系運算
??4.1 指針+-整數
#define N_VALUES 5float values[N_VALUES];float *vp;//指針+-整數;指針的關系運算for (vp = &values[0]; vp < &values[N_VALUES];){ *vp++ = 0;}
int main(){ int arr[10] = { 0 }; int*p = arr; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); for (i = 0; i < sz; i++) { *(p + i) = i; } for (i = 0; i < sz; i++) { printf("%d ", *(p + i)); } //int* q = arr + sz - 1; //for (i = 0; i < sz; i++) //{ // //printf("%d ", *q--); // printf("%d ", *(q - i)); //} return 0;}
int main(){ int arr[10] = { 0 }; int*p = arr; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); for (i = 0; i < sz; i++) { *(p + i) = i; } /*for (i = 0; i < sz; i++) { printf("%d ", *(p + i)); }*/ int* q = arr + sz - 1; for (i = 0; i < sz; i++) { //printf("%d ", *q--); printf("%d ", *(q - i)); } return 0;}
?注:
類型指針加一跳過的距離不同:
例:整型指針加一則跳過一個整型,到達下一個整型,字符指針加一則跳過一個字符到達下一個字符,
4.2 指針-指針
注:指針+指針沒有意義!
?36是字節的個數,而9是元素的個數!
?兩個地址相減的絕對值得到的是兩個地址間元素的個數!
int my_strlen(char *s){ char *p = s; while(*p != "/0" ) p++; return p-s;}
?題例:求字符串長度
//求字符串長度的函數#include
//1.計數器int my_strlen(char* s){ int count = 0; while (*s != "/0") { count++; s++; } return count;}//2. 遞歸//3. 指針-指針的方法//int my_strlen(char* s)//{// char* start = s;// while (*s != "/0")// {// s++;// }// return s - start;//}int main(){ char arr[] = "abc"; int len = my_strlen(arr); printf("%d/n", len); return 0;} ??4.3 指針的關系運算
for(vp = &values[N_VALUES]; vp > &values[0];){ *--vp = 0;}
??代碼簡化, 這將代碼修改如下:
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--){ *vp = 0;}
實際在絕大部分的編譯器上是可以順利完成任務的,然而我們還是應該避免這樣寫,因為標準并不保證 它可行。?
?標準規定: 允許指向數組元素的指針與指向數組最后一個元素后面的那個內存位置的指針比較,但是不允許與 指向第一個元素之前的那個內存位置的指針進行比較。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?——By 作者:新曉·故知
??5. 指針和數組
#include
int main(){ int arr[10] = {1,2,3,4,5,6,7,8,9,0}; printf("%p/n", arr); printf("%p/n", &arr[0]); return 0;} int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; //arr - 數組首元素的地址 int* p = arr; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); for (i = 0; i < sz; i++) { printf("%p == %p/n", p + i, &arr[i]); } //for (i = 0; i < sz; i++) //{ // printf("%d ", p[i]);//p[i] --> *(p+i) --> arr[i] //} return 0;}
?
??運行結果:
可見數組名和數組首元素的地址是一樣的
?結論:數組名表示的是數組首元素的地址。(2種情況除外,數組章節講解了) 那么這樣寫代碼是可行的:
int arr[10] = {1,2,3,4,5,6,7,8,9,0};int *p = arr; p存放的是數組首元素的地址
??既然可以把數組名當成地址存放到一個指針中,我們使用指針來訪問一個就成為可能。
#include
int main(){ int arr[] = {1,2,3,4,5,6,7,8,9,0}; int *p = arr; //指針存放數組首元素的地址 int sz = sizeof(arr)/sizeof(arr[0]); for(i=0; i p+%d = %p/n", i, &arr[i], i, p+i); } return 0;} ?所以 p+i 其實計算的是數組 arr 下標為i的地址。 那我們就可以直接通過指針來訪問數組。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ——By 作者:新曉·故知
int main(){ int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; int *p = arr; //指針存放數組首元素的地址 int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i
??6. 二級指針
??指針變量也是變量,是變量就有地址,那指針變量的地址存放在哪里? 這就是 二級指針 。
?
?對于二級指針的運算有:
?*ppa 通過對ppa中的地址進行解引用,這樣找到的是 pa , *ppa 其實訪問的就是 pa .
int b = 20;*ppa = &b;//等價于 pa = &b;
?**ppa 先通過 *ppa 找到 pa ,然后對 pa 進行解引用操作: *pa ,那找到的是 a .
**ppa = 30;//等價于*pa = 30;//等價于a = 30;
?
????????????????????????????????????????????????????????????????????????????????? ? ——By 作者:新曉·故知
7. 指針數組
指針數組是指針還是數組? 答案:是數組。是存放指針的數組。 數組我們已經知道整形數組,字符數組。
?int arr1[5];
char arr2[6];
?那指針數組是怎樣的?
int* arr3[5];//是什么?
arr3是一個數組,有五個元素,每個元素是一個整形指針。
?
?整形指針數組
int main(){ //int arr[10];//整型數組 - 存放整型的數組 //char ch[5];//字符數組 - 存放字符的數組 //指針數組 - 存放指針的數組 int a = 10; int b = 20; int c = 30; int* arr2[5] = { &a, &b, &c };//存放整型指針的數組 int i = 0; for (i = 0; i < 3; i++) { printf("%d ", *(arr2[i])); } return 0;}
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/123954.html
摘要:目錄前言由于作者水平有限,文章難免存在謬誤之處,敬請讀者斧正,俚語成篇,懇望指教前言由于作者水平有限,文章難免存在謬誤之處,敬請讀者斧正,俚語成篇,懇望指教作者新曉故知作者新曉故知那些代碼背后的故事那些代碼背后的故事通過 目錄 前言:●由于作者水平有限,文章難免存在謬誤之處,敬請讀者斧正,俚...
目錄 ?前言:●由于作者水平有限,文章難免存在謬誤之處,敬請讀者斧正,俚語成篇,懇望指教! ???????? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ——By 作者:新曉·故知 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ...
本章目錄 溫馨提示本章重點正文開始1. 操作符分類2.算數操作符2.1 `/`操作符2.2 `%`操作符 3. 位移操作符3.1 ``左移操作符 4. 位操作符4.1 `&`按位與操作符4.2 `|`按位或操作符4.3 `^`按位異或操作符 5. 賦值操作符6. 單目操作符6.1 各種單目操作符6.2 sizeof 和 數組 7. 關系操作符(后面的操作符不單獨出現在目錄中)8. ...
閱讀 1669·2021-11-19 09:40
閱讀 2924·2021-09-24 10:27
閱讀 3214·2021-09-02 15:15
閱讀 1876·2019-08-30 15:54
閱讀 1202·2019-08-30 15:54
閱讀 1368·2019-08-30 13:12
閱讀 625·2019-08-28 18:05
閱讀 2793·2019-08-27 10:53