火影 发表于 2025-4-4 20:53:04

【C语言入门】由浅入深学习指针 【第二期】

 
目录
 1. 指针变量为什么要有类型?
2. 野指针
2.1 未初始化导致的野指针
2.2 指针越界导致的野指针
2.3 怎样规避野指针 
3. 指针运算
3.1 指针加减整数
3.2 指针减指针
3.3 指针的关系运算
4. 二级指针
5. 指针数组
5.1 怎样使用指针数组模拟二维数组
           上一期已经解释了指针和指针变量的区别以及含义,这一期我们来具体相识一下指针到底有什么作用。
 1. 指针变量为什么要有类型?

        我们知道指针变量的大小是根据地点平台决定的,若平台是32位即x86环境,则指针变量是4个字节,若平台是64位,则指针变量是8个字节。既然指针变量不会根据指针类型变革,那么我们为什么要区分指针变量的类型呢?换句话说char* 和 int* 都有能力存储4个字节的地址,为什么不统一成一个自定义的指针变量例如ptr* ?
https://i-blog.csdnimg.cn/direct/62088f9cca4e417abc0a5df89d227724.png
        从上图可以得知,我们把int*类型的地址强行赋给char*类型的地址,再举行取值调用的时候,会根据char*来举行赋值,以至于只会将一个字节赋值成0,如果正常使用int*来接收,那么四个字节都是0 ,如下图所示。
https://i-blog.csdnimg.cn/direct/5cbd72414ecf431b8319b2ad2fd484a8.png

        由下图可知,虽然不同指针变量的存储类型不影响地址的存储,但是当直接对地址举行运算,还是会根据指针类型的不同举行运算。char*类型+1,跳过1个字节,int*类型+1,跳过4个字节。
https://i-blog.csdnimg.cn/direct/189a7d7fdb554f5586478fd1367ae461.png
所以我们会得到这样的结论:指针变量的类型在存取地址的时候可有可无,在修改地址指向的内容的时候是非常有必要的,它决定了在利用地址更改值的时候必要更改多少个字节;若直接对地址举行运算,那么会根据指针变量的类型+‘1’,这个‘1’大概是char类型的一个字节,也大概是int类型的四个字节。 

使用float*和int*的时候,无论是访问内存还是使用内存,都是4个字节,那么可不可以混用呢?
答案是:不可以。
下图是整型解引用赋值整型,我们可以看到100以16进制存入内存。
https://i-blog.csdnimg.cn/direct/a7d2412dba6d46de95a961bddaa3d050.png
我们把100.0存入内存,发现内存存的数据发生了变革, 虽然都是100,但是浮点数存入内存的方式是不同的。
https://i-blog.csdnimg.cn/direct/de6d097e0f3e4aeab8199463e8fbd183.png

2. 野指针

        指针指向的内存没有初始化,大概已经被销毁,此时的指针称为野指针。
2.1 未初始化导致的野指针

https://i-blog.csdnimg.cn/direct/7fb0bcb474be47f086915df9b22af87c.png
2.2 指针越界导致的野指针

https://i-blog.csdnimg.cn/direct/aa0865b5817142729410ea9b2609003b.png

2.3 怎样规避野指针 

①指针初始化。
②指针小心越界。
③指针指向的空间置为NULL。NULL是0,类型是void*,如果取值的话一定会报错(默认0地址不能访问),所以,我们可以先判断这个指针如果不是NULL再举行取值。
https://i-blog.csdnimg.cn/direct/2f1d1c76aca944a3bb3e7a8a0fca1079.png
https://i-blog.csdnimg.cn/direct/31c17c0bdb5e4ef5a6ab200d179fe4f3.png
④制止返回局部变量的地址,由于局部变量已经被销毁了(没有那块内存空间的使用权限了)。
⑤指针使用之前检查有效性。

3. 指针运算

3.1 指针加减整数

这里的values并不算下标越界,由于并没有使用这段内存,只是用了一下这个地址作为判断条件。
https://i-blog.csdnimg.cn/direct/1392a5490f92470b9b278e204797740c.png
3.2 指针减指针

当同类型的地址减去同类型的另外一个地址,得出的结果的绝对值是两个地址之间的元素个数。
https://i-blog.csdnimg.cn/direct/051ad4c7b8124788b33d36c729d7ec7c.png

必要注意的是,两个指针指向的必须是同一块内存,否则毫无意义。
https://i-blog.csdnimg.cn/direct/3e316c89f4f640bfa8f9dd191c310bbb.png

        那么有同砚会想,指针+指针得到的结果是什么呢,这个结果毫无意义,类似于你可以把日期相减,得到天数,但是你不能把日期相加,这样就毫无意义。
3.3 指针的关系运算

实在就是地址之间的比较,判断两个地址谁大谁小,从而对地址指向的内容举行操作。
https://i-blog.csdnimg.cn/direct/ed9f32d31bf14255a75e450a24540f83.png

4. 二级指针

        简单描述一下,就是指针变量里面存的地址,这个地址是一个指针的地址。乍一听是不是以为在说绕口令呢?下面用一张图来举行诠释。
https://i-blog.csdnimg.cn/direct/f91d1d5409a846c697ba76339fb796a6.png
        上图中表现int * pa = &a;我们可以这么明白:*号表明pa的类型是一个指针类型,int表明这个指针类型指向的是int类型;那么我们是不是可以来明白一下二级指针。
https://i-blog.csdnimg.cn/direct/034af894f37943878d44be760bd3eaef.png
        int* *ppa = &pa;还是将类型拆开,间隔ppa最近的*表明ppa是一个指针,int* 表明ppa指向的类型是int*的类型。
总结:二级指针是用来存放一级指针变量的地址。
5. 指针数组

主语是数组,即存放指针的数组就是指针数组。
https://i-blog.csdnimg.cn/direct/c652dc4a13734d3ca86adeab60942a8b.png

5.1 怎样使用指针数组模拟二维数组

        首先构造出三个一维数组,所谓二维数组就是将这三个一维数组连起来;我们构造一个指针数组,分别存入之前构造的一维数组名,在之前的帖子说明,一维数组名是数组的第一个元素的地址,所以分别存入了三个地址,我们必要遍历指针数组,得到三个一维数组的首地址,再引入一个变量j,根据指针加减法,就可以访问一维数组中除了第一个元素的其他元素的地址,最后解引用就可以得到最后的结果。
#include <stdlib.h>


int main()
{
    int arr1 = {1,2,3,4};
    int arr2 = {2,4,6,8};
    int arr3 = {3,6,9,12};
// 用一维数组模拟出二维数组的效果
    int* arr_sum = {arr1,arr2,arr3};
    for(int i = 0;i < 3;i++)
    {
      for(int j = 0;j < 4;j++)
      {
            printf("%d ",*(arr_sum + j));
      }
      printf("\n");
    }
    return(0);
} https://i-blog.csdnimg.cn/direct/d03af608f7ed49319cc3d57168fe92da.png


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【C语言入门】由浅入深学习指针 【第二期】