1.认识指针
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; }
小结:理解程序栈和堆有助于更深入彻底理解程序的工作方式以及指针的行为。