C语言:指针1

 

目录

指针变量和地址

取地址操作符

指针变量的大小

指针变量类型意义

指针解引⽤

指针的 + - 整数

const修饰指针

const修饰变量

const修饰指针变量

指针的运算

指针+ -整数

 指针的关系运算

野指针

指针未初始化

 指针越界访问

指针指向的空间被释放了

避免野指针

assert断言

传值调⽤和传址调⽤

传值调用

传址调用


下面这一张图,我们可以看到a初始化为20 ,int* p指向a的地址

指针变量和地址

取地址操作符

&取地址操作符可以取出一个变量的地址

下面在32位环境下打印地址,我们可以看到取出a的地址打印

下面这张图,我们在编译过程中,我们也可以查看内存

指针变量的大小

在32位环境下有32根地址总线4X8=32

32位平台下地址是32个bit位,指针变量⼤⼩是4个字节?

在64位环境下有64根地址总线8X8=64

64位平台下地址是64个bit位,指针变量⼤⼩是8个字节

指针变量类型意义

指针解引⽤
int a=20;
int *p = &a;//p指向a的地址
*p = 99;//通过解引⽤把地址变成20,然后进行修改

上面这*p指向的是a的地址,然后再通过解引⽤把地址变成20,然后进行修改成99


下面这代码p如果不解引⽤那么p就是修改int *p指向的地址

int a = 10;
int b = 20;
int *p = &a;//p指向a的地址
p = &b;//这个是修改p指向的地址
//上面修改了p指向的地址,那下面这个修改的就是 b 的数值了
*p = 0;


下面我们可以看到地址是倒着存放的,int是4个字节,11,22,33,44刚刚好4个

每次编译或执行编译器都会重新分配内存空间

当我们执行*p = 0的时候,我们可以发现全部变成0了,因为int *是4个字节。

下面是char *我们可以发现只改了一个地址,因为char *是一个字节

指针的 + - 整数

下面这代码,我们可以看到int *p是int类型的也就是4个字节

p+1我们可以看到往后跳了4个

char * cp是char类型的也就是1个字节

cp+1我们可以看到往后跳了1个

往后跳多少取决于类型是多少,如果类型是8个字节那么就往后跳8个

const修饰指针

const修饰变量

我们可以发现被const修饰变量不能被修改,拥有了常属性

a拥有了常属性,但是不能当常量使用,会报错


我们可以发现被const修饰的变量,用指针的方式通过地址解引⽤后进行修改

举个例子一个房间里大门被const修饰进不去了,可以通过指针也就是翻窗户进去

我们可以发现const也把指针修饰了,也就是说把窗户也关起来了,谁都进不去了

const修饰指针变量

const修饰指针,const在 * 号前面那么数值就不能修改了

const在*号后面的话,地址不能被修改了

指针的运算

指针+ -整数

下面,我们可以发现int *p指向数组首元素地址,for循环通过数组首元素地址加1一直访问到最后一个元素

指针-指针

我们可以看到char* x指向p的首元素地址

然后while循环,每次循环加1,加1跳过类型大小,访问到下一个地址

加到‘\0’停止,每个字符串后面都会有'\0','\0'也是字符串的结束标志

p加到\0停止到了最后一个元素,然后通过最后一个元素的地址减去首元素地址,就可以拿到总共有多少个元素了

 指针的关系运算

野指针

野指针就像一只疯狗,不把狗栓在树上很危险

指针未初始化

指针未初始化那么指针默认就是随机值

 指针越界访问

数组只有10个元素,用指针越界访问到第12个元素,就会成野指针了

指针指向的空间被释放了

下面这个可以运行,但是也是个野指针,很危险

这个函数,返回了n的地址后,这个函数的空间就被释放了,p指向了一个被释放的空间,就是野指针了

避免野指针

当指针没有地址初始化,我们只需要给个NULL就可以避免野指针了

assert断言

使用assert函数我们需要下面这个头文件

#include <assert.h >

assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报
错终⽌运⾏。这个宏常常被称为“断⾔”

用assert可以判断p是不是NULL是NULL就报错并且显示在第几行

p不为空就往下执行

assert() 的使⽤对程序员是⾮常友好的,使⽤ assert() 有⼏个好处:它不仅能⾃动标识⽂件和
出问题的⾏号,还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问
题,不需要再做断⾔,就在 #include <assert.h> 语句的前⾯,定义⼀个宏 NDEBUG 。

如果是我们想让assert全部失效我们可以添加下面这个头文件

#define NDEBUG

然后,重新编译程序,编译器就会禁⽤⽂件中所有的 assert() 语句。如果程序⼜出现问题,可以移
除这条 #define NDBUG 指令(或者把它注释掉),再次编译,这样就重新启⽤了 assert() 语
句。


我们可以看到p是NULL,加上这个头文件,assert失效了,如果有多个assert那么全部失效

当然我们在Release环境下执行会自动过滤assert

传值调⽤和传址调⽤

传值调用

传值调用就是传数值到函数里

下面这代码,在函数里交换后就释放了,

传址调用

传值调用就是传地址解引⽤进行交换,通过地址进行的交换,空间释放了,不会影响地址

  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值