C语言指针详解

1.指针和指针变量

指针 -- 地址 -- 内存单元的编号

指针变量 -- 存放地址的变量

2.指针变量的类型

    指针变量的类型是看指针变量指向的对象是什么类型,假如是int*p,那p的类型就是int*,假如是char*p,那p的类型就是char*的,以此类推

3.指针变量的大小

     CPU和内存之间也是有⼤量的数据交互的,所 以,两者必须也⽤线连起来。想要知道指针变量大小我们就要关注“地址总线”。

    在32位环境和64位环境中指针变量的大小是不一样的,在vs2022中有两种环境,一种是x86(32位)环境,另一种是x64(64位)环境。

    32位机器有32根地址总线, 每根线只有两态,表⽰0,1【电脉冲有⽆】,这就相当于32个bit位,1个字节等于8个bit位,也就是说在32环境下每个指针变量都是4个字节。64位机器有64根地址总线,那每个指针变量都是8个字节。

总结:不管这个指针变量是什么类型的,int*也好,char*也好,大小都是4/8个字节,在64位环境中就都是8个字节,在32位环境中就都是4个字节。

4.指针+-整数

  指针+-整数及表示地址的加减,以以下代码为例,p1和p2中存放的是n的地址,但p1和p2的类型不同,p1是char类型的占1个字节,p2是int类型的占4个字节,将p1+1我们发现地址跳过1个字节,将p2+1则是跳过了4个字节。

  因此我们可以得知指针的类型决定了指针向前或者向后走一步的距离是多少。

5.void*类型的指针

  在指针类型中有一种特殊类型是void*类型的,可以了为无具体类型的指针(也称泛型指针),这种类型的指针可以用来接受任意类型的地址

  如果我们将一个int类型的变量的地址赋值给一个char*类型的指针变脸。编译器会给出一个警告,因为类型不兼容,而使用void*类型就不会有这样的问题。

  但void*类型的指针有局限性,就是void*类型的指针不能直接进行指针的+-整数和解引用的运算。

6.const修饰指针

  变量是可以修改的,如果我们不想某些变量被修改,比如指针变量,我们就可以在指针变量前面加上const,这样子指针变量指向对象的值就不允许被修改,一旦修改,编译器就会报警告。

7.指针运算

  指针运算包括指针+-整数和指针-指针,前者我们前面讲过了,而指针-指针表示一个地址到另一个地址相差多少字节(当然前提是高地址-低地址)

8.野指针

  野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

8.1野指针的成因

(1).未初始化

(2).指针越界访问

(3).指针指向空间的释放

  在 test 函数中,变量 n 是一个局部变量。局部变量的生命周期仅限于定义它的函数内部,当函数执行结束后,该局部变量所占用的内存空间会被释放。

8.2如何规避野指针

(1).指针初始化

  如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL,NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址 会报错。

(2).小心指针越界访问

  ⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是 越界访问。

(3).指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性。

9.assert断言

  assert.h头文件定义了宏arrert(),⽤于在运⾏时确保程序符合指定条件,如果不符合,就报 错终⽌运⾏。这个宏常常被称为“断⾔”。assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零), assert() 不会产⽣ 任何作⽤,程序继续运⾏。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误 流 stderr 中写⼊⼀条错误信息,显⽰没有通过的表达式,以及包含这个表达式的⽂件名和⾏号。

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

9.二级指针

  指针变量也是变量,是变量就有地址,一个用来存放指针的地址的指针变量就是二级指针。

10.指针数组及用指针数组模拟二维数组

  指针数组是数组,数组里面的每个元素都是指针

  运用指针数组我们还可以模拟二维数组

11.数组指针变量

  数组指针变量是一个指针变量,里面存放的是一个数组的首地址,指向一个数组

如何用数组指针实现二维数组传参?答案如下:

二维数组传参的时候我们只需传列数即可,因此是int (*p)[5]

12.函数指针变量

  函数指针变量是一个指针变量,函数指针变量应该是⽤来存放函数地址的,未来通过地址能够调⽤函数。

13.函数指针数组

  函数指针数组是一个数组,里面存放的每个成员都是指针,而这些指针指向的对象是函数,如:int(*p[5])(int x, int y) = { add, sub, mul, div },这里面的add,sub等都是函数名,而函数名就是函数的地址,int和(int x,int y)表示函数的返回类型和参数类型。

13.typedef关键字

  typedef是用来重命名的,可以将复杂的类型名重命名的简单化,这样子我们以后要使用这个类型名的时候敲的也比较方便,例:

  中间的是要重命名的类型名,后面是重命名为什么名字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值