1.1 指針和內存
C程序在編譯後,會以三種形式使用內存:
1)靜態/全局內存
靜態/全局聲明的變量在這裡。這些變量從程序開始運行時分配,直到程序終止才消失。
所有函數都能訪問全局變量,靜態變量的作用域則局限在定義它們的函數內部。
2)自動內存
這些變量在函數內部聲明,並且在函數調用時才創建,他們的作用域局限於函數內部,
而且聲明周期限制在函數的執行時間內。
3)動態內存
內存分配在堆上,可以根據需要釋放,而且直到釋放才消失。指針引用分配的內存,作用域
局限於引用內存的指針。
數組和指針實現員工鏈表時情況:
1.創建數組時需要知道數組的長度,這樣就會限制鏈表所容納的元素數量。
2.指針沒有上面的限制,新節點可以根據需要動態分配。malloc和free函數分配和釋放動態內存。
Tips:
1.如何閱讀指針聲明,那就是倒過來讀
const int *pci // pci 是一個指向整數常量的指針變量
2.在不同平台上用一致的方式顯示指針的值比較困難。一種方法就是把指針(強制)轉化為void指針,然後用%p/%o/%x格式說明符來顯示。
printf("Value of pi: %p\n", (void*)pi);
void指針是通用指針,用來存放任何數據類型的引用。任何指針都可以被賦給void指針,它可以被轉換為原來的指針類型。
void只用作數據指針,不能用作函數指針。
3.指針被聲明為全局/靜態。就會在程序啟動時被初始化為NULL。
1.2 指針操作符
直接間接引用
指針可以用不同的間接引用層級。雙重指針**。
char *titles[]={"ajj","bbs","klc"}; char **bestbooks[2]; char **english[1]; bestbooks[0]=&titles[0]; bestbooks[1]=&titles[1]; english[2]=&titles[2];
常量和指針
2. C的動內存管理 malloc/realloc/calloc/free
malloc分配的是字節數/ sizeof(字節數)
內存洩漏:丟失內存地址,應該調用free函數沒有調用
迷途指針
3.指針和函數 指針函數/函數指針/程序棧/堆
程序棧(程序棧通常占據區域下部,堆則上部,棧向上生長,堆向下生長)
用指針傳遞數據的一個主要原因就是函數可以修改數據。
4. 函數指針和指針函數
為函數指針聲明一個類型定義會比較方便。類型定義的如下:
typedef int (*funcptr)(int);
funcptr fptr2;
fptr2=square;
......
#include<iostream> using namespace std; int main() { int square(int num); int (*fptr1)(int); //類似於定義變量 typedef int (*funcptr)(int); funcptr fptr2; fptr2=square; int n=5; fptr1=□//此時也可以將其替換為 fptr1=square, 函數名表示函數入口地址 cout<<"5 square is "<<fptr1(n)<<endl; cout<<"5 square is "<<fptr2(n)<<endl; return 0; } int square(int num) { return num*num; }
傳遞函數指針,只要把函數指針聲明作為函數參數(形參)即可。
#include<iostream> using namespace std; int add (int num1,int num2) { return num1+num2; } int sub(int num1,int num2) { return num1-num2; } typedef int (*fptr)(int,int); int compute(fptr operation, int num1,int num2) { return operation(num1,num2); } int main() { cout<<compute(add,5,8)<<endl; cout<<compute(sub,5,8)<<endl; return 0; }
返回函數指針需要把函數的返回類型聲明為函數指針。(注意注釋部分////)
#include<iostream> using namespace std; int add (int num1,int num2) { return num1+num2; } int sub(int num1,int num2) { return num1-num2; } typedef int (*fptr)(int,int); int compute(fptr operation, int num1,int num2) { return operation(num1,num2); } ////////////////////////////////////////////// fptr select(char opcode) { switch(opcode) { case '+':return add; case '-':return sub; } } int evalute(char opcode,int num1,int num2) { fptr operation=select(opcode); return operation(num1,num2); } /////////////////////////////////////////////// int main() { cout<<evalute('+',5,8)<<endl; cout<<evalute('-',5,8)<<endl; return 0; }
使用函數指針數組可以基於某些條件選擇要執行的函數,只要把這些函數指針聲明為數組類型即可。定義如下:
#include<iostream> using namespace std; int add (int num1,int num2) { return num1+num2; } int sub(int num1,int num2) { return num1-num2; } typedef int (*fptr)(int,int); int compute(fptr operation, int num1,int num2) { return operation(num1,num2); } //////////////////////返回函數指針//////////////////////// fptr select(char opcode) { switch(opcode) { case '+':return add; case '-':return sub; } } int evalute(char opcode,int num1,int num2) { fptr operation=select(opcode); return operation(num1,num2); } /////////////////////使用函數指針數組////////////////////////// typedef int (*operation)(int,int); operation operations[128]={NULL}; void initializeopArray() { operations['+']=add; operations['-']=sub; } int evaArray(char opcode,int num1,int num2) { fptr operation; operation=operations[opcode]; return operation(num1,num2); } ///////////////////////////////////////////////////// int main() { initializeopArray(); cout<<evalute('+',5,8)<<endl; cout<<evalute('-',5,8)<<endl; cout<<evaArray('+',5,8)<<endl; cout<<evaArray('-',5,8)<<endl; return 0; }
小結:理解程序棧和堆有助於更深入徹底理解程序的工作方式以及指針的行為。
備注:本文代碼均為Dev C++編譯器編譯