【C语言】指针进化 !!!

简介: 【C语言】指针进化 !!!

前言

🎈大家好,我是何小侠🎈

🍃大家可以叫我小何或者小侠🍃

💐希望能通过写博客加深自己对于学习内容的理解💐

🌸也能帮助更多人理解和学习🌸

兰生幽谷,不为莫服而不芳。舟在江海,不为莫乘而不浮。君子行义,不为莫知而止休。— 出自《淮南子·说山训》

解释:兰花生长在无人的山谷,不会因为没人佩戴而不散发芳香;船在江河湖海上,不会因为没有人乘坐而不浮在水上;君子行使自己的道义,不因没有人理解而停止。


    这篇博客我们将会深入的理解指针和学习指针的用法

    字符指针⁉️

    1. 字符指针最基本的用法如下。
    int main()
    {
      char ch = 'w';
      char* p = &ch;
      *p = 'a';
      return 0;
    }
    

    这确实是一个本基本的代码我们都会使用。

    我们看看在内存中是怎么变化的。

    6518aead4f974d5aa16b63f8ab9ae038.png

    首先将’ w ‘的对应的ASCII值存在ch中,然后用 p这个指针变量存放ch的地址,通过给解引用p赋值,成功改变ch中的字符由’ w ‘变成’ a ’

    e3c1cd60c6f14b25b7645c83013834f8.png

    当然这都是16进制的表示方法,自己算一算便可知道。

    1. 字符指针的第二种用法。
    int main()
    {
      char* p = "abcdefg";
      printf(p);
      printf("\n%c", *p);
      return 0;
    }

    我们看第一行代码时要注意,这里是将一个常量字符串"abcdefg"的首地址放在了p中,我们通过这个首地址找到这个常量字符串。并不是把这个字符串放在p里面。

    那么打印的结果就应该是 :

    abcdefg

    a

    528e1944ab0446059dd486fcd6ce2611.png

    没错确实是这样。

    那我们是否能够改变*p的内容呢?

    int main()
    {
      char* p = "abcdefg";
      printf(p);
      printf("\n%c", *p);
      *p = 'w';
      printf("\n%c", *p);
      return 0;
    }

    其实 * p = ‘w’;这种写法是不对的,为什么呢?因为我们的"abcdefg"是一个常量字符串常量字符串是不能够修改的!!

    指针数组🐽

    我们都知道,整型数组是存放整型的数组,字符数组是存放字符的数组

    那么指针数组就比较明显,肯定是存放指针的数组。

    1. 那么它的一般形式是什么呢?
    int main()
    {
      char* pc = "abcde";
      char* p1 = pc;
      char* p2 = pc+1;
      char* p3 = pc + 2;
      char* p4 = pc + 3;
      char* p5 = pc + 4;
      char* p[5] = { p1,p2,p3,p4,p5 };
      for (int i = 0; i < 5; i++)
      {
        printf("%c\n", *p[i]);//[]先结合,因为优先级最高。
      }
      return 0;
    }

    我们为了与上面的字符指针对应,例子举的相似一点。

    我们知道p1 ~ p5 存储的就是对应的abcde的地址,而类型决定应该放什么元素,而这里指针数组是字符指针数组,所以类型就是char *.

    我们想一下,在我们传参的时候,arr数组名就是用char * 来接受的,为什么呢?就是因为实参就是地址,char * 类型也就是需要地址来作为数组元素,那么这里的初始化就应该很好理解了。

    031499bbd15f43babf7d0f42a4013239.png

    1. 但是我们一般会这样来使用它
    int main()
    {
      int arr1[] = { 1,2,3,4,5 };
      int arr2[] = { 2,3,4,5,6 };
      int arr3[] = { 3,4,5,6,7 };
      int* p[3] = { arr1,arr2,arr3 };
      int i = 0;
      int j = 0;
      for (i = 0; i < 3; i++)
      {
        for (j = 0; j < 5; j++)
        {
          printf("%d", *(*(p + i) + j));
        }
        printf("\n");
      }
      return 0;
    }

    9d8ba094928d49c5801931040f999cb8.png

    我们这里要讲的是最后的输出部分

    printf("%d", *(*(p + i) + j));

    这里为什么要这样写呢?还有没有其他写法?

    我们知道arr[3] = *(arr +3); 为什么呢? arr[3]其实是下标为3的元素,那么

    arr+3就是下标为3的元素的地址,我解引用不就是这个元素吗?

    这里也差不多。

    b5b7abc2432c42beb75ab8b6e8853220.png

    我们可以这样理解,先看成是一个一维数组,那么*(p+i)不就是拿到arr1,或者arr2,arr3的地址吗?加入我们拿到arr1的地址。

    8b1c22c9437b423d9d547e12685afd80.png

    那么*(p )就是arr1这个数组的首地址, * (arr1+j)也就很明显了。

    那么我们换一种写法呢?

    这样写:*( p[ i ]+j )

    48138223f53842a180065bc75b8df4fa.png

    这样写:p[ i ][ j ]

    dd51d110e2c7499e97b8e4398d14fb95.png

    为什么可以当作二维数组看呢?因为二维数组其实也可以理解为多个一维数组的拼接。但是我觉得还是我上面描述的要更清晰一些。

    这样写: (*(p + i))[ j]

    数组指针🦑

    我们上面讲的是指针数组,是数组。因为最后是数组这个名词,而数组指针是指针,是指向数组的指针。

    1. 区分指针数组和数组指针
    int *p1[10];
    int (*p2)[10];
    //p1, p2分别是什么?

    p1是指针数组,为什么呢?我们讲过,p1先与[ ]结合确认是一个数组,再与结合说明是指针数组。
    而p2就是我们要讲到的数组指针,用()让
    p2 优先结合说明是一个指针,然后确认指针类型,是int [ 10 ],也就是数组指针

    &数组名与数组名的区别

    这真的是一个非常重要的知识点。

    我们先来看一段代码

    int main()
    {
      int arr[] = { 1,2,3,4,5,6 };
      printf("%p\n", arr);
      printf("%p\n", arr+1);
      printf("%p\n", &arr);
      printf("%p\n", &arr+1);
      return 0;
    }
    

    我们用计算机一算便知。

    这里为什么是这样呢?

    • 实际上&arr,取出的是整个数组的地址,整个数组的地址+1也就应该跳过一个数组。
    • arr是首元素地址,+1当然只会跳过一个元素。
      大家觉得这和我们的指针是不是有点类似呢?
      我们知道 arr传参我们可以用 int * arr这个指指来接受,这个我们已经是老生常谈了,上面也解释过了。
      那么&arr用什么来接收?
      当然用数组指针
      整型指针变量存储的是一个整型元素的地址!
      那么数组指针变量应该存储的是数组的首元素地址,由于类型是数组指针,+1当然就会跳过一个数组的大小。

    那么我们就可以得出结论,&arr的数组名就是 int (*p)[ ]。

    数组指针的用法

    int main()
    {
        int arr[10] = {1,2,3,4,5,6,7,8,9,0};
        int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
        //但是我们一般很少这样写代码
        return 0;
    }

    我们一般这么写。

    void print(int(*p)[5],int i ,int j )
    {
      for (i = 0; i < 3; i++)
      {
        for (j = 0; j < 5; j++)
        {
          printf("%d ",(*(p+i))[j]);//不要写成 *p+i,
          //因为*比加号的优先级要高
          //printf("%d ", *(*(p + i) + j));
        }
        printf("\n");
      }
    }
    int main()
    {
      int arr[][5] = { {1 ,3 ,4} ,{2,3,4,5,6}, {1,2,3,4} };
      print(arr,3,5);
      return 0;
    }

    可能有点跳跃不过没有关系,为什么二维数组传首地址能够用数组指针接收呢?
    我们知道二维数组的数组名代表第一行的地址,第一行就相当于是一个一维数组,所以说可以。

    学了指针数组和数组指针我们来一起回顾并看看下面代码的意思 :

    int arr[5];
    int *parr1[10];
    int (*parr2)[10];
    int (*parr3[10])[5];
    1. 是一个普通的整型数组,5个元素,每个元素是int
    2. 是一个指针数组,存放的是整型指针,每个元素是int *
    3. 是一个数组指针,指向的是整型数组,数组每个元素是int
    4. 是一个指针数组,指针的类型是数组指针,也就是说是一个存放指向数组的指针的数组

    总结🍊

    这篇博客值得我们学习了指针进化的第一部分,后续还有几部分我也会陆续发出来,请大家期待。

    最后如果这篇博客有帮助到你,欢迎点赞关注加收藏

    如果本文有任何错误或者有疑点欢迎在评论区评论


    目录
    相关文章
    |
    2月前
    |
    C语言
    【c语言】指针就该这么学(1)
    本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
    52 0
    |
    10天前
    |
    存储 NoSQL 编译器
    【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
    指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
    58 3
    【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
    |
    10天前
    |
    存储 编译器 C语言
    【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
    在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
    35 9
    |
    10天前
    |
    安全 程序员 C语言
    【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
    在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
    32 7
    |
    20天前
    |
    存储 C语言
    C语言如何使用结构体和指针来操作动态分配的内存
    在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
    81 12
    |
    13天前
    |
    存储 程序员 编译器
    C 语言数组与指针的深度剖析与应用
    在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
    |
    14天前
    |
    算法 C语言
    C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
    本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
    45 3
    |
    14天前
    |
    存储 算法 程序员
    C 语言指针详解 —— 内存操控的魔法棒
    《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
    |
    20天前
    |
    存储 C语言 开发者
    C 语言指针与内存管理
    C语言中的指针与内存管理是编程的核心概念。指针用于存储变量的内存地址,实现数据的间接访问和操作;内存管理涉及动态分配(如malloc、free函数)和释放内存,确保程序高效运行并避免内存泄漏。掌握这两者对于编写高质量的C语言程序至关重要。
    42 10
    |
    14天前
    |
    程序员 C语言
    C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
    C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
    29 1