作者:余小小
日期:2021-10-02
指针概念
-
每一个变量都有一个内存位置
-
每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。
-
指针的接收符号:%p
-
定义指针变量:新号
-
指针的获取方式: & 运算符(地址运算符)
为了方便读懂,我这里改了改demo的变量名字
#include <stdio.h>
int main ()
{
int demo = 10;
int *zhizhen; // 定义指针变量
zhizhen = &demo;
printf("demo 变量的地址: %p\n", zhizhen);
return 0;
}
代码分析:
-
启动程序,执行main函数
-
定义了一个叫做demo的变量,值是10,在内存中开辟了一处空间,放了这个值,并且给这个空间的地址赋予了一串十六进制的代码,类似于你游戏的激活码
-
定义了一个指针变量,一定要注意这里的*号,是区别指针和基本数据类型的变量的依据。
-
定义的指针变量的初始值,这里暂时不考虑
-
给定义的指针变量的指针赋值,赋予的是demo变量的地址值(不是demo的值哦)
-
打印输出,结束
什么是指针?
-
指针也就是内存地址
-
完整的指针变量是有带了个新号的哦
-
指针变量的变量名是用来存放内存地址(变量指针)。变量指针,是指针变量没有新号的变量
-
指针变量是用来存储指针所在的位置的值(指针变量)
-
要注意,和其他变量的区别是一个新号
-
指针也是有数据类型的,不是的单独的一个数据类型
就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。
指针的声明语法伪代码:
数据类型 *指针变量名字;
int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */
不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。
指针和值没有关系,和地址关系
使用指针
#include <stdio.h>
int main ()
{
int var = 20; /* 实际变量的声明 */
int *ip; /* 指针变量的声明 */
ip = &var; /* 在指针变量中存储 var 的地址 */
printf("var 变量的地址: %p\n", &var );
/* 在指针变量中存储的地址 */
printf("ip 变量存储的地址: %p\n", ip );
/* 使用指针访问值 */
printf("*ip 变量的值: %d\n", *ip );
return 0;
}
可以看到指针的值和地址值是一样的哦
NULL 指针
-
赋为 NULL 值的指针被称为空指针。
-
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。
-
NULL 指针是一个定义在标准库中的值为零的常量
#include <stdio.h>
int main ()
{
int *ptr = NULL;
printf("ptr 的地址是 %p\n", ptr );
return 0;
}
-
每个编译器的结果不一样哦,我这里是十进制的0
-
如果简写,则是0x0,0x(数字零和字母x)代表十六进制
-
大多数的操作系统上,程序不允许访问地址为 0 的内存
-
因为该内存是操作系统保留的。
-
然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。
-
但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
检查空指针
在其他语言中,我们习惯的直接判断变量,比如在前端js中,最常用的就是用if直接判断变量是否存在,存在则执行某些东西,也是用到指针判断。其实就是判断地址是否存在。
if(ptr) /* 如果 p 非空,则通过 */
if(!ptr) /* 如果 p 为空,则通过 */
指针的算术运算
-
指针因为也是一个数值,所以可以执行数值可以执行的 各种运算,比如四则运算等等
-
指针的每次运算的单位,都是根据当前的数据类型,比如一个int字节是4个字节,short,是2个字节,char是1个字节,double是8个字节,float是4个字节,汉字是3个字节,long是8个字节。
-
指针的每一次递增,它其实会指向下一个元素的存储单元。
-
指针的每一次递减,它都会指向前一个元素的存储单元。
假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数
ptr++
在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 字节。
这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。
所以说,
-
指针的跳跃范围,一定要看数据类型
-
指针的跳跃范围,一定要看数据类型
-
指针的跳跃范围,一定要看数据类型
递增一个指针
在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量。
数组变量名字就是装的数组第一个元素的地址值
#include <stdio.h>
const int MAX = 3;
int main ()
{
int var[] = {10, 100, 200};
int i, *ptr;
/* 指针中的数组地址 */
ptr = var;
for ( i = 0; i < MAX; i++)
{
printf("存储地址:var[%d] = %p\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr );
/* 指向下一个位置 */
ptr++;
}
return 0;
}
代码解析:
-
动态初始化了一个数组
-
定义了一个和数组相同数据类型的变量i,和指针变量ptr
-
直接将数组的第一个元素的地址赋值给了指针变量ptf(没有用到地址符号,因为数组的名字就是装的元素的首位地址)
-
直接循环遍历
-
打印出地址的值(十六进制的,我们看不懂,所以这里暂时没有参考意义),注意,这里是用的变量指针
-
打印数组存储属性的值:这里使用的指针变量,则是变量,装的是当前指针指向的地址中的值
-
指针跳跃:按照数据类型进行跳跃,这里是int类型,所以一次跳跃4个字节,但是是直接跳跃到下一个指针的位置,从索引来看,则是跳跃了1个距离。
指针的比较
指针可以用关系运算符进行比较
如 ==、< 和 >。
如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
#include <stdio.h>
const int MAX = 3;
int main (){
int var[] = {10, 100, 200};
int i, *ptr; /* 指针中第一个元素的地址 */
ptr = var;
i = 0;
while ( ptr <= &var[MAX - 1] )
{
printf("存储地址:var[%d] = %p\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr );
/* 指向上一个位置 */
ptr++;
i++;
}
return 0;
}
代码分析:
-
定义了一个数组
-
定义了一个变量
-
定义了一个指针变量
-
将数组的首位地址,赋值给变量指针ptr
-
使用循环遍历,条件是指针变量是在数组的元素地址之内,简单 的说,就是变量指针的跳跃范围,是在数组元素地址所在的范围之内
-
以为变量指针的初始值是数组的第一位元素的地址,所以我觉的应该是跳跃到下一个指针的位置哦
函数指针
-
函数指针 是指向函数的 指针变量。
-
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
-
函数指针可以像一般函数一样,用于调用函数、传递参数。
-
函数指针,是函数
-
指针函数,是指针
-
函数的名字,也是存储的函数地址值
-
指针变量,是指针
-
变量指针,是变量
-
使用函数指针或者变量指针,或者是xxx指针,都是不用带星号的,因为不是当作指针来使用,都是当作原来的数据来使用。
函数指针的格式
返回值类型 (*函数指针名字)(传入参数的数据类型); // 声明一个指向同样参数、返回值的函数指针类型
#include <stdio.h>
int max(int x, int y){
return x > y ? x : y;
}
int main(void){
/* p 是函数指针 */
int (* p)(int, int) = & max; // &可以省略
int a, b, c, d;
printf("请输入三个数字:");
scanf("%d %d %d", & a, & b, & c);
/* 与直接调用函数等价,d = max(max(a, b), c) */
d = p(p(a, b), c);
printf("最大的数字是: %d\n", d);
return 0;
}
-
函数指针和直接调用函数一样
回调函数
执行一个函数后还要执行一个你规定的函数,比如定时炸弹,时间到了,炸弹就触发了
触发炸弹,就是用 的指针来触发,是通过传入指针函数来触发实现触发炸弹的函数指针
#include <stdlib.h>
#include <stdio.h>
// 回调函数
void dingshizhadan(void (*didi)(void))
{
printf("定时炸弹开始启动了\n");
// 调用传入函数指针
didi();
}
// 获取随机值
void chufa(void)
{
printf("炸弹触发,啵啵啵\n");
}int main(void) {
dingshizhadan(&chufa);
return 0;
}
-
我是参考其他教程来写,这里的main中的括号中的void可写可不写,每个c的版本不一样,有些语法规则有点点不同,不影响的哦
-
我之类先调用了定时炸弹的函数,传入的是一个函数的地址,建议在刚开始学习的时候,把地址符号加上
-
在回调函数中,我传入了一个自定义的dd指针函数参数。记住了哦,我这里是传入的指针哦(地址)
-
括号里的void可以不用管哦,因为我也没带有参数。
-
暂无评论内容