【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

🎡指针类型的意义

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

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

🚗指针数组

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

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

💥数组名

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

1.sizeof(数组名);//求的是整个数组在空间中所占内存的大小
//数组名单独包括在sizeof内
2.&数组名//取出的是整个数组的地址
#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
}

🎠函数指针

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

#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;
}

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

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

🌈函数指针数组

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

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

💥冒泡排序模拟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;
}

在这里插入图片描述

🚩数组的笔试题

小沐所用的平台是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.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;
}
解析

在这里插入图片描述
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;
}
结果

在这里插入图片描述

✨笔试题四

代码
#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;
}
结果

在这里插入图片描述

笔试题五

代码
#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. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
  2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表示首元素的地址。

💫写在最后

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

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

评论 134
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐曦希

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值