5.C语言指针篇
什么是指针?
- 指针就是内存地址
指针变量
-
简称指针,用于存储指针(即内存地址)
-
定义格式
- 数据类型* 变量名 = &要获取指针的变量
- 数据类型:要跟指向变量的类型保持一致(比如,int a = 10; int * aa = &a;)
- *:标记
-
指针变量占用的大小,跟数据类型无关,只跟编译器有关
- 32位(x86):4字节 64位(x64):8字节
-
给指针变量赋值的时候,不能把一个数值赋值给指针变量
指针的作用
查询/存储数据
- 格式
- *指针名
- *:解引用运算符
int a = 10;
int* p = &a;
printf("%d", *p); // 10
*p = 100;
printf("%d", *p); // 100
printf("%d", a); // 100
作用1:操作其他函数中的变量
#include<stdio.h>
void swap(int* p1, int* p2);
int main()
{
int a = 10;
int b = 20;
printf("前:%d %d\n", a, b);
swap(&a, &b);
printf("后:%d %d\n", a, b);
return 0;
}
// 使用指针交换两个变量里面的数据
void swap(int* p1, int* p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
作用2:在函数中用于返回多个值
#include<stdio.h>
void compare(int arr[], int len, int* max, int* min);
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int max = arr[0];
int min = arr[0];
int len = sizeof(arr) / sizeof(int);
compare(arr, len, &max, &min);
printf("Max: %d\n", max);
printf("Min: %d\n", min);
return 0;
}
// 找出数组中的最大最小值
void compare(int arr[], int len, int* max, int* min)
{
for (int i = 0; i < len; i++)
{
if (arr[i] > *max)
{
*max = arr[i];
}
else if (arr[i] < *min)
{
*min = arr[i];
}
}
}
作用3:将函数的结果和状态分开
#include<stdio.h>
int getR(int a, int b, int* res);
int main()
{
//定义一个函数,求前者对后者的余数,后者有可能是0,此时函数状态异常(0不能作为除数)
int a = 10;
int b = 0;
int res;
int flage = getR(a, b, &res);
if (!flage)
{
printf("余数为:%d", res);
}
return 0;
}
int getR(int a, int b, int* res)
{
if (b == 0)
{
return 1; // 异常
}
*res = a % b;
return 0; // 正常
}
指针运算
- 步长:指针移动一次,走了多少个字节
| 常见数据类型 | 字节数 |
|---|---|
| char | 1 |
| short | 2 |
| int | 4 |
| long | 4 |
| long long | 8 |
#include<stdio.h>
int main()
{
int a = 10;
int* p = &a;
printf("%p\n", p); // 000000FE00FBF844
printf("%p\n", p + 1); // 000000FE00FBF848
printf("%p\n", p - 1); // 000000FE00FBF840
return 0;
}
- 有意义的操作
- 指针跟整数进行加、减法操作(每次移动N个步长)
- 指针跟指针进行减法操作(间隔步长)
- 无意义的操作
- 指针跟整数进行乘除法操作
- 指针指向不明
- 指针跟指针进行加、乘、除操作
- 指针指向不明(或表示不明意义)
- 指针跟整数进行乘除法操作
指向不明的指针
- 野指针
- 指针指向的空间未分配
#include<stdio.h>
int main()
{
int a = 10;
int* p1 = &a;
printf("%p\n", p1); // 000000BD365CF734
printf("%d\n", *p1); // 10
//野指针
int* p2 = p1 + 10;
printf("%p\n", p2); // 000000BD365CF75C
printf("%d\n", *p2); // 189
}
- 悬空指针
- 指针指向的空间已分配,但是又被释放了
#include<stdio.h>
int* method();
int main()
{
int* p1 = method();
printf("---------\n");
printf("函数外:%p\n", p1); // 函数外:0000001D361EF614
printf("函数外:%d\n", *p1); // 函数外:25 相同指针,却得到了不同的数据结果,说明该指针指向空间已被释放
return 0;
}
int* method()
{
int a = 10;
int* p = &a;
printf("函数内:%p\n", p); // 函数内:0000001D361EF614
printf("函数内:%d\n", *p); // 函数内:10
return p;
}
无类型指针
-
void* p;
-
特点:
- 无法获得数据,无法计算,可以接收任意地址
-
应用场景(增强函数的通用性)
//以指针作用1中交换变量数据为例
#include<stdio.h>
void swap02(void* p1, void* p2, int len);
int main()
{
long a = 10L;
long b = 20L;
swap02(&a, &b, 4);
printf("a = %ld\n", a); // a = 20
printf("b = %ld\n", b); // b = 10
return 0;
}
void swap02(void* p1, void* p2, int len)
{
// 步骤1:将通用指针void*转为char*(关键!char*每次操作1字节)
char* p3 = p1;
char* p4 = p2;
char temp = 0; // 临时变量,存单个字节的值
// 步骤2:循环len次(len是要交换的数据的总字节数)
for (int i = 0; i < len; i++)
{
// 步骤3:交换当前指向的1个字节
temp = *p3; // 把p3指向的1个字节的值存到temp
*p3 = *p4; // 把p4指向的1个字节的值覆盖到p3的位置
*p4 = temp; // 把temp里原来p3的值覆盖到p4的位置
// 步骤4:指针后移1字节,指向下一个待交换的字节
p3++;
p4++;
}
}
二级指针和多级指针
-
再次申明
-
指针数据类型:
- 跟指向空间中的数据的数据类型,保持一致
-
int a =10; //一级指针 int* p = &a; //二级指针 int** pp = &p; //三级指针 int*** ppp = &pp; //... -
作用:
- 二级指针可以操作一级指针记录的内存地址
数组指针
-
概念:
- 指向数组的指针,称为数组指针
-
作用:
- 方便操作数组中各种数据
-
实例:
-
#include<stdio.h> int main() { //利用数组指针遍历数组 int arr[] = { 10,20,30,40,50,60,70,80,90 }; int len = sizeof(arr) / sizeof(int); //获得数组指针的两种方式 int* p1 = arr; int* p2 = &arr[0]; for (int i = 0; i < len; i++) { printf("%d\n", *p1++); // 每打印一次数组元素,数组指针便向后移动一步(这里的数组是int型,也就是向后移动4个字节) } return 0; }
-
数组指针的细节
- arr(数组名) 参与计算时,会退化为指向第一个元素的指针
- 特殊情况
- sizeof 运算时,不会退化,arr依旧是一个数组整体
- &arr 获取地址时,不会退化,arr依旧是一个数组整体
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5 };
int* p1 = arr;
int* p2 = &arr;
printf("%p\n", p1); // 0000005E52AFF728
printf("%p\n", p2); // 0000005E52AFF728
//arr(数组名) 参与计算时,会退化为指向第一个元素的指针
printf("%p\n", arr + 1); // 0000005E52AFF72C = p1 + 4 步长:4个字节
//sizeof 运算时,不会退化,arr依旧是一个数组整体
printf("%d\n", sizeof(arr));// 20
//&arr 获取地址时,不会退化,arr依旧是一个数组整体
printf("%p\n", &arr + 1); // 0000005E52AFF73C = p1 + 10 步长:20个字节(数据类型*数组长度)
}
数组指针和指针数组
-
数组指针:指向数组的指针
- int* p1 = arr; 步长:int(4字节)
- int (*p)[5] = &arr; 步长:int * 5(20字节)
-
指针数组:存放指针的数组
- int* arr[5];
- 容易混淆的写法
- int*p[5];
函数指针
- 格式:返回值类型 (*指针名)(形参列表)= 方法名;
- 作用:利用函数指针,可以动态地调用函数
#include<stdio.h>
void method1();
int method2(int num1, int num2);
int main()
{
//定义函数指针
void (*p1)() = method1;
int (*p2)(int, int) = method2;
p1();
printf("-------\n");
int num = p2(10, 20);
printf("%d\n", num);
return 0;
}
void method1()
{
printf("method1\n");
}
int method2(int num1, int num2)
{
printf("method2\n");
return num1 + num2;
}

浙公网安备 33010602011771号