当前位置: 首页 > news >正文

C语言-数组指针笔试题讲解(1)-干货满满!!!

文章目录

  • ▶️1.sizeof和strlen的对比💯
    • ➡️1.1 sizeof是什么?💯
    • ➡️1.2sizeof用法举例💯
    • ▶️1.3strlen是什么?💯
    • ▶️1.4 strlen函数用法举例:💯
    • ▶️1.5 strlen和sizeof的对比💯
  • ▶️2. 数组和指针笔试题:💯
    • ▶️2.1 整型数组和指针笔试题1:💯
    • ▶️2.1.1 整型数组和指针笔试题解析~💯
      • ▶️ 2.1.1.1 VS运行结果展示:💯
    • ▶️2.2 字符数组和指针笔试题💯
      • ▶️2.2.1 字符数组和指针笔试题1💯
      • ▶️2.2.1 字符数组和指针笔试题解析:💯
      • ▶️2.2.1.1 VS运行结果展示:💯
      • ▶️2.2.2 字符数组和指针笔试题2💯
      • ▶️2.2.2 字符数组和指针笔试题解析:💯
      • ▶️2.2.2.1 VS运行结果展示:💯
      • ▶️2.2.3 字符数组和指针笔试题3💯
      • ▶️2.2.3字符数组和指针笔试题解析:💯
      • ▶️2.2.3.1 VS运行结果展示:💯
      • ▶️2.2.4 字符数组和指针笔试题4💯
      • ▶️2.2.4字符数组和指针笔试题解析:💯
      • ▶️2.2.4.1 VS运行结果展示:💯
      • ▶️2.2.5 字符数组和指针笔试题5💯
      • ▶️2.2.5字符数组和指针笔试题解析:💯
      • ▶️2.2.5.1 VS运行结果展示:💯
      • ▶️2.2.6 字符数组和指针笔试题6💯
      • ▶️2.2.6字符数组和指针笔试题解析:💯
      • ▶️2.2.6.1 VS运行结果展示:💯

在上一次介绍篇博客中:
C语言-指针讲解(4)
我们给大家主要讲解了指针的进阶用法,让我们来回顾一下讲了什么吧!

  • 回调函数是通过函数指针调用的函数,以及回调函数用法举例。
  • 细致地讲解qsort函数的参数,以及用qsort函数排序任意类型用法举例,同时qsort函数是运用了快速排序的思想。
  • 改造普通的整型冒泡排序算法,让它模拟实现成一个qsort函数,然后用模拟实现的qsort函数对各种数据类型进行排序操作举例。

那么这次博主根据前面5讲的指针介绍,给大家讲解C语言指针相关的笔试题:
这次讲的内容如下:
在这里插入图片描述



首先,在讲解C语言指针笔试题前,我们先对sizeof操作符以及strlen库函数进行详细的介绍。



▶️1.sizeof和strlen的对比💯

➡️1.1 sizeof是什么?💯

  • sizeof顾名思义,它就是一种操作符。
  • 并且sizeof操作符是用来计算变量所占内存空间大小的,单位是字节,计算的是适用类型创建的变量所占内存空间的大小。

➡️1.2sizeof用法举例💯

在这里插入图片描述
如下所示:

#inculde <stdio.h>
int main()
{int a = 10;printf("%d\n", sizeof(a));printf("%d\n", sizeof a);printf("%d\n", sizeof(int));return 0;
}

vs编译结果如下:
在这里插入图片描述

代码分析:
1.我们通过上图发现用sizeof计算变量的大小类型的大小,只要它们的类型相同,那么它们的大小也是相等的,而且如果是计算创建变量a的大小,是无需加上括号的,反倒如果是计算int类型的大小,是需要对它加上一个括号的。

总结: sizeof只关注内存存放空间的大小,不在乎内存中存放的数据。


▶️1.3strlen是什么?💯

strlen顾名思义,就是C语言的库函数,功能是求字符串长度。

它的函数原型如下:

1 size_t strlen (const char * str);


▶️1.4 strlen函数用法举例:💯

如下代码所示:

#include <stdio.h>
int main()
{char arr1[3] = { 'a', 'b', 'c' };char arr2[] = "abc";printf("%d\n", strlen(arr1));printf("%d\n", strlen(arr2));return 0;
}

vs运行结果如下:
在这里插入图片描述
有同学可能会有疑问了,为什么数组arr1和数组arr2存的内容都一样,但为什么用strlen函数计算它们的长度却不相同呢?

代码分析:

  • 这是因为strlen函数本质上是统计参数str中这个地址开始往后,\0之前的字符。strlen函数会一直向后找\0字符,直到找到为止。所以:这样有可能会导致数组越界访问

如下所示:
在这里插入图片描述

  • 从上图,我们发现arr1数组是一个一个字符一个字符地存放的,如果我们不把\0存进数组中,strlen函数会一直往后找\0。直到找到为止。
  • 反倒是strlen计算arr2数组就不一样了,因为arr2数组是以字符串的形式存放在数组中而\0是字符串的结束标志,因此,如果我们以字符串的形式存放在数组,strlen函数会把arr2数组中‘\0’之前的字符个数都加起来。


▶️1.5 strlen和sizeof的对比💯

我们把strlen函数和sizeof操作符区别做了张图总结
如下图所示:
在这里插入图片描述



▶️2. 数组和指针笔试题:💯

