• 【C语言进阶篇】数组&&指针&&数组笔试题


    大家好我是沐曦希💕

    在这里插入图片描述


    在这里插入图片描述

    🎆前言

    🔭指针

    内存–》内存的单元(1byte字节)–》编号–》地址–》指针
    所以指针就是一个地址(编号)而已。
    口头语中说的指针一般指:指针变量。指针变量就是一个变量而已,就是一块内存空间,指针变量用来存放地址。
    指针变量在x32平台下大小为4个字节,在x64平台下大小为8个字节。
    指针运算包括:
    1.加减正数
    2.指针-指针
    3.指针的关系运算

    指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。
    在 C/C++语言中,指针一般被认为是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组,函数等占据存储空间的实体

    int a = 10;
    int* pa = &a;//pa是指针变量,int*是指针变量pa的类型
    //*说明pa是指针变量,int说明指针变量pa所指向的变量的类型
    *pa = 20;//*pa解引用操作
    printf("%d\n",a);//20
    
    • 1
    • 2
    • 3
    • 4
    • 5

    🎡指针类型的意义

    char ch = 'w';
    char* pc = &ch;//字符指针
    float a = 3.14f;
    float* pf = &a;//浮点数指针
    
    • 1
    • 2
    • 3
    • 4

    1.指针变量在进行加减整数运算时候,指针变量类型决定指针变量跳过几个字节(步长)。
    2.指针变量进行解引用操作的时候,指针变量的类型决定了指针变量一次访问多少个字符(权限)。

    🚗指针数组

    指针数组:本质上就是数组,数组中存放的是指针(地址)

    int* pa = NULL;//指针变量要初始化,否则为野指针
    int* pb = NULL;
    int* pc = NULL;
    int* pd = NULL;
    int* arr[4] = {pa,pb,pc,pd};//指针数组
    
    • 1
    • 2
    • 3
    • 4
    • 5

    💥数组名

    1.数组名在大部分情况下表示:首元素地址。
    但有两个例外,下面两个数组名表示整个数组:

    1.sizeof(数组名);//求的是整个数组在空间中所占内存的大小
    //数组名单独包括在sizeof内
    2.&数组名//取出的是整个数组的地址
    
    • 1
    • 2
    • 3
    #include<stdio.h>
    int main()
    {
    	int arr[3] = { 1,2,3 };
    	printf("%d\n", sizeof(arr));//12
    	printf("%d\n", sizeof(&arr));//4或者8//地址的大小为4或者8,x32是4,x64是8
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    🎠函数指针

    函数也是有地址,那么可以用指针变量来存储函数的地址,方便以后的函数调用。

    #include<stdio.h>
    int Add(int x, int y)
    {
    	return x + y;
    }
    int main()
    {
    	int (*pa)(int, int) = &Add;
    	//函数的地址存放在函数的指针变量中
    	int (*pb)(int, int) = Add;
    	int ret = (*pa)(2, 3);
    	int sum = pb(2, 3);
    	printf("%p\n", &Add);
    	printf("%p\n", pa);
    	printf("%p\n", pb);
    	printf("%d\n", ret);
    	printf("%d\n", sum);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述
    函数指针能实现回调函数。回调函数是通过函数指针调用的函数。

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

    🌈函数指针数组

    函数指针数组指:本质上是数组,用于存放函数指针的数组。

    int (*pf)(int , int ) = Add;
    int (*pfArr[4])(int ,int );//int(*)(int ,int )是函数指针数组的类型
    pfArr数组的每个元素的类型是:int(*)(int ,int );
    pfArr数组可以存放四个类型为int(*)(int ,int )的函数指针。
    
    • 1
    • 2
    • 3
    • 4

    💥冒泡排序模拟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 };
        //char *arr[] = {"aaaa","dddd","cccc","bbbb"};
        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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

    🚩数组的笔试题

    小沐所用的平台是x32环境下的

    🎄笔试题一

    代码

    //一维数组
    #include<stdio.h>
    int main()
    {
    	int a[] = { 1,2,3,4 };
    	printf("%d\n", sizeof(a));
    	printf("%d\n", sizeof(a + 0)); 
    	printf("%d\n", sizeof(*a));
    	printf("%d\n", sizeof(a + 1));
    	printf("%d\n", sizeof(a[1]));
    	printf("%d\n", sizeof(&a));
    	printf("%d\n", sizeof(*&a));
    	printf("%d\n", sizeof(&a + 1));
    	printf("%d\n", sizeof(&a[0]));
    	printf("%d\n", sizeof(&a[0] + 1));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    解析

    1.sizeof(数组名),此时数组名表示整个数组,计算的是整个数组的大小,单位是字节。故为16个字节
    2.a+0 中的数组名a不是单独放在sizeof内部,又没有取地址符号,所以a就是首元地址,a+0还是首元素地址,地址的大小为4或者8个字节。故为4或者8个字节
    3.*a 中的数组名a是数组首元素的地址,*a就是对首元素的地址解引用,找到的就是首元素,因为首元素的类型为int整型,所以首元素的大小就是4个字节。故为4个字节
    4.a+1 中的a是数组首元素的地址,a+1是第二个元素的地址,sizeof(a+1)就是地址的大小4或者8。故为4或者8个字节。
    5.a[1] 表示的是第二位元素,故sizeof(a[1])计算的是第二位元素所占内存的大小。故为4个字节
    6.&a取出的数组的地址,数组的地址,也就是个地址,而地址的大小是4或者8。故为4或者8个字节。
    7.*&a 中的&a的类型是int(*)[4],&a拿到的是数组名的地址,类型是 int(*)[4],是一种数组指针,数组指针解引用找到的是数组,即相当于*和&相互抵消,即*&a等价于a,即求sizeof(a),而a表示整个数组,计算的是整个数组的大小,单位是字节。故为16个字节。
    8.&a+1 中的&a取出的是数组的地址,&a的数组指针类型是 int(*)[4],&a+1 是从数组a的地址向后跳过了一个(4个整型元素的)数组的大小,&a+1还是地址,是地址就是4/8字节。故为4或者8个字节。
    9.&a[0] 中&a[0]就是第一个元素的地址,计算的是地址的大小。故为4或者8个字节。
    10.&a[0]+1 中&a[0]+1是第二个元素的地址,大小是4/8个字节,&a[0]+1相当于&a[1]。故为4个字节。

    结果

    在这里插入图片描述

    🎈笔试题二

    代码

    //字符数组
    #include<stdio.h>
    #include<string.h>
    int main()
    {
    	char arr[] = { 'a','b','c','d','e','f' };
    	//6个元素
    	printf("%d\n", sizeof(arr));
    	printf("%d\n", sizeof(arr + 0));
    	printf("%d\n", sizeof(*arr));
    	printf("%d\n", sizeof(arr[1]));
    	printf("%d\n", sizeof(&arr));
    	printf("%d\n", sizeof(&arr + 1));
    	printf("%d\n", sizeof(&arr[0] + 1));
    	printf("%d\n", strlen(arr));
    	printf("%d\n", strlen(arr + 0));
    	//printf("%d\n", strlen(*arr));//error
    	//printf("%d\n", strlen(arr[1]));//error
    	printf("%d\n", strlen(&arr));
    	printf("%d\n", strlen(&arr + 1));
    	printf("%d\n", strlen(&arr[0] + 1));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    解析

    在这里插入图片描述
    strlen求字符串长度,关注的是字符串中的‘\0’,计算的是’\0’之前出现的字符串的个数,是库函数,只针对字符串。
    sizeof只关注占用内存空间的大小,不在乎内存中存放的是什么,是操作符。

    1.sizeof(数组名),此时数组名表示整个数组,计算的是整个数组的大小,单位是字节。故为6个字节
    2.arr+0 中arr + 0 是数组首元素的地址,地址的大小为4或者8。故为4或者8个字节。
    3.*arr 中arr表示首元素的地址,*arr表示首元素,大小为1个字节,故为1个字节。
    4.arr[1]表示第二位元素,大小为一个字节。
    5.&arr取的是整个数组的地址,地址的大小为4或者8个字节。
    6.&arr+1 就是跳过一个数组后的地址,地址的大小为4或者8个字节。
    7.&arr[0]+1相当于arr[1],即表示第二位元素,大小为一个字节。
    8.strlen(arr) 表示在‘\0’(0)之前的元素个数,所以为随机值
    9.strlen(arr+0)相当于strlen(arr),故依然为随机值
    10.strlen(arr)相当于strlen(‘a’),又相当于strlen(97),是一个野指针,故是错误的。
    11.strlen(arr[1])相当于strlen(‘b’),又相当于strlen(98),是一个野指针,故是错误的。
    12.strlen(&arr)取得是整个数组的地址,从首元素开始数,到’\0’结束,即随机值。
    13.strlen(&arr+1)表示跳过一个类型为char(
    )[6]的数组,故为随机值-6。
    14.strlen(&arr[0]-1)表示从第二位元素开始数,到’\0’结束,即随机值-1.

    以上的随机值相等

    结果

    在这里插入图片描述

    🎊笔试题三

    代码

    #include<stdio.h>
    int main()
    {
    	char arr[] = "abcdef";
    	//7个元素
    	//[a b c d e f \0]
    	printf("%d\n", sizeof(arr));//7
    	printf("%d\n", sizeof(arr + 0));//4/8
    	printf("%d\n", sizeof(*arr));//1
    	printf("%d\n", sizeof(arr[1]));//1
    	printf("%d\n", sizeof(&arr));//4/8
    	printf("%d\n", sizeof(&arr + 1));//4/8
    	printf("%d\n", sizeof(&arr[0] + 1));//4/8
    	printf("%d\n", strlen(arr));//6
    	printf("%d\n", strlen(arr + 0));//6
    	//printf("%d\n", strlen(*arr));//error
    	//printf("%d\n", strlen(arr[1]));//error
    	printf("%d\n", strlen(&arr));//6
    	printf("%d\n", strlen(&arr + 1));//随机值
    	printf("%d\n", strlen(&arr[0] + 1));5
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    结果

    在这里插入图片描述

    ✨笔试题四

    代码

    #include<stdio.h>
    int main()
    {
    	char* p = "abcdef";
    	//7个元素
    	printf("%d\n", sizeof(p));//4/8
    	printf("%d\n", sizeof(p + 1));//4/8
    	printf("%d\n", sizeof(*p));//1
    	printf("%d\n", sizeof(p[0]));//1
    	printf("%d\n", sizeof(&p));//4/8
    	printf("%d\n", sizeof(&p + 1));//4/8
    	printf("%d\n", sizeof(&p[0] + 1));//4/8
    	printf("%d\n", strlen(p));//6
    	printf("%d\n", strlen(p + 1));//5
    	//printf("%d\n", strlen(*p));//error
    	//printf("%d\n", strlen(p[0]));//p[0]-->*(p+0)//error
    	printf("%d\n", strlen(&p));//随机值
    	printf("%d\n", strlen(&p + 1));//随机值
    	printf("%d\n", strlen(&p[0] + 1));//5
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    结果

    在这里插入图片描述

    笔试题五

    代码

    #include<stdio.h>
    int main()
    {
    	int a[3][4] = { 0 };
    	printf("%d\n", sizeof(a));//3*4*4=48
    	printf("%d\n", sizeof(a[0][0]));4
    	printf("%d\n", sizeof(a[0]));
    	//a[0]是第一行这个一维数组的数组名,单独放在sizeof内部,a[0]表示第一个整个这个一维数组
    	//sizeof(a[0])计算的就是第一行的大小
    	printf("%d\n", sizeof(a[0] + 1));
    	//a[0]并没有单独放在sizeof内部,也没取地址,a[0]就表示首元素的地址
    	//就是第一行这个一维数组的第一个元素的地址,a[0] + 1就是第一行第二个元素的地址
    	printf("%d\n", sizeof(*(a[0] + 1)));
    	//a[0] + 1就是第一行第二个元素的地址
    	//*(a[0] + 1))就是第一行第二个元素
    	printf("%d\n", sizeof(a + 1));
    	//a虽然是二维数组的地址,但是并没有单独放在sizeof内部,也没取地址
    	//a表示首元素的地址,二维数组的首元素是它的第一行,a就是第一行的地址
    	//a+1就是跳过第一行,表示第二行的地址
    	printf("%d\n", sizeof(*(a + 1)));
    	//*(a + 1)是对第二行地址的解引用,拿到的是第二行
    	//*(a+1)-->a[1]
    	//sizeof(*(a+1))-->sizeof(a[1])
    	printf("%d\n", sizeof(&a[0] + 1));
    	//&a[0] - 对第一行的数组名取地址,拿出的是第一行的地址
    	//&a[0]+1 - 得到的是第二行的地址
    	printf("%d\n", sizeof(*(&a[0] + 1)));
    	printf("%d\n", sizeof(*a));
    	//a表示首元素的地址,就是第一行的地址
    	//*a就是对第一行地址的解引用,拿到的就是第一行
    	printf("%d\n", sizeof(a[3]));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    结果

    在这里插入图片描述

    🎇总结

    数组名的意义:

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

    💫写在最后

    友友们觉得不错的可以给个关注,点赞或者收藏哦!😘感谢各位友友们的支持。

    你的❤️点赞是我创作的动力的源泉
    你的✨收藏是我奋斗的方向
    你的🙌关注是对我最大的支持
    你的✏️评论是我前进的明灯
    创作不易,希望大佬你支持一下小沐吧😘

  • 相关阅读:
    每天五分钟机器学习:如何解决欠拟合问题
    【数学建模】简单的优化模型-6 血管分支
    JS-树:深度优先搜索与广度优先搜索
    error C2039: ‘m_ctlMainTopReBar‘: is not a member
    北大C++课后记录:文件读写的I/O流
    【Wamp】局域网设备访问WampServer | 使用域名访问Wamp | Wamp配置HTTPS
    如何开启Win10虚拟机Hyper-V功能
    ESP8266-Arduino网络编程实例-Web页面WiFi配置管理
    leetcode - 串联所有单词的子串 - 最小覆盖子串 - x 的平方根
    java基于SpringBoot+Vue+nodejs的医院患者就诊档案管理系统 element
  • 原文地址:https://blog.csdn.net/m0_68931081/article/details/125573777