目录
前言
指针编程是C语言的灵魂,通过指针对数组字符串、函数参数、内存地址进行操作,可以使程序更简洁,工作事半功倍。说白了,玩C语言关键就在于玩指针。
一、指针的介绍
指针的定义和初始化示例如下:
/*指针定义:
* 类型说明符 *指针变量名;
* 类型说明符表示指针指向的变量的数据类型,*为指针运算符
* 指针变量只能存放地址类型数据,且只能指向同一种数据类型
*/
int *p1; // 未初始化(野指针:指向一个不确定的内存区域)
char *p2 = NULL; // 初始化为NULL(空指针:目前并未指向任何位置)
float data = 3.14f;
float *p3 = &data; // 初始化为变量的地址,&为取址运算符
printf("data:%f", data); // 直接访问
printf("data:%f", *p3); // 间接访问
printf("&data:%p", &data); // 打印变量地址
printf("&data:%p", p3);
二、段错误(Segment fault)
在编译完程序执行时,有时会莫名出现“Segment fault”提示,通常是指访问的内存超出了系统分配给这个程序的内存空间。常见原因如下:
1、操作空指针
2、操作地址不存在的内存
3、操作受系统保护的内存
4、修改常量区中的内容
/*操作空指针可能会出现段错误*/
int *p1 = NULL;
printf("*p1:%d\n", *p1);
/*操作野指针可能会出现段错误*/
int *p2;
printf("*p2:%d\n", *p2);
*p2 = 100;
/*指针指向一个错误的内存地址可能会出现段错误*/
int *p3 = (int*)0x123ef;
printf("*p3:%d\n", *p3);
常见避免方式:
1、变量、数值、指针等均要做初始化
2、数值不要越界操作
3、通过指针不要随意去操作不存在或受系统保护的内存
常见解决方式:
1、通过不断地注释代码来缩小段错误出现的范围
2、利用GDB调试器来查找段错误
3、通过学习前人的经验和开发的工具
三、指针运算
/*运算符*/
// 两个表达式等价,指针运算符*是取址运算符&的反运算符
a = 10;
*(&a) = 10;
/*赋值运算*/
// 指针赋值实际上是地址的复制
// 左值代表存储单元,右值代表存储内容
int a = 10;
int *p1 = &a;
int *p2;
p2 = p1; // p1和p2指向同一变量a
/*加减运算*/
int a[] = {1, 2, 3, 4, 5};
int *p = a; // 指向数组的指针,数组名是数组首元素的地址
p = p + i; // 指向当前元素后第i个元素
p = p - i; // 指向当前元素前第i个元素
/*比较运算*/
// 前提是两个指针都指向一个数组中的元素,不同内存区域的指针比较没有意义
p_a < p_b; // 如果a存储在b的前面,则返回true
p_a <= p_b; // 如果a存储在b的前面或两个指针指向同一位置,则返回true
p_a == p_b; // 如果两个指针指向同一位置,则返回true
p_a != p_b; // 如果两个指针指向不同位置,则返回true
p_a == NULL; // 如果a是空值,则返回true
/*指针相减*/
// *(a + i)(指针法)等价于a[i](下标法)
int a[] = {1, 2, 3, 4, 5};
int *p1 = a;
int *p2 = a + 4;
printf("%d", p2 - p1); // 打印两个元素之间相差的存储单元个数
四、函数传参
1、值传递
数据传送是单向的,只能把实参传递给形参,形参的变化不会影响实参。
2、地址传递(指针传递)
形参指针的变化不会影响实参指针,但可以通过形参指针修改实参指针所指向的存储单元中的值。
void swap (int *p1, int *p2) // 交换两个整数
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
五、数组传参
实参 | 形参 |
---|---|
数组名 | 数组名 |
指针 | 数组名 |
数组名 | 指针 |
指针 | 指针 |
六、二级指针
二级指针也称为指针的指针,指向另一个指针变量。
int a = 10; // 变量
int *p = &a; // 一级指针
int **pp = &p; // 二级指针
七、常量指针和指针常量
1、常量指针
常量指针本身可以被修改,它所指向的存储单元的值不可以修改。通过其他指针可以修改常量指针所指向的存储单元的值。常量指针通常作为函数的形参使用。
类型说明符 const *指针变量;
2、指针常量
指针常量本身不可以被修改,它所指向的存储单元的值可以修改。通过二级指针可以修改指针常量本身。
类型说明符 * const 指针变量;
3、指向常量的指针常量
指针本身不可以被修改,它所指向的存储单元的值不可以修改。通过其他指针可以修改指针本身,也可以修改指针所指向的存储单元的值。
类型说明符 const * const 指针变量;