再讲解数组和指针笔试题之前,我们再来复习一下数组名的概念。
我们之前在这篇博客:C语言-指针讲解(2)讲过:通常情况下,数组名是数组首元素的地址。 但是有两个例外:
1.sizeof(数组名),sizeof里面单独放数组名,这里的数组名代表的是整个数组,计算的是整个数组的大小。
2.&arr表示整个数组,&是指取出整个数组的地址,(整个数组的地址和数组首元素的地址还是有区别的。)


▶️2.1 整型数组和指针笔试题1:💯

题目如下:

int main()
{int a[] = {1,2,3,4};printf("%zd\n",sizeof(a));//1.输出结果是什么呢?printf("%zd\n",sizeof(a+0));//2.输出结果是什么呢?printf("%zd\n",sizeof(*a));//3.输出结果是什么呢?printf("%zd\n",sizeof(a+1));//4.输出结果是什么呢?printf("%zd\n",sizeof(a[1]));//5.输出结果是什么呢?printf("%zd\n",sizeof(&a));//6.输出结果是什么呢?printf("%zd\n",sizeof(*&a));//7.输出结果是什么呢?printf("%d\n",sizeof(&a+1));//8.输出结果是什么呢?printf("%d\n",sizeof(&a[0]));//9.输出结果是什么呢?printf("%d\n",sizeof(&a[0]+1));//10.输出结果是什么呢?return 0;
}

大家不妨先思考一下这些题,看看它们的输出结果是什么?

在这里插入图片描述

▶️2.1.1 整型数组和指针笔试题解析~💯

1.由于是sizeof(数组名),计算的是整个数组的大小,单位是字节。这里的整型数组有四个元素,每个元素占4个字节,那么也就是总共占16个字节。
2.这里的数组名并没有单独放在sizeof内部,也没有&,所以a就是数组首元素的地址,是地址就是4/8个字节。需要注意的是,这里的(a+0) == &a[0]。
3.a就是数组首元素的地址,a==&a[0],然后*a其实就是第一个元素,也就是a[0],大小就是4个字节。
4.a就是数组首元素的地址(&a[0]–int ),a+1—>&a[1],a+1就是第二个元素的地址。它的大小也就是4/8字节。
5.计算第2个元素的大小,单位是字节 - 4
6.&a虽然取出的是数组的地址,但是数组的地址也是地址,是地址大小就是4/8个字节。
7.16
8.&a+1是跳过整个数组后的地址,是地址大小就是4/8个字节。
9.首元素的地址,4/8
10.因为&a[0] - int
,那么+1就是到第二个元素的地址,也就是&a[1]的地址,大小是4/8个字节。

这里我们重点讲一下第七道和第八道题目:
7.这里我们有两种方法来分析这道题:
1.这里的&a --> int(*p)[4]=&a,也就是说这里的p指向的是一个大小为4的整型数组这里的 * p是指访问一个数组的大小,然后p+1是跳过一个数组的大小。
&a取出的是数组的地址,数组的地址应该放到数组指针里面去,然后它的数组指针类型是int( * )[4]。然后这里 * p是访问整个数组的大小,也就是说这个数组占了16个字节。
2.这里的&a就是取出整个数组的地址,它的类型是个数组指针,我们对数组指针进行解引用操作,访问的不就是整个数组吗?所以sizeof整个数组不就是16吗?

8.如下图所示:
在这里插入图片描述

虽然我们通过&a+1是个地址,是地址就是4/8个字节。但是我们通过图中更能直观地发现&a+1指向的是第四个元素后面的地址。

▶️ 2.1.1.1 VS运行结果展示:💯

那我们分析的是否正确呢,接下来我们分别用vs的x64环境和x86环境来测试一下运行结果~

x86环境:在这里插入图片描述
x64环境
在这里插入图片描述



▶️2.2 字符数组和指针笔试题💯

▶️2.2.1 字符数组和指针笔试题1💯

题目如下:

//字符数组1.1
#include <stdio.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%zd\n", sizeof(arr));//1.输出结果是什么?printf("%zd\n", sizeof(arr + 0));//2.输出结果是什么?printf("%zd\n", sizeof(*arr));//3.输出结果是什么?printf("%zd\n", sizeof(arr[1]));//4.输出结果是什么?printf("%zd\n", sizeof(&arr));//5.输出结果是什么?printf("%zd\n", sizeof(&arr + 1));//6.输出结果是什么?printf("%zd\n", sizeof(&arr[0] + 1));//7.输出结果是什么?return 0;
}

大家不妨先思考这几道题,待会我们会统一讲解一下。

在这里插入图片描述

▶️2.2.1 字符数组和指针笔试题解析:💯

1.由于是sizeof(数组名),计算的是整个数组的大小,单位是字节。这里的整型数组有六个元素,每个元素占1个字节,那么也就是总共占6个字节。
2.arr是数组首元素的地址,arr+0 还是首元素的地址 是地址大小就是4/8个字节。
3.arr是数组首元素的地址,*arr就是首元素,就占一个字符大小就是1个字节。
4.arr[1]就是数组的第二个元素,大小是1个字节。
5.&arr 是数组的地址,数组的地址也是地址,大小就是4/8。
6.&arr+1 是跳过整个数组,指向f的后面 4/8。
7.&arr[0]是首元素的地址,&arr[0]+1就是第二个元素的地址 4/8。

▶️2.2.1.1 VS运行结果展示:💯

