0


都知道指针很重要,但你真的了解指针么?

前言:

    **指针在C的的重要性不言而喻,指针用的好和指针不会用,相信大家都有一个自己的认识,接下来我就通过讲解 + 例题的形式为大家进行深度解剖指针,让大家对指针认识清楚,并应用自如~!**![](https://img-blog.csdnimg.cn/8ca25ecc8d7c440fa5f569a7d4534675.jpeg)

1.指针的基础概念

  1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
  2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。
  3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。

2.字符指针

** 在指针的类型中我们知道有一种指针类型为字符指针 char*

🏠一般使用:

int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'w';
    return 0;
}

🏠还有一种使用方法:

int main()
{
    const char* pstr = "Liyuyuea~!";//这里是把一个字符串放到pstr指针变量里了吗?
    printf("%s\n", pstr);
    return 0;
}

** 这里是把一个字符串放到pstr指针变量里了么?**

** 很显然不是的,指针大小不是4个字节么(默认X86),指针怎么可能存这么多字符呢,所以肯定不是将字符串存到指针变量里了,根据对指针的认识,得知指针存的是一个地址,那么只要存字符串的首元素地址就可以了。**

** 通过字符串首元素地址就可以打印整个字符串~!**

    ** 上面代码的意思是把一个常量字符串的首字母 L 的地址放在了指针变量 pstr 里。**

🚀那么接下来给大家看一个面试题~!

