一指针简介
指针是 C 语言的灵魂, C 语言之所以强大, 很大一部分原因在于对指针的灵活运用我们无论需要对内存的精准分配和释放, 还是对接口 api 的使用, 乃至面向对象中的类和对象的封装, 都涉及到了指针 C 语言的指针大致可以分为两种, 一种是作为一个变量, 其保存的是一段内存地址, 也就是本文要谈的多级指针; 另一种是作为一种数据类型, 像函数指针, 用于引出一种类型, 主要用于回调函数
二指针与基础数据类型
从内存的角度看, 数据类型就是一段固定大小内存块的别名
int a=0;
int 在 32/64 位操作系统中都是占用 4 个字节, 这段简单的代码相当于告诉编译器, 让操作系统在栈区分配一块占 4 个字节的内存块, 命名为 a, 并且初始化为 0,a 为变量名
因此我们可以将这块内存的地址赋值给一个指针变量
int* p=&a;
即 p 保存了 a 的地址, 通过 * p 可以间接的改变 a 的值而这样修改最大的好处是在于在函数调用中, 或者说在不同模块中能够修改 a 的值下面讲讲在开发中遇到的情形
- char* p=NULL;
- char buf[32]="key1= value";
假设上述代码是在主调函数中定义的, 那么指针 p 在向 NULL, 意味着我们希望能在被调用分配内存, 然后使 p 指向所分配的内存空间, 那么此时就需要使用二级指针来存放 p 的地址了, 假设我们需要设计一个去除字符串中的空格的函数, 那么其接口如下
- int ReSpace(char* p1,int len,char** p2,int* len2)
- {.....}
调用方法:
- char buf[32] = "key1= value";
- char* p = NULL;
- int len1 = strlen(buf);
- int len2 = 0;
- ReSpace(buf,len1,&p,&len2)
即函数将去除空格的字符串通过 p 传出来了同时二级指针也可以记录字符数组, 或者二位数组的内存地址因此也可以推出三级指针甚至是多级指针的用法了, 即用来修改二级指针的值
三指针与结构数据类型
1 结构体类型:
有以下一段代码
- typedef struct _SCK_HANDLE
- {
- char version[64];
- char ip[128];
- int port;
- unsigned char *p;
- int plen;
- }SCK_HANDLE;
- void main()
- {
- SCK_HANDLE *hdl = NULL;
- hdl = (SCK_HANDLE *)malloc(sizeof(SCK_HANDLE));
- }
即声明了一个结构体类型的指针, 并且给它分配了内存空间, 那么就可以将 hdl 指针作为一个参数传递给其他模块来改变这块内存中的值
2 数组指针
初学 C 语言往往很难理解数组指针, 也很容易和指针数组相混淆, 事实上, 如果只要明白数组指针就是一个行指针, 指向的是一个数组, 保存的是一个数组的地址它的步长是数组的列数
- int c[5];
- int (*pointer)[5] = &c;
- int buf[10][30];
- int (*p)[30]=buf; // 指向二维数组的首行
四使用指针时常见的错误
1 用指针修改内存中的值时, 应该确保所指的值能够被修改如:
- char* p="abcdefg";
- p[0]=w; // 错误, 指向的是常量区的字符常量
2 注意深拷贝和浅拷贝, 即应该明确用指针分配了多少内存空间, 以免出现重复释放内存的问题
3 指针的步长问题
指针步长和其存放的数据类型有关, 每移动一步, 编译器都会乘以其存放数据类型的长度, 相当于移动到下一个数据
4sizeof 指针 求的是指针变量所占的内存, sizeof 数组名 求的 是数组所占的内存
5 避免出现野指针, 即释放指针所指的内存空间后, 将指针置 NULL
总结
指针是 C 语言中很细致的一个语法, 再怎么说也说不完指针的所有应该场景但是我们只要抓住它的根本, 即从内存的角度去理解, 分析, 那么它就变得很好理解我们在平时的学习中, 多去应用它, 学习指针的思想, 站在内存的角度去思考, 那么整个 C 语言的学习都会有很大的提升
来源: http://www.bubuko.com/infodetail-2546261.html