我们不妨用vs来运行一下此代码,看看我们分析得是否正确~
x64环境:
在这里插入图片描述x86环境:
在这里插入图片描述



▶️2.2.2 字符数组和指针笔试题2💯

题目如下:

#include <stdio.h>
#include <string.h>int main()
{//字符数组1.2char arr[] = { 'a','b','c','d','e','f' };printf("%zd\n", strlen(arr));//1.输出结果是什么呢?printf("%zd\n", strlen(arr + 0));//2.输出结果是什么呢?printf("%zd\n", strlen(*arr));//3.输出结果是什么呢?printf("%zd\n", strlen(arr[1]));//4.输出结果是什么呢?printf("%zd\n", strlen(&arr));//5.输出结果是什么呢?printf("%zd\n", strlen(&arr + 1));//6.输出结果是什么呢?printf("%zd\n", strlen(&arr[0] + 1));//7.输出结果是什么呢?return 0;
}

大家不妨先思考这几道题,待会我们会统一讲解一下。

在这里插入图片描述

▶️2.2.2 字符数组和指针笔试题解析:💯

1.如下图所示:
我们发现,这个arr数组它是没有\0的,也就是说当这个strlen函数拿到首元素字符a的地址,会一直往后找\0。
它有可能会在内存中的某个位置找到\0,然后统计\0之前的字符个数,因此我们是不确定它的值是多少,因此它是个随机值。

在这里插入图片描述
2.同样地,这个输出结果也是随机值,因为arr+0,意思就是首元素地址跳过0个元素,本质上还是首元素的地址。
所以strlen函数拿到的也是首元素a的地址,然后向后面找\0,但是arr数组里面没有\0,因此它本质上还是个随机值。

如下图所示:
在这里插入图片描述
在这里插入图片描述
3.我们从上面两张图中可以发现,* arr就是把它首元素的地址进行解引用,得到的是它的元素a,a的ASCLL码值是97。我们知道strlen函数参数的是一个指针类型的,我们把97它传过去的话,它就把它当成一个地址。
97这个地址你说想访问就访问吗?哪个地址你能说想访问就访问呢?我们通过vs调试也发现0x00000061是访问异常,也就是我们常说的非法访问。那么这个输出结果就会报错。
4.同样地,我们发现arr[1]就是数组的第二个元素。也就是传过去的是字符b,字符b的ASCLL码值是98,也就是传过去的地址是98。也会属于非法访问,所以它的输出结果同样也会出现报错。

总结:通过上面分析,我们知道只能传给strlen地址。而不能胡传,如果胡传,strlen函数会误以为地址,最终就会出现报错。

5.我们发现&arr的类型是char (*p)[6],然后如果把它传到strlen函数里面的话,它的参数类型就强制转换为char *。
站在strlen函数的角度,它依然拿到的是arr起始位置的地址,也就是从字符a向后数的,数到的结果还是随机值。所以它的结果跟第一道题和第二道题输出结果是一样的,都是随机值。

如下图所示:
在这里插入图片描述
6.从上图,我们发现,&arr+1指向的是字符f后面的地址,也就是从f后面的地址往后去找\0
所以从这里往后数,那个内存放什么,我们就更不知道了,但是这个地方得到的随机值跟前面那些随机值是不一样的,因为它们中间相差了几个字符。

如下图所示
在这里插入图片描述
7.从上图我们发现&arr[0]+1得到的是字符b的地址,然后把b的地址传给strlen函数,从b的位置一直往后数找\0,所以它这里的输出结果依然是随机值
只不过它的随机值跟第一题和第二题输出结果的随机值 少了个1。

综上所述: 对于指针来说 我们要搞清楚它指向哪里,才能知道它指向的内容是什么。

▶️2.2.2.1 VS运行结果展示:💯

我们不妨用vs来运行一下此代码,看看我们分析得是否正确~
这里需要注意的是: 如果我们直接运行的话,第三题和第四题输出结果是会报错的。那它会影响后面第五-第七题的输出结果,因此我们要先将它的代码先注释掉再运行。

x64环境:
在这里插入图片描述
x86环境:
在这里插入图片描述
我们从x64环境和x86环境中也知道,除了第三和第四题,其他题的输出结果均为随机值。 说明我们的分析是正确的。



▶️2.2.3 字符数组和指针笔试题3💯

题目如下:

#include <stdio.h>
int main() {//字符数组2.1char arr[] = "abcdef";printf("%zd\n", sizeof(arr));//1.输出结果是什么?printf("%zd\n", sizeof(arr + 0));//2.输出结果是什么?printf("%zd\n", sizeof(*arr));//3.输出结果是什么?printf("%zd\n", sizeof(arr[1]));//4.输出结果是什么?printf("%zd\n", sizeof(&arr));//5.输出结果是什么?printf("%zd\n", sizeof(&arr + 1));//6.输出结果是什么?printf("%zd\n", sizeof(&arr[0] + 1));//7.输出结果是什么?return 0;
}

这里需要注意的是: 由于arr里面存放的是字符串,我们知道\0是字符串的结束标志,所以里面默认存放的是有\0的。
如下所示:
在这里插入图片描述

大家不妨先思考这几道题,待会我们会统一讲解一下。
在这里插入图片描述

▶️2.2.3字符数组和指针笔试题解析:💯