** 大家先看看这个题会输出什么呢。**

    ** 我先给大家公布答案,看看你们做对了没~!**![](https://img-blog.csdnimg.cn/c10b9d71618f461ea7a3c58379ae4a9f.gif)

**     想必有大佬做对了,那么这又是为什么呢?我给大家话个图就明白了~!**

    ![](https://img-blog.csdnimg.cn/4305c5c97ddc4a389c2b2b2de046589f.png)

3.指针数组

概念:

** 指针数组就是数组,数组里的元素是指针。也就是一个存放指针的数组~!**

int arr1[10]; //整形指针的数组*

*char arr2[4]; //一级字符指针的数组

**char arr3[5]; //二级字符指针的数组

温馨提示:

    **我们一定要记住指针的概念,因为这里会有很多“套娃”,只有记住了哪个代码是什么,才不会搞混乱~!**(接下来直接看数组指针,和数组指针一起进行区分!)

4.数组指针

4.1数组指针的定义

概念:

** 数组指针是一个指针,这个指针指向一个数组。也就是一个指向数组的指针~!**

🍑根据 指针数组 和 数组指针 的概念,我们来区分一下:

🍑想好了接下来看图~!

4.2 &数组名 VS 数组名

概念:

  1. 数组名一般情况下都是首元素地址~!
  2. 在&数组名 和 sizeof(数组名)的时候是数组地址~!

🏠那么我们看一段代码:

🚀运行结果如下:

** 由此可见,他们的地址是相同的,可是我们刚才说 &数组名 是整个数组的地址阿,难道表示整个数组的表示地址和首元素地址没有区别么?是一样的么?**

🏠接下来我们再看一段代码:

🚀下面是运行的代码:

4.3数组指针的使用

  **  我们懂了数组指针,那么数组指针的如何使用的呢?**![](https://img-blog.csdnimg.cn/26c7fa22294743ab87daae0f2abcc2b3.jpeg)

** 既然数组指针指向的是数组,那么数组指针里就应该存放数组,只要把数组放进去就好了~!**

🚀代码如下:

🍑下面进行讲解~!

  ** **

** 相信经过讲解,大概该怎么去用大家已经有了一定的理解,接下来就是大家在实战中可以去尝试写更多代码去体会~!**

小总结:

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

🚀接下来看解析~


5.数组参数、指针参数

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

5.1一维数组传参

🍑接下来我们判断一下这样传参可不可以~!

5.2二维数组传参

🍑接下来我们判断一下这样传参可不可以~!


6.函数指针

概念:

** 函数指针是一个指针,这个指针指向一个函数。也就是指向函数的指针~!**

🍑首先我们先来观察一段代码:

** 输出的是两个地址,这两个地址是test函数的地址。**

** 那么我们的函数地址要想保存起来,是用什么形式进行保存呢?**

🍑接下来就看解析~!

小提升:

    ** 接下来我们来阅读两端有趣的代码~**
//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);

** 相信大家看到这两个代码肯定很苦恼吧(这是什么乱七八糟的!一堆括号堆在一起,我才不想看!),但你要掌握了原理,也是可以分析出来的!!!**

** 接下来第二个代码我就不进行解释了,你们自己可以去想想,如果有感兴趣的小伙伴可以在评论区留言,我会给你单独解释~!**


7.函数指针数组

概念:

** **函数指针数组是一个数组,这个数组的元素是函数指针。所以函数指针数组是存放函数指针的数组~!

🍑我们首先还是先来判别哪个是函数指针数组:

int (*parr1[10])();
int *parr2[10]();
int (*)() parr3[10];

如何应用:

    **首先我们先看这样一个代码,这个代码是一个计算器。**
#include <stdio.h>
int add(int a, int b)
{
    return a + b;
}
int sub(int a, int b)
{
    return a - b;
}
int mul(int a, int b)
{
    return a * b;
}
int div(int a, int b)
{
    return a / b;
}
int main()
{
    int x, y;
    int input = 1;
    int ret = 0;
    do
    {
        printf("*************************\n");
        printf(" 1:add           2:sub \n");
        printf(" 3:mul           4:div \n");
        printf("*************************\n");
        printf("请选择:");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = add(x, y);
            printf("ret = %d\n", ret);
            break;
        case 2:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = sub(x, y);
            printf("ret = %d\n", ret);
            break;
        case 3:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = mul(x, y);
            printf("ret = %d\n", ret);
            break;
        case 4:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = div(x, y);
            printf("ret = %d\n", ret);
            break;
        case 0:
            printf("退出程序\n");
            break;
        default:
            printf("选择错误\n");
            break;
        }
    } while (input);

    return 0;
}

** 我们可以看出switch语句中有很多重复的语句,整体就很冗余,那么我们便可以利用函数指针数组的形式进行制作一个转移表。**

**    如下列所示:**
#include <stdio.h>
int add(int a, int b)
{
    return a + b;
}
int sub(int a, int b)
{
    return a - b;
}
int mul(int a, int b)
{
    return a * b;
}
int div(int a, int b)
{
    return a / b;
}
int main()
{
    int x, y;
    int input = 1;
    int ret = 0;
    int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
    while (input)
    {
        printf("*************************\n");
        printf(" 1:add           2:sub \n");
        printf(" 3:mul           4:div \n");
        printf("*************************\n");
        printf("请选择:");
        scanf("%d", &input);
        if ((input <= 4 && input >= 1))
        {
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = (*p[input])(x, y);
        }
        else
            printf("输入有误\n");
        printf("ret = %d\n", ret);
    }
    return 0;
}

** 这样看起来是不是就舒服多啦!所以我们要是利用好指针,不仅可以提供我们不同的思路,也可以让我们的代码看起来更漂亮!**


8.回调函数

概念:

  **  回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。**

qsort函数:

    **所谓的qsort就是快速排列。**
#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{
  return (*( int *)p1 - *(int *) p2);
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int i = 0;
    
    qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
   {
       printf( "%d ", arr[i]);
   }
    printf("\n");
    return 0;
}

🚀它运行的结果就是把arr中数组的元素进行了排列,如图所示。

**     接下来我会模拟实现qsort函数,但其实大家只要看哪里用到了回调函数就好,没必要会模拟实现,只要懂了就好~!**
#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{
    return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{
    int i = 0;
    for (i = 0; i < size; i++)
    {
        char tmp = *((char*)p1 + i);
        *((char*)p1 + i) = *((char*)p2 + i);
        *((char*)p2 + i) = tmp;
    }
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
    int i = 0;
    int j = 0;
    for (i = 0; i < count - 1; i++)
    {
        for (j = 0; j < count - i - 1; j++)
        {
            if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
            {
                _swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
            }
        }
    }
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int i = 0;
    bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
    for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

** 只要清楚这几点就可以了~!**

9.指针和数组笔试题 + 讲解

第一组:

** 🍑大家先想想吧~!**

第二组:

** 🍑大家先想想吧~!**

第三组:

** 🍑大家先想想吧~!**

第四组:

** 🍑大家先想想吧~!**

第五组:

** 🍑大家先想想吧~!**

第六组:

** 🍑大家先想想吧~!**

第七组:

** 🍑大家先想想吧~!**

第八组:

** 🍑大家先想想吧~!**

总结:

数组名的意义:

  1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
  2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表示首元素的地址。

10.指针笔试题

    **如果你能看到这里,相信指针对你来说已经了如指掌了,但是还是缺少实战,接下来我会列出几个笔试题,支持反复观看~!**

** 大家做题前好好想想,动手画画,可能这里的笔试题会是你将来面试题的原题或者经过改编的哦,大家再认真看完吧~!!!**

笔试题一:

** 🍑大家先想想吧~!**

笔试题二:

🍑大家先想想吧~!

笔试题三:

🍑大家先想想吧~!

笔试题四:

🍑大家先想想吧~!

笔试题五:

🍑大家先想想吧~!

笔试题六:

🍑大家先想想吧~!

笔试题七:

🍑大家先想想吧~!

11.小结

    **本次内容纯干货,博主准备了好几天才整理好的,绝对够干~!![](https://img-blog.csdnimg.cn/c1115acffdef42edbfacbcd4e6604556.gif)**

** 可能看的时候会挺枯燥的,但是这点内容必须要掌握,而且要掌握好,只有掌握好这点才能正好的向下顺利学习~!**

** 其实最后还有一个笔试题我没写出来,那个有点复杂,我准备再出一篇博客,所以如果这点知识对你有帮助,麻烦你给博主个三连,博主才更有动力去总结并出讲解~!**

** 也不知道大家爱看干货还是喜欢实在的东西,大家如果有要求可以给我评论,都会看,都会看~!!! **


本文转载自: https://blog.csdn.net/weixin_69725192/article/details/125015971
版权归原作者 Liyuyuea! 所有, 如有侵权,请联系我们删除。

“都知道指针很重要,但你真的了解指针么?”的评论:

还没有评论