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

news2025/1/23 12:00:12

文章目录

  • ▶️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.2
	char 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.1
   char 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.2
	char 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.1
	char* 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.2
	char* 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.coloradmin.cn/o/1321863.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Axure

目录 一. 交互 1.2 交互事件 二. 情形 2.1 应用场景 三. 案例 3.1 ERP登录 3.2 ERP页面跳转 一. 交互 交互事件是指在用户界面中发生某些操作或行为时&#xff0c;触发相应的响应或动作。在设计网页、应用程序或其他用户界面时&#xff0c;交互事件通常用于实现交互式功…

文件操作(下)

标题的顺序是接着之前写的&#xff0c;希望这篇博客对你有帮助 七. 随机读写函数 实际上&#xff0c;无论是读还是写&#xff0c;在一次调用顺序读写函数&#xff0c;文件指针会移到已经读过或者写过的下一个位置&#xff0c;从那个位置开始下一次读和写&#xff08;在文件没有…

python排序算法,冒泡排序和快排

对于排序算法中比较知名的两个算法&#xff0c;分别就是冒泡排序和快速排序&#xff0c;在日常学习和使用中都会听到这两种排序算法的名称&#xff0c;这里主要介绍如何使用python来实现这两种排序算法。 冒泡排序的实现&#xff1a;一是从集合第一个元素开始&#xff0c;每两…

Ansible:模块1

Ansible&#xff1a; 远程操作主机功能 自动化运维&#xff08;playbook 剧本 yaml&#xff09; 是基于python开发的配置管理和应用部署工具。在自动化运维中&#xff0c;现在是一军突起。 Ansible能批量配置&#xff0c;部署&#xff0c;管理上千台主机。类似于xshell的一…

2023ChatGPT浪潮,2024开源大语言模型会成王者?

《2023ChatGPT浪潮&#xff0c;2024开源大语言模型会成王者&#xff1f;》 一、2023年的回顾 1.1、背景 我们正迈向2023年的终点&#xff0c;回首这一年&#xff0c;技术行业的发展如同车轮滚滚。尽管互联网行业在最近几天基本上处于冬天&#xff0c;但在这一年间我们仍然经…

基于Apache SeaTunnel构建CDC数据同步管道

引言 在快速发展的数据驱动时代&#xff0c;数据的实时、准确同步成为了企业信息系统不可或缺的一部分。随着技术的进步&#xff0c;特别是在分布式计算和大数据技术的背景下&#xff0c;构建一个高效且可靠的数据同步管道成为了挑战。 Apache SeaTunnel作为一个先进的数据集…

数组|73. 矩阵置零 48. 旋转图像

73. 矩阵置零 **题目:**给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 题目链接&#xff1a;矩阵置零 class Solution {public void setZeroes(int[][] matrix) {Stack<int[]> mapofzerone…

产品入门第六讲:Axure中继器

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​​​​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Axure》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c…

解锁终端安全的钥匙:深度了解迅软DSE桌面管理系统

随着信息化的快速发展&#xff0c;企业内部计算机终端数量不断攀升&#xff0c;成为网络整体安全管理的关键环节。越来越多的企业认识到终端安全管理的重要性&#xff0c;纷纷采取综合规划来应对这一挑战。为了满足广大用户对桌面终端管理的需求&#xff0c;迅软DSE推出了一套全…

微博被封禁如何解决

1.电脑搜索互联网信息投诉平台&#xff0c;点击我要投诉 2.找到互联网企业&#xff0c;选择新浪微博 3.然后填写个人信息&#xff0c;这里正常填写就行 4.填写信息 5.截图 6.成功

Qt实现动画的2种方式

由于我之前是写java的所以在学习Qt的时候感觉会有点熟悉&#xff0c;因为Qt就是 用c写&#xff0c;而java底层也是c实现的 先看效果&#xff1a; 一、使用QMovie 这种方式我目前是用来加载gif图的&#xff0c;很简单噢&#xff0c;只不过我是加载的本地的路径&#xff0c;如…

【NSX-T】7. 搭建NSX-T环境 —— 部署和配置 Edge Cluster

目录 7. 部署和配置 Edge Cluster7.1 配置 Edge 节点&#xff08;1&#xff09;Name and Description&#xff08;2&#xff09;Credentials&#xff08;3&#xff09;Configure Deployment&#xff08;4&#xff09;Configure Node Settings&#xff08;5&#xff09;Configur…

APM固件编译和仿真

事情起因 主要想对无人机APM固件进行仿真的算法验证&#xff0c;因实际飞行的过程实际验证太浪费飞机了&#xff0c;所以就先试用仿真对算法进行仿真开发。 一&#xff0c;环境搭建 环境搭建我建议参考官方英文教程&#xff0c;英文教程写的比较全&#xff0c;不懂可以自己使…

使用Python Scrapy设置代理IP的详细教程

目录 前言 一、代理IP的作用和原理 二、Scrapy框架中设置代理IP的方法 步骤1&#xff1a;安装依赖库 步骤2&#xff1a;配置代理IP池 步骤3&#xff1a;创建代理IP中间件 步骤4&#xff1a;激活代理IP中间件 步骤5&#xff1a;运行爬虫程序 三、代码示例 四、常见问题…

数字化医疗新篇章:构建智能医保支付购药系统

在迎接数字化医疗时代的挑战和机遇中&#xff0c;智能医保支付购药系统的建设显得尤为重要。本文将深入介绍如何通过先进的技术实现&#xff0c;构建一套智能、高效的医保支付购药系统&#xff0c;为全面建设健康中国贡献力量。 1. 引言 随着医疗科技的飞速发展&#xff0c;…

「Verilog学习笔记」交通灯

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1nsmodule triffic_light(input rst_n, //异位复位信号&#xff0c;低电平有效input clk, //时钟信号input pass_request,output wire[7:0]clock,output reg…

如何使用示波器探头对被测电路进行检测

对电路信号进行检测之前首先要知道被测电路是什么电路&#xff0c;被测信号是什么信号。盲目地测试或者使用不正确的测量方法&#xff0c;有可能得到错误的波形甚至损坏仪器危及安全。 1、什么是差分信号&#xff1f;什么是单端信号&#xff1f; 差分传输是一种信号传输的技术…

OpenHarmony - 应用开发入门指南

一、了解OpenHarmony OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目, 目标是面向全场景、全连接、全智能时代, 搭建一个智能终端设备操作系统的框架和平台, 促进万物互联产业的繁荣发展。 开放原子开源基金会&#xff1a; 由阿里巴巴、百度、华…

前置接口数据引用指南:自动化测试流程优化技巧

当进行 自动化测试 编排时&#xff0c;测试步骤间的数据传递是至关重要的。 在传统的方式中&#xff0c;一般通过复杂的脚本配置&#xff0c;或者手动复制这些数据&#xff0c;然后再慢慢地粘贴到每个需要它们的地方&#xff0c;以此来实现接口之间的参数传递。这种方式往往效…

openwrt 搭建web

折腾 软路由 有几年了&#xff0c;最近试了下 移动的 IPV6, 既然可以拿到 公网的 IPV6&#xff0c; 所以想折腾下, 经过不懈努力 实现了&#xff1a;通过 ipv4/ipv6 地址访问我的 web站点 (白飘不花钱的方式) 1 动态DNS 折腾 DDNS 无非是想 白飘 公网IP&#xff0c;但是 仅仅…