1.我们知道sizeof(数组名)是计算整个数组的大小。
那这里数组里面有7个元素,而且该数组为char类型,所以每个元素是占一个字节,那这里就总共占了7个字节。
2.这里的arr+0 表示arr跳过0个元素,本质上还是首元素的地址,所以大小就是4/8个字节。
3.arr表示数组首元素的地址,*arr就是首元素,大小就是1字节
4.arr[1]是第二个元素,大小也是1字节。
5.&arr是数组的地址,但是也是地址,是地址大小就是4/8个字节。

这里我们重点详解一下第六题和第七题
如下图所示:
在这里插入图片描述
6.从上图,我们发现&arr+1指向的是\0后面的地址,因此我们可以推导出&arr+1就是跳过整个数组的那个地址。大小为4/8个字节。

如下图所示:
在这里插入图片描述
7.同样地,我们从上图发现&arr[0]+1指向的是数组中第二个元素的地址,所以它的大小为4/8个字节。

▶️2.2.3.1 VS运行结果展示:💯

我们不妨用vs测试一下结果,看看分析的是否正确~

x86环境运行结果:
在这里插入图片描述
x64环境运行结果
在这里插入图片描述



▶️2.2.4 字符数组和指针笔试题4💯

题目如下:

int main() {//字符数组2.2char arr[] = "abcdef";printf("%d\n", strlen(arr));//1.输出结果是什么呢?printf("%d\n", strlen(arr + 0));//2.输出结果是什么呢?printf("%d\n", strlen(*arr));//3.输出结果是什么呢?printf("%d\n", strlen(arr[1]));//4.输出结果是什么呢?printf("%d\n", strlen(&arr));//5.输出结果是什么呢?printf("%d\n", strlen(&arr + 1));//6.输出结果是什么呢?printf("%d\n", strlen(&arr[0] + 1));//7.输出结果是什么呢?return 0;
}

大家不妨先思考这几道题,待会我们会统一讲解一下。
在这里插入图片描述

▶️2.2.4字符数组和指针笔试题解析:💯

如下图所示:
在这里插入图片描述
1.我们发现strlen(arr) 本质上就是把首元素的地址a传给strlen函数,然后strlen就往后找\0,统计\0之前的个数,从上图,我们能直观地分析到\0之前有6个元素个数,因此它的输出结果是6。
2.同样地,我们发现arr+0 还是首元素跳过0个元素,本质上还是把首元素的地址传给strlen函数,统计\0之前的字符个数,所以它的输出结果依然是6。
3.这里我们前面已经介绍过,* arr就是数组首元素a,它的Ascll码值为97当做地址传给strlen函数,但是这个地址属于是非法访问,因此会出现报错情况。
4.同样地,arr[1]就是数组首元素a,它的Ascll码值为98当做地址传给strlen函数,但是这个地址属于是非法访问,因此会出现报错情况。
5.我们前面已经介绍过这里的&arr本质上它的类型就是char (* p)[7],当我们把这个数组地址传入strlen函数内部,会把它强转为char*类型
站在strlen函数的角度,它依然拿到的是arr起始位置的地址,也就是从字符a的地址向后数的,直到遇到\0为止,所以它的输出结果也是6。

如下图所示:
在这里插入图片描述
6.我们从上图发现&arr+1是指向\0的后面,因此它后面内存放的是什么,以及后面是否有\0,我们是不知道的。
因此它的输出是个随机值。

如下图所示:
在这里插入图片描述
7.从上图,我们更能直观地发现,&arr[0]+1指向的是字符b的地址,当我们把字符b的地址传入strlen函数,
会统计字符b的地址到\0之间的字符个数。 所以它的输出结果就是5。

▶️2.2.4.1 VS运行结果展示:💯

由于我们发现第三题和第四题的结果输出是报错的,我们先用注释把它屏蔽掉,再拿vs来运行此代码。

这里博主用x64环境下运行此代码:
在这里插入图片描述
从上图,我们发现第六题输出结果是26,是个随机值。
在这里插入图片描述
另外,虽然VS编译器中运行没有报错,但是我们仔细查看的话,会发现&arr是一个数组指针类型,它跟strlen函数参数const char * 指针类型不太一样,所以这里有可能会出现被警告情况。



▶️2.2.5 字符数组和指针笔试题5💯

题目如下:

#include <stdio.h>
int main() {//字符数组3.1char* p = "abcdef";printf("%zd\n", sizeof(p));//1.输出结果是什么printf("%zd\n", sizeof(p + 1));//2.输出结果是什么printf("%zd\n", sizeof(*p));//3.输出结果是什么printf("%zd\n", sizeof(p[0]));//4.输出结果是什么printf("%zd\n", sizeof(&p));//5.输出结果是什么printf("%zd\n", sizeof(&p + 1));//6.输出结果是什么printf("%zd\n", sizeof(&p[0] + 1));//7.输出结果是什么return 0;
}

如下图所示:
在这里插入图片描述

这里大家需要注意的是我们根据上图可以知道,这里的"abcdef"本质上是一个常量字符串,这里的常量字符串的首字符的地址是放到指针变量p里面去。假设a的地址为0x0012ff40,那么p的地址放的也是0x0012ff40,正因为有这个地址才能找到它。

大家不妨先思考这几道题,待会我们会统一讲解一下。
在这里插入图片描述

▶️2.2.5字符数组和指针笔试题解析:💯

