標籤:無法 標頭檔 必須 malloc 元素 運算 字元 儲存 strong
指標
指標和指標變數的關係 指標就是地址,地址就是指標 地址就是記憶體單元的編號 指標變數是存放地址(記憶體單元的編號)的變數 指標和指標變數是兩個不同的概念 但要注意:通常我們會把指標變數簡稱為指標表,實際含義不一樣 指標的本質就是一個操作受限的非負整數 重要性: 表示一些複雜的資料結構 快速的傳遞資料 減少了記憶體的耗用【重點】 使函數返回一個以上的值【重點】 能直接存取硬體 能夠方便的處理字串 是理解物件導向語言中引用的基礎 定義: 地址: 記憶體單元的編號
從0開始的非負整數 範圍:4G 【0---4G-1】 分類: 1.基本類型指標【重點】 附註: *的含義
1.乘法 2.定義指標變數 int *p;//定義一個名字叫p的變數,int *表示p只能存放 int變數地址 3.指標運算子 該運算子放在已經定義好的指標變數的前面 如果p是一個已經定義好的指標變數 則*p表示以p的內容為地址的變數 如何通過被調函數修改主調函數普通變數的值 1.實參必須為該普通變數的地址 2.形參必須為指標變數 3.在被調函數中通過 *形參名 = ····· 的方式就可以修改主調函數相關變數的值 2.指標和數組 指標和一維數組 一維數組名: 一維數組名是個指標常量 它存放的是數組第一個元素的地址 下標和指標的關係 如果p是個指標變數,則 p[i]永遠等價於 *(p+i) 確定一個一維數組需要幾個參數【如果一個函數要接受一個一維數組,需要哪些條件】數組第一個元素的地址和數組長度
# include <stdio.h>//f函數可以輸出任何一個一維數組的內容 void f(int * pArr,int len){ int i; for(i = 0;i < len;++i) printf("%d",*(pArr + i)); /*(pArr + i)等價於 pArr[i] 也等價於 數組[i] printf("\n"); }int main(void){ int a[5] = {1,2,3,4,5}; int b[6] = {-1,-2,-3,4,5,-6}; int c[100] = {1,99,22,33}; f(a,5); //a是int *類型,需要數組第一個元素的地址和長度 f(b,6); f(c,100); return 0; }
# include <stdio.h>//f函數可以輸出任何一個一維數組的內容 void f(int * pArr,int len){ pArr[3] = 88;}int main(void){ int a[6] = {1,2,3,4,5,6}; printf("%d\n",a[3]); f(a,6); printf("%d\n",a[3]); return 0; }/*488*/
指標變數的運算 指標變數不能相加,不能相乘,也不能相除,只能相減 如果兩個指標變數指向的是同一塊連續空間中的不同儲存單元,則這兩個指標變數才可以相減
# include <stdio.h>int main(void){ int i = 5; int j = 10; int *p = &i; int *q = &j; int a[5]; p = &a[1]; q = &a[4]; printf("p和q所指向的單元相隔%d個單元\n",q-p); //p-q沒有實際意義 return 0; }
一個指標變數到底占幾個位元組【非重點】 預備知識: sizeof(資料類型) 功能:傳回值就是該資料類型所佔的位元組數 例子:sizeof(int) = 4 sizeof(char) = 1 sizeof(double) = 8 sizeof(變數名) 功能:傳回值是該變數所佔的位元組數 假設p指向char類型變數(1個位元組) 假設p指向char類型變數(4個位元組) 假設p指向char類型變數(8個位元組) p q r本身所佔位元組數是否一致? 答案:一致總結: 1.一個指標變數,無論它所指向耳朵變數占幾個位元組 該指標變數本身只佔四個位元組 2.一個變數的地址使用該變數首位元組的地址來表示 指標和二維數組 3.指標和函數 4.指標和結構體 5.多級指標
//多級指標 # include <stdio.h>int main(void){ int i = 10; int *p = &i; int **q = &p; int ***r = &q; /* *r = q->**r = *q = p->***r = **q = *p = i */ //r = &p; //因為r是int ***類型,r只能存放int **類型變數的地址 printf("i = %d\n",***r); return 0;}
//多級指標 # include <stdio.h>void f(int **q) //*q就是p { } void g(){ int i = 10; int *p = &i; f(&p); //p是int *類型,&p是int ** 類型 }int main(void){ g(); return 0;}
專題:
動態記憶體分配【重點痛點】
傳統數組的缺點: 1.數組的長度必須事先指定,且只能是常整數,不能是變數 例子: int a[5]; //OK int len = 5;int a[len];//error 2.傳統形式定義的數組,該數組的記憶體程式員無法手動釋放 在一個函數運行期間,系統為該函數中的數組所分配的空間會一直存在,直到該函數運行完畢時,數組的空間才會被系統釋放 3.數組的長度不能在函數啟動並執行過程中動態擴充或縮小 數組的長度一旦定義,其長度就不能再更改 4.A函數定義的數組在A函數運行期間可以被其他函數使用,但A函數運行完畢之後,A函數中的數組無法再被其他函數使用 傳統方式定義的數組不能跨函數使用 為什麼需要動態分配記憶體 動態數組很好的解決了傳統數組的這4個缺點 傳統數組也叫靜態數組 動態記憶體分配舉例--動態數組的構造
/* malloc是memory(記憶體) allocate(分配)的縮寫 */# include <stdio.h># include <malloc.h> //不能省 int main(void){ int i = 5; //分配了4個位元組 靜態分配 int *p = (int *)malloc(4);//12行 /* 1.要使用malloc函數,必須添加malloc.h這個標頭檔 2. mallo0c函數只有一個形參,並且形參是整型 3.4表示請求系統為本程式分配4個位元組 4.malloc函數只能返回第一個位元組的地址 5. 12行分配了8個位元組, p變數佔4個位元組,p指向的記憶體也佔4個位元組 6.p本身所佔的記憶體是靜態分配的,p所指向的記憶體是動態分配的 */ *p = 5;//*p代表的就是一個int變數, //只不過*p這個整型變數的記憶體配置方式和11行的不同 free(p); //free(p)表示把p所佔的記憶體給釋放掉 // p本身的記憶體是靜態,不能由程式員手動釋放 printf("同志們好!\n"); return 0; }
# include <stdio.h># include <malloc.h> int main(void){ int len; int *pArr; int i; //動態構造一維數組 printf("請輸入您要存放的元素的個數:"); scanf("%d",&len); pArr = (int *)malloc(4 * len); //對一維數組進行操作 for(i = 0;i < len;++i) scanf("%d",&pArr[i]); //對一維數組進行輸出 printf("一維數組的內容是:\n"); for(i = 0;i < len;++i) printf("%d\n",pArr[i]); free(pArr); //釋放掉動態分配的數組 return 0;}
靜態記憶體和動態記憶體的比較 靜態記憶體是由系統自動分配,由系統自動釋放 靜態記憶體是在棧分配的 動態記憶體是由程式員手動分配,手動釋放 動態記憶體是在堆分配的
跨函數使用記憶體的問題 靜態變數不能跨函數使用
# include <stdio.h>void f(int **q) //q也是個指標變數, //無論q是什麼類型的指標變數,都只佔4個位元組 { int i = 5; //*q等價於p q和**q都不等價於p //*q = i; //error 因為*q = i;等價於p = i,這是錯誤的 *q = &i; //p = &i; p = *q; --> *q = &i;}int main(void){ int *p; f(&p); //printf("%d\n",*p); //本語句文法沒有問題,但邏輯有問題 ,它是靜態分配的 return 0;}
動態記憶體可以跨函數使用
# include <stdio.h># include <malloc.h> void f(int **q){ *q = (intn *)malloc(sizeof(int)); //sizeof(資料類型) 傳回值是該資料類型所佔的位元組 **q = 5; //*p = 5;}int main(void){ int *p; f(&p); printf("%d\n",*p); //沒有錯誤,函數沒有終止 ,因為是動態分配的 return 0;}
C語言之指標