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的地址。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/220262.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

栈(C语言版)

一.栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守 后进先出 LIFO &#xff08; Last In First Out &#xff09;的原则。…

人工智能数据挖掘:发掘信息的新境界

导言 人工智能数据挖掘作为信息时代的利器&#xff0c;通过智能算法和大数据技术的结合&#xff0c;为企业、学术研究和社会决策提供了前所未有的洞察力。本文将深入探讨人工智能在数据挖掘领域的应用、技术挑战以及对未来的影响。 1. 人工智能数据挖掘的基本原理 数…

回归预测 | MATLAB实现SABO-LSTM基于减法平均优化器优化长短期记忆神经网络的多输入单输出数据回归预测模型 (多指标,多图)

回归预测 | MATLAB实现SABO-LSTM基于减法平均优化器优化长短期记忆神经网络的多输入单输出数据回归预测模型 &#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SABO-LSTM基于减法平均优化器优化长短期记忆神经网络的多输入单输出数据回归预测模型 &a…

CSS3 2D变形 过渡 动画

​​​​​ transform(2D变形)概述translate()平移scale()缩放skew()倾斜rotate()旋转transform-origin中心原点 CSS3 2D变形 3D变形 过渡 动画 在CSS3中&#xff0c;动画效果包括4个部分&#xff1a;变形&#xff08;transform&#xff09;、3D变形、过渡&#xff08;transit…

数据结构(Chapter Two -02)—顺序表基本操作实现

在前一部分我们了解线性表和顺序表概念&#xff0c;如果有不清楚可以参考下面的博客&#xff1a; 数据结构(Chapter Two -01)—线性表及顺序表-CSDN博客 首先列出线性表的数据结构&#xff1a; #define MaxSize 50 //定义顺序表最大长度 typedef struct{ElemType data…

数据可视化---双Y轴折线图比较

内容导航 类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统…

<软考高项备考>《论文专题 - 15 资源管理(一) 》

1 写作要点 过程定义、作用写作要点、思路规划资源管理是定义如何估算、获取、管理和利用团队以及实物资源的过程。作用:根据项目类型和复杂程度确定适用于项目资源的管理方法和管理程度。资源管理计划的内容、编写的原则&#xff08;考虑资源竞争、稀缺资源、争取资源等&…

SQL进阶理论篇(十二):InnoDB中的MVCC是如何实现的?

文章目录 简介事务版本号行记录的隐藏列Undo LogRead View的工作流程总结参考文献 简介 在不同的DBMS里&#xff0c;MVCC的实现机制是不同的。本节我们会以InnoDB举例&#xff0c;讲解InnoDB里MVCC的实现机制。 我们需要掌握这么几个概念&#xff1a; 事务版本号行记录的隐藏…

TrustZone之其他设备及可信基础系统架构

一、其他设备 最后,我们将查看系统中的其他设备,如下图所示: 我们的示例TrustZone启用的系统包括一些尚未涵盖的设备,但我们需要这些设备来构建一个实际的系统。 • 一次性可编程存储器(OTP)或保险丝 这些是一旦写入就无法更改的存储器。与每个芯片上都包含相同…

基础算法(3):排序(3)插入排序

1.插入排序实现 插入排序的工作原理是&#xff1a;通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已经排序的序列从后向前扫描&#xff0c;找到位置并插入&#xff0c;类似于平时打扑克牌时&#xff0c;将牌从大到小排列&#xff0c;每次摸到一张牌就插入到正确的位…

202352读书笔记|踪迹——在繁星般的黄的交错里,秦淮河仿佛笼上了一团光雾

《踪迹》朱自清&#xff0c;因为春&#xff0c;匆匆&#xff0c;背影&#xff0c;疯狂入坑。学生时代&#xff0c;我的语文并不好&#xff0c;可害怕写作文了。对于文章/古文/诗都是比较浅显的学习&#xff0c;从未探究深意&#xff0c;可以说并没有学明白。是比较跳脱而表面的…

Docker 的基本概念、优势、及在程序开发中的应用

Docker 是一种容器化平台,它通过使用容器化技术,将应用程序及其依赖性打包到一个独立的、可移植的容器中,从而实现应用程序的快速部署、可靠性和可扩展性。 下面是 Docker 的一些基本概念和优势: 容器:Docker 使用容器化技术,将应用程序及其依赖性打包到一个可移植的容器…

不做数据采集,不碰行业应用,专注数字孪生PaaS平台,飞渡科技三轮融资成功秘诀

12月15日&#xff0c;飞渡科技在北京举行2023年度投资人媒体见面会&#xff0c;全面分享其产品技术理念与融资之路。北京大兴经开区党委书记、管委会主任常学智、大兴经开区副总经理梁萌、北京和聚百川投资管理有限公司&#xff08;以下简称“和聚百川”&#xff09;投资总监严…

ChatGPT使用:一个发包机器人的提示词

发包机器人&#xff1a; 设想&#xff1a;目前项目组有n条打包线会输出多个包&#xff0c;用户想获取最新的包是比较困难的&#xff0c;难点在于 1. 分支多&#xff1a;trunk&#xff0c;release&#xff0c;outer等&#xff0c;至少有3个分支&#xff1b; 2. 多平台&#x…

分布式理论 | RPC | Spring Boot 整合 Dubbo + ZooKeeper

一、基础 分布式理论 什么是分布式系统&#xff1f; 在《分布式系统原理与范型》一书中有如下定义&#xff1a;“分布式系统是若干独立计算机的集合&#xff0c;这些计算机对于用户来说就像单个相关系统”&#xff1b; 分布式系统是由一组通过网络进行通信、为了完成共同的…

入侵检测系统HIDS_wazuh使用及部署

文章目录 wazuh简介wazuh在线文档及下载资源虚拟机默认用户是&#xff1a; 访问页面登录&#xff0c;默认是用户&#xff1a;admin&#xff0c;密码&#xff1a;admin进入系统后页面点击代理总数选择需要添加的主机需要检测的主机测试是否ping通wazuh服务机测试访问通后&#x…

搭建动态网站之——基于Redhat8.6搭建Discuz论坛

一、动态网站与静态网站区别 动态网站并不是指具有动画功能的网站&#xff0c;而是指网站内容可根据不同情况动态变更的网站&#xff0c;一般情况下动态网站通过数据库进行架构。 动态网站除了要设计网页外&#xff0c;还要通过数据库和编程序来使网站具有更多自动的和高级的功…

数据仓库与数据挖掘c5-c7基础知识

chapter5 分类 内容 分类的基本概念 分类 数据对象 元组(x,y) X 属性集合 Y 类标签 任务 基于有标签的数据&#xff0c;学习一个分类模型&#xff0c;通过这个分类模型&#xff0c;可以把一组属性x映射到一个特定的类别y上 类别y 提前设定好的--如&#xff1a;学生…

机器学习---推荐系统案例(一)

一、推荐系统-数据处理流程 推荐系统数据处理首先是将Hive中的用户app历史下载表与app浏览信息表按照设备id进行关联&#xff0c;然后将关联数据使用python文件进行处理&#xff0c;将数据预处理为label和feature两列的临时数据&#xff0c;后期经过处理转换成逻辑回归 模型的…

任务十六:主备备份型防火墙双机热备

目录 目的 器材 拓扑 步骤 一、基本配置 配置各路由器接口的IP地址【省略】 1、配置BGP协议实现Internet路由器之间互联 2、防火墙FW1和FW2接口IP配置与区域划分 3、配置区域间转发策略 4、配置NAPT和默认路由 5、配置VRRP组&#xff0c;并加入Active/standby VGMP管…