1.我们发现:p是一个指针变量,大小是4/8字节。
2.由于我们知道p指向的是a的地址,那么p+1指向的是a的地址,假设p的地址是0xff12ff40那么p+1指向的产生b的地址,也就是0xff12ff41–>‘b’,所以p+1是字符b的地址,大小同样是4/8个字节。
3.我们知道p指向的是a的地址,那* p指向的是字符a,类型是char *, 所以 * p是首字符,大小为1个字节。

如下图所示:
在这里插入图片描述
4.这道题我们用两种方式来解读:
一.我们从上图发现:我们发现,这个字符串画出来也像数组一样,连续放到内存空间里面,假设我们把这个常量字符串想象成一个数组,
那它有下标,a的下标为0,b的下标为1,c的下标为2,以此类推,可以得知f的下标为5。
数组名也是数组首元素的地址,那么p可以理解为后面这个数组名,那p[0]访问数组下标为0的元素。也就是字符a,同样也是占了一个字节。
二.p[0]从计算的角度被转换为*(p+0)是这个a的地址,那(p+0)也是这个位置的地址。
那解引用不就是对这个a访问吗?也就是占了一个字节。

如下图所示:
在这里插入图片描述

5.从上图,我们知道&p相当于是个二级指针,是p的地址,既然是地址,那地址大小就是4/8个字节。

如下图所示:
在这里插入图片描述
6.这道题我们先举个例子,比如从上图,我们得知* p是访问一个整型的大小,p+1是跳过一个整型。 接着看下图
在这里插入图片描述
然后,我们知道,p的类型其实是char *,那如果我们&p我就会把这个地址放到 ** pp,那pp的类型就是char ** 类型的。

char *p;//1.
char ** pp=&p;//2.

从上面第二行代码我们知道:pp是一个char ** 类型的,第二行代码中pp左边的那个* 代表pp是一个指针,而前面的char *表示pp指向的对象是p,它的类型为char *,而第一行的char *和第二行的 char *是一致的。
这足矣说明第二行的代码char * 表示p所指向的对象就是char * 。 那我们是不是能得出这个结论:
&p+1=pp+1?因为我们把&p交给pp了,所以&p+1=pp+1,那pp+1要跳过几个字节,是不是跳过一个char * 对象的大小,那大家想象一下。
在这里插入图片描述
如上图红框所示:如果说pp指向p的话,p的地址是0x0012ff40。 那pp的地址也是0x0012ff40,那pp要跳过一个char * 对象的话,那此时p不就是char *类型的对象吗?
那把char *对象跳过的话,不是指向0地址处后面的地址吗?实际上,它就是跳过一个指针变量的大小,从p所在空间的内部跳过去的,因为这块空间用的是自己的地址,那这+1就整块空间到了p后面的地址。

总结:因为&p+1也是地址,&p+1是跳过p变量后的地址。那大小就是4/8个字节。

7.因为我们前面已经介绍过p[0]是首字符a,那我们把它的地址取出来,就是a的地址,+1,那也就是b的地址对不对。
同样地,它的大小是占4/8个字节。

▶️2.2.5.1 VS运行结果展示:💯

我们用vs来测试一下,看看我们分析的结果是否正确?
我们分别以x64和x86环境来演示一下
在这里插入图片描述

x64环境:
在这里插入图片描述
x86环境:
在这里插入图片描述



▶️2.2.6 字符数组和指针笔试题6💯

题目如下:

#include <stdio.h>
#include <string.h>int main() {//字符数组3.2char* p = "abcdef";printf("%zd\n", strlen(p));//1.输出结果是什么printf("%zd\n", strlen(p + 1));//2.输出结果是什么printf("%zd\n", strlen(*p));//3.输出结果是什么printf("%zd\n", strlen(p[0]));//4.输出结果是什么printf("%zd\n", strlen(&p));//5.输出结果是什么printf("%zd\n", strlen(&p + 1));//6.输出结果是什么printf("%zd\n", strlen(&p[0] + 1));//7.输出结果是什么return 0;
}

如下图所示:
在这里插入图片描述
需要注意的是:这里的内存布局跟上个题目是一样的,同样指针变量p拿到的是字符串中首字符a的地址。

好了,大家先思考这七道题的输出结果是什么,等下我们会进行细致的讲解~
在这里插入图片描述

▶️2.2.6字符数组和指针笔试题解析:💯

如下图所示:
在这里插入图片描述
1.由于我们知道abcdef是个常量字符串,字符串中是有\0。
通过上图,p中存放的a的地址,然后从a的地址开始往后访问。所以它的字符串长度为6。
2.同样的道理,因为我们已经知道p拿到的首元素a的地址,那么p+1相当于拿到的是字符b的地址,然后往后找\0。

3.因为p是拿到字符a的地址,那么 *p拿到的是a的字符。
但是我们前面已经讲过,它会把字符a的Ascll码值作为地址传给strlen。这就属于是非法访问了,因此会报错。
4.同样地,我们之前讲过,因为p[0]== * (p+0)== * p,因为p拿到首字符a的地址,那(p+0)跳过0个元素同样也是拿到a的地址。
对其进行解引用也是拿到字符a,如果把a的ascll码值传入strlen函数同样也会报错。


5.这道题估计很多同学会误以为它的字符串长度是6。
他们可能以为是从的首元素a的地址往后数。但实际上并不是。接下来我给大家解释一下:
如下图所示:
在这里插入图片描述
它实际上是从p的内存空间往后数的,那p这个内存空间放什么我们知道吗?我们刚刚举的0x0012ff40这个地址我们都是假设的。
我们只是假设它放了这个地址,但是具体编译器里面分配了什么地址,我们是不知道的。当然,这里的地址也不是随机的,编译器一定会指派一个有效的地址,但是它地址的值在内存存的是什么,每个字节放的是什么,我们是不知道的,所以我们这里是不能确定答案的。
这里什么时候遇到\0,我们也是不可知的。
因此我们可以得出以下结论:&p是p的地址,它是从p的所占空间起始位置开始查找的,因此它是个随机值。

当然,有同学可能会有这个疑问,要是p的内存中有00就不是随机值了?

这个想法是错的,我们来给大家解释一下:
在这里插入图片描述
我们在VS的x64环境通过调试,然后观察&p内存,因为x64环境下,指针变量是占8个字节的,因此我们就调成8列,每列分别是一个字节,然后我们发现00是在第七个字节的位置才遇到的,但是也有可能在前面第二个字节,第三个字节遇到00,是不是这个道理呀,所以不一定是第七个。 所以这个随机值我们是无法预测的。

如下图所示:
在这里插入图片描述
6.从图中,我们可以看出&p指向的是p的内存空间起始位置,然后&p+1就相当于跳过一个p内存空间的地址,它就指向下一个内存空间的起始位置。
那从这个位置往后,它也是个内存空间啊,那它内存是什么?什么时候遇到\0,我们同样也是不知道的,那从这个位置往后数,这也是不可控的。因此它也是个随机值

需要注意的是:
p所占的空间和字符串所占的空间根本就不是一回事,因为p有p的空间,字符串有字符串的空间,只不过我把字符串的首字符地址放在p里面去,所以这两块内存不一定是连续的,也可能是无关的,因此这是两个独立的空间。

7.p[0]是第一个元素,那&p[0]就是把它的地址取出来,就是a的地址,+1,就是从b的地址一直往后数,一直数到\0,所以它的长度是5。


▶️2.2.6.1 VS运行结果展示:💯

我们用vs来测试一下,看看我们分析的结果是否正确?
首先,先把分析为报错结果的第三题和第四题的代码先注释掉。

然后分别以x64和x86环境来运行一下此代码
x64环境:
在这里插入图片描述如上图,我们发现第五题和第六题的运行结果分别为6和30。
这里可能有同学对于第五题的运行结果有所疑问,为什么在x64环境下
printf("%zd\n", strlen(&p);
这行代码的运行结果是6,但其实它这个是随机值。为什么呢?
原因如下:
在这里插入图片描述
如上图所示:我们通过调试发现恰好那个\0刚好在内存空间p的第七个字节的位置,所以它的字符串长度恰好为。
但是它跟字符串长度是没有任何关系的。
比如说,我们将它那个常量字符串改为10,它运行起来一样是为6的。
如下:
在这里插入图片描述

x86环境:
在这里插入图片描述同样地,我们拿x86环境下运行,第五题和第六题运行结果同样是一个随机值。

总结: 这里我们三种不同类型的字符数组都进行了讲解,分别是:
1.拿多个字符来初始化一个字符数组的。这里面是没有\0。
2.拿一个字符串来初始一个数组的情况,这里面的字符串是包括了\0。
3.拿一个字符指针来指向一个常量字符串的情况,它里面虽然是有\0,但是p不是一个数组空间,它是一个变量空间,这个变量存放着p的地址。

希望博主讲的这三种类型的字符数组,大家能理解透彻!!
在这里插入图片描述另外,博主这里只是讲一部分的数组和指针的笔试题,还有一部分的笔试题留到下次的博客再讲解哦~
** 如果觉得博主写的不错的话,**
在这里插入图片描述
欢迎大家一键三连支持一下博主,谢谢大家!!!

相关文章:

C语言-数组指针笔试题讲解(1)-干货满满!!!

文章目录 ▶️1.sizeof和strlen的对比&#x1f4af;➡️1.1 sizeof是什么&#xff1f;&#x1f4af;➡️1.2sizeof用法举例&#x1f4af;▶️1.3strlen是什么&#xff1f;&#x1f4af;▶️1.4 strlen函数用法举例&#xff1a;&#x1f4af;▶️1.5 strlen和sizeof的对比&#…...

springboot整合vue,将vue项目整合到springboot项目中

将vue项目打包后&#xff0c;与springboot项目整合。 第一步&#xff0c;使用springboot中的thymeleaf模板引擎 导入依赖 <!-- thymeleaf 模板 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-t…...

C++ 二叉搜索树(BST)的实现(非递归版本与递归版本)与应用

C 二叉搜索树的实现与应用 一.二叉搜索树的特点二.我们要实现的大致框架三.Insert四.InOrder和Find1.InOrder2.Find 五.Erase六.Find,Insert,Erase的递归版本1.FindR2.InsertR3.EraseR 七.析构,拷贝构造,赋值运算符重载1.析构2.拷贝构造3.赋值运算重载 八.Key模型完整代码九.二…...

分类预测 | Matlab实现AOA-SVM算术优化支持向量机的数据分类预测【23年新算法】

分类预测 | Matlab实现AOA-SVM算术优化支持向量机的数据分类预测【23年新算法】 目录 分类预测 | Matlab实现AOA-SVM算术优化支持向量机的数据分类预测【23年新算法】分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现AOA-SVM算术优化支持向量机的数据分类预测…...

代码随想录算法训练营第七天 | 454.四数相加II、383. 赎金信、15. 三数之和 、18. 四数之和

454.四数相加II 题目链接&#xff1a;454.四数相加II 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 < i, j, k, l < nnums1[i] nums2[j] nums3[k] nums4[l] 0…...

SpringBoot 3.2.0 版本 mysql 依赖下载错误

最近想尝试一下最新的 SpringBoot 项目&#xff0c;于是将自己的开源项目进行了一些升级。 JDK 版本从 JDK8 升级至 JDK17。SpringBoot 版本从 SpringBoot 2.7.3 升级到 SpringBoot 3.2.0 其中 JDK 的升级比较顺利&#xff0c;毕竟 JDK 的旧版本兼容性一直非常好。 但是在升级…...

内网穿透的应用-如何结合Cpolar内网穿透工具实现在IDEA中远程访问家里或者公司的数据库

文章目录 1. 本地连接测试2. Windows安装Cpolar3. 配置Mysql公网地址4. IDEA远程连接Mysql小结 5. 固定连接公网地址6. 固定地址连接测试 IDEA作为Java开发最主力的工具&#xff0c;在开发过程中需要经常用到数据库&#xff0c;如Mysql数据库&#xff0c;但是在IDEA中只能连接本…...

ElasticSearch单机或集群未授权访问漏洞

漏洞处理方法&#xff1a; 1、可以使用系统防火墙 来做限制只允许ES集群和Server节点的IP来访问漏洞节点的9200端口&#xff0c;其他的全部拒绝。 2、在ES节点上设置用户密码 漏洞现象&#xff1a;直接访问9200端口不需要密码验证 修复过程 2.1 生成认证文件 必须要生成…...

【华为OD题库-097】最大岛屿体积-java

题目 题目描述 给你一个由大于0的数&#xff08;陆地)和0(水)组成的的二维网格&#xff0c;请你计算网格中最大岛屿的体积。陆地的数表示所在岛屿的体积。岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#xff0c;你可以假…...

HTML中边框样式、内外边距、盒子模型尺寸计算(附代码图文示例)【详解】

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍HTML中边框样式、内外边距、盒子模型尺寸计算以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习记录获&#xff0c;友友们有任何问…...

drf入门规范

一 Web应用模式 在开发Web应用中&#xff0c;有两种应用模式&#xff1a; 1.1 前后端不分离 1.2 前后端分离 二 API接口 为了在团队内部形成共识、防止个人习惯差异引起的混乱&#xff0c;我们需要找到一种大家都觉得很好的接口实现规范&#xff0c;而且这种规范能够让后端写…...

【微服务】springboot整合minio详解

目录 一、前言 二、Minio 概述 2.1 Minio简介 2.1 Minio特点 三、Minio 环境搭建 3.1 部署过程 3.1.1 拉取镜像 3.1.2 启动容器 3.1.3 访问web页面 四、Minio基本使用 4.1 基本概念 4.2 上传文件演示 4.3 用户管理 4.4 Java操作Minio 4.4.1 导入依赖 4.4.2 上传…...

减速机振动相关标准 - 笔记

参考标准&#xff1a;国家标准|GB/T 39523-2020 减速机的振动标准与发动机不同&#xff0c;摘引&#xff1a; 原始加速度传感器波形 可以明显看到调幅波 它的驱动电机是300Hz~2000Hz范围的。这个采样时间是5秒&#xff0c;看分辨率至少1024线。可分出500条谱线。 频谱部分 …...

【matlab】MATLAB 中的标量运算及实例

MATLAB 中的标量运算及实例 引言 在 MATLAB 中,标量是指只包含单个数值的变量或常量。尽管标量运算可能看似简单,但它在数值计算、数据处理和算法设计中扮演着重要的角色。本文将深入探讨 MATLAB 中的标量运算,介绍其基本操作和一些实例应用。 1. 标量运算的基本操作 标…...

java简易制作-王者荣耀游戏

一.准备工作 首先创建一个新的Java项目命名为“王者荣耀”&#xff0c;并在src下创建两个包分别命名为“com.sxt"、”com.stx.beast",在相应的包中创建所需的类。 创建一个名为“img”的文件夹来储存所需的图片素材。 二.代码呈现 package com.sxt; import javax…...

手撕分布式缓存---多节点的调取

经过上一个章节的学习&#xff0c;我们已经知晓了如何搭建了HTTP Server&#xff0c;通过HTTP协议与我们定义的路由&#xff0c;我们可以远程访问这个节点&#xff1b;基于这一点&#xff0c;我们可以部署多台实现了HTTP的缓存服务从而实现分布式的特性。这一章节我们要基于此背…...

C/C++编程中的算法实现技巧与案例分析

C/C编程语言因其高效、灵活和底层的特性&#xff0c;被广大开发者用于实现各种复杂算法。本文将通过10个具体的算法案例&#xff0c;详细探讨C/C在算法实现中的技巧和应用。 一、冒泡排序&#xff08;Bubble Sort&#xff09; 冒泡排序&#xff08;Bubble Sort&#xff09;是一…...

干货分享 | 如何在TSMaster中对常用总线报文信号进行过滤?

TSMaster软件平台支持对不同总线&#xff08;CAN、LIN、FlexRay&#xff09;的报文和信号过滤&#xff0c;过滤方法一般有全局接收过滤、数据流过滤、窗口过滤、字符串过滤、可编程过滤&#xff0c;针对不同的总线信号过滤器的使用方法也基本相同。今天重点和大家分享一下关于T…...

k8s链接数据库故障Waiting for table metadata lock

场景&#xff1a;早上来发现一个程序&#xff0c;链接mysql数据库有点问题&#xff0c;随后排查&#xff0c;因为容器在k8s里面。所以尝试重启了pod没有效果 一、重启pod: 这里是几种在Kubernetes中重启Pod的方法: 删除Pod,利用Deployment重建 kubectl delete pod mypodDepl…...

数字经济如何驱动企业高质量发展? ——核心机制、模式选择与推进路径

文章目录 每日一句正能量前言核心机制信息化和智能化作为数字经济的核心机制信息化和智能化如何提升企业生产效率和管理水平数据的获取、分析和利用对企业发展的影响 模式选择电子商务模式的选择共享经济模式的选择数据驱动的业务模式选择 推进路径建设数字化基础设施培养数字化…...

机器学习——支持向量机

目录 一、基于最大间隔分隔数据 二、寻找最大间隔 1. 最大间隔 2. 拉格朗日乘子法 3. 对偶问题 三、SMO高效优化算法 四、软间隔 五、SMO算法实现 1. 简化版SMO算法 2. 完整版SMO算法 3. 可视化决策结果 六、核函数 1. 线性不可分——高维可分 2. 核函数 …...

mq的作用

使用mq优点 mq是一种常见的中间件&#xff0c;在项目中经常用到&#xff0c;它具有异步、解耦、削峰填谷的作用。 异步 比如下单流程&#xff0c;A服务—>B服务&#xff0c;总的耗时是A耗时时间B耗时时间&#xff0c;而改为A—>mq---->B后&#xff0c;A发送mq后立刻…...

AUTOSAR组织引入了Rust语言的原因是什么?有哪些好处?与C++相比它有什么优点?并推荐一些入门学习Rust语言链接等

AUTOSAR(汽车开放系统架构)是一个由汽车制造商、供应商和其他来自电子、半导体和软件行业的公司组成的全球发展伙伴关系,自2003年以来一直致力于为汽车行业开发和引入开放、标准化的软件平台。 AUTOSAR 最近宣布成立一个新的工作组,用于探索在汽车软件中使用 Rust 编程语言…...

基于PyCharm实现串口GUI编程

工具效果如下如所示 下面简单介绍一下操作流程 1.打开PyCharm软件 2.创建一个工程 3.给该工程命名 4.在main.py里面黏贴如下的代码 # This is a sample Python script. # Press ShiftF10 to execute it or replace it with your code. # Press Double Shift to search everyw…...

【1.8计算机组成与体系结构】磁盘管理

目录 1.磁盘基本结构与存取过程1.1 磁盘基本结构1.2 磁盘的存取过程 2.磁盘优化分布存储3.磁盘单缓冲区与双缓冲区4.磁盘移臂调度算法 1.磁盘基本结构与存取过程 1.1 磁盘基本结构 磁盘&#xff1a;柱面&#xff0c;磁道&#xff0c;扇区。 1.2 磁盘的存取过程 存取时间寻…...

1663:【 例 1】取石子游戏 1

【题目描述】 有一种有趣的游戏&#xff0c;玩法如下&#xff1a; 玩家&#xff1a; 2 人&#xff1b; 道具&#xff1a; N 颗石子&#xff1b; 规则&#xff1a; 1、游戏双方轮流取石子&#xff1b; 2、每人每次取走若干颗石子&#xff08;最少取 1 颗&#xff0c;最多取…...

Django去访问web api接口Object of type Session is not JSON serializable

解决方案&#xff1a;settings.py中加入 &#xff1a;SESSION_SERIALIZER django.contrib.sessions.serializers.PickleSerializer 事由&#xff1a;Django去访问一个web api接口&#xff0c;两次连接之间需要通过Session()保持身份验证。 def sendCode(request): mobile jso…...

每日一题,二维平面

给你 二维 平面上两个 由直线构成且边与坐标轴平行/垂直 的矩形&#xff0c;请你计算并返回两个矩形覆盖的总面积。 每个矩形由其 左下 顶点和 右上 顶点坐标表示&#xff1a; 第一个矩形由其左下顶点 (ax1, ay1) 和右上顶点 (ax2, ay2) 定义。 第二个矩形由其左下顶点 (bx1, …...

【jupyter notebook】jupyter notebook 调用另一个jupyter notebook 的函数

总结 使用 %run 魔法命令将 Notebook 转换为py文件使用 nbimporter 库手动复制代码优点notebook最前面加上即可最基本方法就跟导入py文件一样&#xff0c;不会被执行一遍快缺点所有的代码都会执行一遍修改原文件就要重新转换&#xff0c;且 从自定义的 .py 文件中导入函数时&a…...

Linux--学习记录(3)

G重要编译参数 -g&#xff08;GDB调试&#xff09; -g选项告诉gcc产生能被GNU调试器GDB使用的调试信息&#xff0c;以调试程序编译带调试信息的可执行文件g -g hello.c -o hello编译过程&#xff1a; -E&#xff08;预处理&#xff09; g -E hello.c -o hello.i-S&#xff08;编…...