【C语言进阶技巧】指针解密:炼金术士的秘密面试题揭秘

news2024/10/5 16:22:04

【C语言进阶技巧】指针解密:炼金术士的秘密面试题揭秘

  • 1. 主要涉及sizeof与strlen函数的使用的笔试题
    • 1.1 笔试题一(一维整形数组)
    • 1.2 笔试题二(不带\0的字符数组)
    • 1.3 笔试题三(带\0的字符数组)
    • 1.4 笔试题四 (字符指针形式的字符串)
    • 1.5 笔试题五(二维整形数组)
  • 2. 无明显特征的笔试题
    • 2.1 笔试题一
    • 2.2 笔试题二
      • 2.2.1 %x与%p
    • 2.3 笔试题三
    • 2.4 笔试题四
    • 2.5 笔试题五
    • 2.6 笔试题六
    • 2.7 笔试题七
    • 2.8 笔试题八

❤️博客主页: 小镇敲码人
🍏 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌞回来6天了,加油!!!🍎🍎🍎
❤️二十岁出头的时候,请把自己摆在二十岁出头的位置上。踏实的学习,好好积累能力和锻炼心智。那些远大的目标,不管你如何幻想,都不如当下多看一页书,多学一点东西,每天早起奋斗,来的实际。 💞 💞 💞

1. 主要涉及sizeof与strlen函数的使用的笔试题

在做这类题型之前我们首先要回顾一下数组名代表什么?
数组名代表数组首元素的地址,但下面两种情况例外:
1. sizeof(数组名),此时的数组名,代表整个数组,计算的是整个数组的大小,单位是字节。
2. &数组名,这里的数组名也代表整个数组,取出的是整个数组的大小。

然后我们介绍一下sizeof和stlren:

  1. sizeof

sizeof是C语言中的一个关键字,用来计算类型所占内存的大小,单位是字节。

  1. strlen
    在这里插入图片描述

由图可知,strlen是C语言标准库'string.h'中的一个函数,用来计算字符串的长度(不包含\0),这个函数的参数是一个字符指针,并且有const修饰字符串,代表strlen只计算字符的个数,而不会修改字符串,返回值是size_t类型(无符号整形,返回的是字符串的长度,意思是字符串的长度不会出现负数的情况,当遇见\0时,这个函数才会返回一个值。

1.1 笔试题一(一维整形数组)

  • sizeof只关注里面()的类型,不会去去计算表达式的值。
  • 32位和64位地址的大小不同,分别是4/8字节。
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16
	printf("%d\n", sizeof(a + 0));//4/8
	printf("%d\n", sizeof(*a));//4
	printf("%d\n", sizeof(a + 1));//4/8
	printf("%d\n", sizeof(a[1]));//4
	printf("%d\n", sizeof(&a));//4/8
	printf("%d\n", sizeof(*&a));//16
	printf("%d\n", sizeof(&a + 1));//4/8
	printf("%d\n", sizeof(&a[0]));//4/8
	printf("%d\n", sizeof(&a[0] + 1));//4/8
}
  1. printf("%d\n", sizeof(a));a在这里代表整个数组,所以计算的是整个数组的大小为 16 16 16
  2. printf("%d\n", sizeof(a + 0));a+0代表的是首元素的地址,是地址,就是4/8。
  3. printf("%d\n", sizeof(*a));*a的类型是int型,答案是4。
  4. printf("%d\n", sizeof(a + 1));a+1的类型是指针,答案是4/8。
  5. printf("%d\n", sizeof(a[1]));a[1]与*a是等效的,它的类型也是int型,答案是4。
  6. printf("%d\n", sizeof(&a));&a的类型是指针,答案是4/8。
  7. printf("%d\n", sizeof(*&a));//*和&抵消,就等价于sizeof(a),和第一个一样,答案是16。
  8. printf("%d\n", sizeof(&a + 1));&a+1的类型是指针,答案是4/8。
  9. printf("%d\n", sizeof(&a[0]));&a[0]代表第一个元素的地址,地址就是4/8。
    也可以这样理解,&a[0]等价于&*(a+0),&和*抵消,所以这题和第二题一样,答案就是4/8。
  10. printf("%d\n", sizeof(&a[0] + 1));&a[0]是首元素地址,加一指向下一个元素,还是地址,所以答案就是4/8。
    运行结果:(32位)
    在这里插入图片描述
    这里给出64位的运行结果,后面的题只给32位:
    在这里插入图片描述

1.2 笔试题二(不带\0的字符数组)

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));//6
	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));//随机值
	printf("%d\n", strlen(arr + 0));//随机值
	printf("%d\n", strlen(*arr));//err
	printf("%d\n", strlen(arr[1]));//err
	printf("%d\n", strlen(&arr));//随机值
	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//随机值
}
  1. printf("%d\n", sizeof(arr));此时的数组名代表整个数组,计算的是整个数组的大小,所以答案是6。
  2. printf("%d\n", sizeof(arr + 0));arr+0代表第一个元素的地址,是地址,所以答案就是4/8。
  3. printf("%d\n", sizeof(*arr));由于arr除了和sizeof单独在一起表示整个数组,其余情况都是表示首元素地址,所以解引用后,*arr就代表数组的第一个元素,它的类型是char,所以答案是1。
  4. printf("%d\n", sizeof(arr[1]));arr[1]从数组的角度来理解,是代表第二个元素,它的类型是char,所以答案是1。从指针的角度来理解,[]与*等价,所以arr[1]可以写为*(arr+1),arr是首元素地址,加一,跳过一个字节,指针指向第二个元素,解引用后,代表第二个元素,类型是char,答案是1。
  5. printf("%d\n", sizeof(&arr));类型是指针,答案是4/8。
  6. printf("%d\n", sizeof(&arr + 1));类型是指针,答案是4/8。
  7. printf("%d\n", sizeof(&arr[0] + 1));[]和*等价,&arr[0]+1,可以写为&*(arr+0)+1,*和&抵消,再等价变为,arr+1,代表第二个元素的地址,答案是4/8。
  8. printf("%d\n", strlen(arr));arr是首元素地址,strlen遇见\0才会返回值,但这个数组不是字符串不会默认加上\0,所以算出的长度是一个随机值。
  9. printf("%d\n", strlen(arr + 0));arr+0也是首元素地址,答案也是随机值由于,数组是连续存储,它分配的地址也是连续的一块,但这一块具体是哪里,每一次都不同,所以这个随机值的结果每一次都不同,但答案和8的答案相同,因为程序开始运行,数组的地址已经分配好了,所以它遇见的\0和第8行代码遇见的\0是同一个\0
  10. printf("%d\n", strlen(*arr));strlen函数的参数是一个字符指针,arr代表首元素地址,解引用后是一个字符,所以这个代码是错误的,程序会崩溃。
  11. printf("%d\n", strlen(arr[1]));arr[1]是第二个字符,情况和10的情况一样。
  12. printf("%d\n", strlen(&arr));&arr代表整个数组的地址,但它的值和arr是一样的,所以答案也是随机值,和8一样,这里VS的编译器会报警告,因为&arr是数组指针类型,而strlen函数的参数是字符指针,但不影响程序的运行。
  13. printf("%d\n", strlen(&arr + 1));&arr是整个数组的地址虽然值和arr一样但是类型不一样,+1跳过整个数组,结果是随机值,比8的值要小6。
  14. printf("%d\n", strlen(&arr[0] + 1));&arr[0]是首元素的地址,+1代表第一个元素的地址,是随机值,但结果比8的结果小了1。

运行结果:在这里插入图片描述

  • 这里我们没有把错误的代码注释,可以看到,程序进行到那个错误的代码那里就崩溃了。
    当我们把两个错误的代码注释后,运行结果是这样的:
    在这里插入图片描述
  • 注意:我们发现两次运行8、9的结果是不同的,因为编译器给数组重新分配了一块新的地址,第一个\0的位置也不同了。

1.3 笔试题三(带\0的字符数组)

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdef";
	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));//err
	printf("%d\n", strlen(arr[1]));//err
	printf("%d\n", strlen(&arr));//6
	printf("%d\n", strlen(&arr + 1int));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//5
	return 0;
}
  • 字符串是字符数组的一种类型,区别是字符串编译器会默认在它最后一个非\0字符后面加上\0。
  1. printf("%d\n", sizeof(arr));此时的数组名代表整个数组,计算的是整个数组的大小,所以答案是7,因为字符串结尾默认带一个\0,也存入了数组中。
  2. printf("%d\n", sizeof(arr+0));表示首元素地址,答案为4/8。
  3. printf("%d\n", sizeof(*arr));表示首元素,类型是char,所以答案是1。
  4. printf("%d\n", sizeof(arr[1]));表示第二个元素,类型也是char,答案是1。
  5. printf("%d\n", sizeof(&arr));表示整个数组的地址,类型是指针,答案是4/8。
  6. printf("%d\n", sizeof(&arr+1));类型为指针,答案是4/8。
  7. printf("%d\n", sizeof(&arr[0]+1));类型为指针,答案是4/8。
  8. printf("%d\n", strlen(arr));strlen计算字符串长度以\0为结束标志,但是不计入\0,arr表示首元素地址,所以答案是就是字符串字符的个数(不含\0)为6。
  9. printf("%d\n", strlen(arr+0));表示首元素地址,答案是6。
  10. printf("%d\n", strlen(*arr));程序会崩溃,因为*arr是首字符,strlen函数参数是指针。
  11. printf("%d\n", strlen(arr[1]));程序会崩溃,因为*arr是首字符,strlen函数参数是指针。
  12. printf("%d\n", strlen(&arr));&arr是数组的地址,它的值和数组首元素的值一样,所以答案是6。
  13. printf("%d\n", strlen(&arr+1));&arr+1,指针跳过的是一个数组的大小,所以指针指向\0的后面,答案是一个随机值。
  14. printf("%d\n", strlen(&arr[0]+1));&arr[0]是首元素的地址,+1是第二个元素的地址,所以答案是5。
    运行结果:
    在这里插入图片描述

1.4 笔试题四 (字符指针形式的字符串)

int main()
{
	char* p = "abcdef";
	printf("%d\n", sizeof(p));//4
	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));//err
	printf("%d\n", strlen(p[0]));//err
	printf("%d\n", strlen(&p));//随机值
	printf("%d\n", strlen(&p + 1));//随机值
	printf("%d\n", strlen(&p[0] + 1));//5
	return 0;
}
  • p是一个字符指针,存放首字符a的地址。
    在这里插入图片描述
  1. printf("%d\n", sizeof(p));p是指针变量,所以答案是4/8。
  2. printf("%d\n", sizeof(p+1));p+1也是指针变量,答案是4/8。
  3. printf("%d\n", sizeof(*p));p是一个字符指针,存放首字符a的地址,*p是首字符,类型是char,所以答案是1。
  4. printf("%d\n", sizeof(p[0]));p[0] -> *(p+0),代表首字符,类型是char,故答案是1。
  5. printf("%d\n", sizeof(&p));&p是存放字符指针的地址,是地址所以答案就是4/8。
  6. printf("%d\n", sizeof(&p+1));&p+1,也是指针,因为char*类型是指针,所以&p+1要跳过4/8个字节,指向一个char*类型的变量,并存放它的地址,不过它既然是指针变量,那么答案就是4/8字节。
  7. printf("%d\n", sizeof(&p[0]+1));&p[0] -> &*(p+0)为第一个字符的地址,加上1,就代表第二个字符的地址,类型是指针变量,那么答案就是4/8。
  8. printf("%d\n", strlen(p));p是首字符的地址,strlen算的是字符串的长度,所以答案是6。
  9. printf("%d\n", strlen(p+1));p+1是第2个字符的地址,从这个字符往后数,直到遇见\0结束,所以答案是5。
  10. printf("%d\n", strlen(*p));*p代表首字符,strlen应该传地址,程序会崩。
  11. printf("%d\n", strlen(p[0]));p[0] -> *(p+0)也是首字符,和10一样程序会崩。
  12. printf("%d\n", strlen(&p));&p是二级指针,存储着指针变量p的地址,除了两次解引用可以找到首字符,它和字符串没有任何关系,这一点和数组是有区别的,所以我们不知道什么时候会遇见\0,答案是随机值。
  13. printf("%d\n", strlen(&p+1));&p+1也是一个地址,指针加1在原先位置跳过四个字节,储存那个位置的地址,同样的传给strlen,我们也不清楚什么时候会遇见\0,答案是随机值。
    15.printf("%d\n", strlen(&p[0]+1));由上面第11题可以知道&p[0]等价于p,和第9题一样,答案是5。

运行结果:
在这里插入图片描述

  • 这里我们没有把错误的代码注释,可以看到,程序进行到那个错误的代码那里就崩溃了。当我们把两个错误的代码注释后,运行结果是这样的:
    在这里插入图片描述

1.5 笔试题五(二维整形数组)

在做题前对二维数组的a[i]做一下阐述:
在这里插入图片描述

  • 二维数组是一维数组的数组。
  • 二维数组的数组名代表首元素地址,也就是第一行的地址,单独放在sizeof内部代表整个数组
  • a[i]代表第i行的数组名,一般情况下表示第i行首元素的地址,单独放在sizeof内部表示那一行的大小。
int main()
{
	//二维数组
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48
	printf("%d\n", sizeof(a[0][0]));//4
	printf("%d\n", sizeof(a[0]));//16
	printf("%d\n", sizeof(a[0] + 1));//4/8
	printf("%d\n", sizeof(*(a[0] + 1)));//4
	printf("%d\n", sizeof(a + 1));//4/8
	printf("%d\n", sizeof(*(a + 1)));//16
	printf("%d\n", sizeof(&a[0] + 1));//4/8
	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	printf("%d\n", sizeof(*a));//16
	printf("%d\n", sizeof(a[3]));//16
}
  1. printf("%d\n",sizeof(a));a是二维数组的数组名,与sizeof单独放在一起,所以表示整个二维数组的大小,答案是 3 ∗ 4 ∗ 4 = 48 3*4*4=48 344=48
  2. printf("%d\n",sizeof(a[0][0]));a[0][0]代表第一个元素,类型是int,答案是4。
  3. printf("%d\n",sizeof(a[0]));a[0]代表第一行的数组名,sizeof与第一行数组名单独放在一起,代表第一行的大小,所以答案是 4 ∗ 4 = 16 4*4=16 44=16
  4. printf("%d\n",sizeof(a[0]+1));a[0]是第一行数组名,它没有和sizeof单独放在一起,所以现在代表第一行首元素的地址,加上一是第一行第二个元素的地址,是地址,所以答案是4/8。
  5. printf("%d\n",sizeof(*(a[0]+1)));a[0] -> *(a+0),a是二维数组的数组名,这里是二维数组首元素地址,也就是第一行的地址,解引用就是第一行的数组名a[0],第一行的数组名这里不是单独放在sizeof里面,所以代表第一行一维数组的首元素地址,指针加1代表第一行第二个元素的地址,再解引用,代表第一行的第二个元素,即a[0][1],类型是int,所以答案是4。
  6. printf("%d\n",sizeof(a+1));a是第一行一维数组的地址,指针+1代表,跳过一个数组的大小,二维数组中的下一行的数据是与前一行的数据相邻的,所以指针现在指向第二行,表示第二行的地址,所以答案是4/8。
  7. printf("%d\n",sizeof(*(a+1)));由第6题可以知道,a+1是第二行一维数组的地址,*(a+1)-> a[1],表示第二行一维数组的数组名,sizeof与数组名单独在一起,此时数组名代表整个第二行的一维数组,所以计算的是整个第二行一维数组的大小,答案是 4 ∗ 4 = 16 4*4=16 44=16
  8. printf("%d\n",sizeof(&a[0]+1));&a[0] ->&*(a+0))->a+0,此时的a没有单独放在sizeof中,表示第一行数组的地址,数组的地址+1,代表第二行数组的地址,是地址所以答案就是4/8。
  9. printf("%d\n",sizeof(*(&a[0]+1)));由第8题可以知道,&a[0]+1代表第二行数组的地址,再解引用,就是(a+1) -> a[1],表示第二行数组名,此时数组名单独放在sizeof里面,计算的是整个这一行数组的大小,所以答案是 4 ∗ 4 = 16 4*4=16 44=16
  10. printf("%d\n",sizeof(*a));*a -> a[0],第一行一维数组的数组名单独放在sizeof内部,计算这第一行数组的大小,所以答案是 4 ∗ 4 = 16 4*4=16 44=16
  11. printf("%d\n",sizeof(a[3]));sizeof只关心所给式子的类型,虽然这里的a[3]越界了,但是不影响,sizeof不会真的去计算或者访问我的数据,a[3]还是数组名单独放在sizeof内部,它的类型是int [4],所以答案是 4 ∗ 4 = 16 4*4=16 44=16
    运行结果:在这里插入图片描述

2. 无明显特征的笔试题

2.1 笔试题一

int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));//2,5
return 0;
}
//程序的结果是什么?
  1. *(a+1)这样来理解,a此时代表数组首元素地址,a+1,指针跳过4个字节,指向第二个元素,解引用,结果就是第二个元素,答案是 4 4 4
  2. *(ptr-1)等于什么?要做这个题,我们得先知道ptr指向哪里?它的类型是什么?&a+1的理解,&a表示整个数组的地址,它的值和a相同,但是间接级别不一样,它的类型是int (*) [5],+1跳过整个数组,指向5后面的内容,它然后强制转换变成int*的指针,-1向后跳4个字节,指向整数5,此时指针变量储存的是5的地址,解引用所以答案是5,下面有一张图帮助你理解:
    在这里插入图片描述
    运行截图:在这里插入图片描述

2.2 笔试题二

2.2.1 %x与%p

在C语言中,%x 和 %p 都是格式化输出的转换说明符,但它们有不同的用途和功能。
%x:%x 用于将无符号整数以十六进制形式输出。它将整数值转换为十六进制表示,并以小写字母表示字母部分(a-f)。例如,使用 %x 输出十进制数 255,结果将是 ff。
%p: %p 用于将指针的地址以十六进制形式输出。它接受一个指向任何类型的指针,并将其地址以十六进制形式输出。通常用于打印指针变量的值。
需要注意的是,使用 %p 输出指针时,需要将指针转换为 (void *) 类型,因为 %p 期望的是一个 void * 类型的指针。

//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
//注意:H:十六进制 D:十进制
int main()
{
	printf("%p\n", p + 0x1);//0x100000(H)+20(D) -> 0x100014
	printf("%p\n", (unsigned long)p + 0x1);//0x100001
	printf("%p\n", (unsigned int*)p + 0x1);//0x100004
	return 0;
}
  1. printf("%p\n", p + 0x1);p是一个指针,它解引用是一个结构体,所以它的间接级别是这个结构体类型的大小,+1跳过20个字节,p变量的值就会增加, 0 X 100000 ( H ) + 20 ( D ) − > 0 X 100000 ( H ) + 0 X 000014 ( H ) = 0 X 100014 0X100000(H)+20(D)->0X100000(H)+0X000014(H)=0X100014 0X100000(H)+20(D)>0X100000(H)+0X000014H=0X100014
  2. printf("%p\n", (unsigned long)p + 0x1);p被强制转换为一个无符号的整形,+1就是整数加1,它的十六进制存储值也只加1,答案就是0X100001。
  3. printf("%p\n", (unsigned int*)p + 0x1);将p强制转换为无符号整形指针的变量,间接级别改变,+1只跳过4个字节, 0 X 100000 + 0 X 100004 = 0 X 100004 0X100000+0X100004=0X100004 0X100000+0X100004=0X100004

运行截图:
在这里插入图片描述

2.3 笔试题三

int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (int*)((int)a + 1);
	printf("%x,%x", ptr1[-1], *ptr2);//4,2000000
	return 0;
}

我们通过画图和文字的形式给出过程:
在这里插入图片描述
由于是小端存储(后续会讲),ptr1解引用后拿出来十六进制表示应该是0x00000002,以十进制打印,结果就是2,ptr2解引用后拿出来以十六进制来表示是0x02000000,以十进制打印,结果就是2000000。

运行结果:
在这里插入图片描述

2.4 笔试题四

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);//1
	return 0;
}
  • 逗号表达式(Comma Expression)是一种C语言中的表达式,它由多个表达式通过逗号连接而成。逗号表达式的值是最后一个表达式的值。
  • 在C语言中,表达式(Expression)是由操作数(Operand)和运算符(Operator)组成的组合,用于执行计算和生成值。数字(如整数和浮点数)可以被视为最简单的操作数。
  • 此题主要考察了逗号表达式,注意二维数组中一维数组的赋值应该是大括号的形式,此题是(value1,value2)的形式,说明存在陷阱,因为逗号表达式的值是最后一个表达式的值,所以实际上,只给二维数组a赋了3个值,即1、3、5,其他的位置都没有赋值,p是a[0]也就是第一行一维数组的数组名,p[0] -> a[0][0],a[0][0]的值是1,所以结果就是1。

运行结果:
在这里插入图片描述

2.5 笔试题五

int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//FFFFFFFC,-4
	return 0;
}

在这里插入图片描述

  • 所以从图中可以看到&p[4][2]与&a[4][2]相差4个元素,注意:高地址的指针-低地址的指针,以%d形式打印得到的是两者之间相隔的元素个数,而单独以%d打印,然后再去相减得到是两个地址相差的字节数,由于是数组从左往右遍历,右边的是高地址,所以%d打印是-4,%p打印-4在内存中是补码的形式去打印,这里我们给出-4的原码、反码、补码、补码的16进制表示:
    在这里插入图片描述

运行截图:
在这里插入图片描述

2.6 笔试题六

int main()
{
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int* ptr1 = (int*)(&aa + 1);
	int* ptr2 = (int*)(*(aa + 1));
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5

	return 0;
}
  • 这是一道送分题,就不画图了,&aa此时表示整个数组的地址,虽然值和aa的值相同但是间接级别不同,&aa的间接级别是 int (*)[2][5],&aa+1跳过整个数组,然后强制转换为int*类型它的间接级别又发生变化,加一减一只跳过一个元素也就是4个字节,赋给ptr1,ptr1-1,此时ptr1就指向a[1][5]这个元素,解引用后结果是10,再来看ptr2,aa表示第一行的地址,间接级别是int (*)[5],加一跳过一个一维数组的大小,aa+1就表示第二行的地址,解引用表示第二行的数组名,强制转换为int*类型后,赋给ptr2,间接级别也发生改变,加一减一只跳过一个元素也就是4个字节,ptr2-1指向第一行最后一个元素的初始位置,解引用后这个元素也就是5。

运行结果:
在这里插入图片描述

2.7 笔试题七

#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);//at;
	return 0;
}

我们画图分析:
在这里插入图片描述

  • 解引用后,传给%s的就是第二个字符串首字符的地址,所以从首字符开始打印第二个字符串遇到\0就停止。
    运行截图:
    在这里插入图片描述

2.8 笔试题八

int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);//POINT
printf("%s\n", *--*++cpp+3);//ER
printf("%s\n", *cpp[-2]+3);//ST
printf("%s\n", cpp[-1][-1]+1);//EW
return 0;

我们以画图形式给出解析:


运行结果:
`在这里插入图片描述

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

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

相关文章

【C#】默认打开图片、文件下载

系列文章 【C#】编号生成器&#xff08;定义单号规则、固定字符、流水号、业务单号&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器&#xff08;开始日期、结束日期&#xff09; 本文链接&#xff1a;h…

Linux(centos7)系统关闭 virbr0

背景&#xff1a; 在使用 VMware 虚拟机安装 centos7 操作系统中&#xff0c;经常出现将 IP 地址分配到虚拟网桥接口virbr0 上&#xff0c;引起虚拟机不能正常访问网络的问题。 我是在学习 docker 网络分析这块遇到的问题&#xff0c;教程上在虚拟机上输入 ip addr 并没有出现 …

linux开发工具:repo

1&#xff1a;repo简单介绍 repo是Google开发的用于管理Android版本库的一个工具&#xff0c;它是由一系列的Python脚本组成&#xff0c;封装了一系列的Git命令&#xff0c;用来统一管理多个Git仓库。repo不是用于取代git&#xff0c;而是简化了对多个Git版本库的管理。 repo…

6 种方式读取 Springboot 的配置(原理+实战)

从配置文件中获取属性应该是SpringBoot开发中最为常用的功能之一&#xff0c;但就是这么常用的功能&#xff0c;仍然有很多开发者在这个方面踩坑。 我整理了几种获取配置属性的方式&#xff0c;目的不仅是要让大家学会如何使用&#xff0c;更重要的是弄清配置加载、读取的底层…

搭建Promethues + grafana +alertManager+blakbox 监控springboot 健康和接口情况

一。概述 架构图&#xff1a; 拓扑图&#xff1a; prometheus 是一个开源系统&#xff0c;用于构建监控和报警的工具包。 Prometheus 收集其指标并将其存储为时间序列数据&#xff0c;即指标信息与记录它的时间戳一起存储&#xff0c;以及称为标签的可选键值对。 特点&#…

003.PADS VX2.4选项设置及显示颜色设置

文章目录 一、PADS颜色设置及选项设置二、选项设置1.全局2.设计3.栅格和捕获4.显示5.布线选项页6.覆铜平面选项页7.文本和线选项页8.文本和线选项页9.过孔样式选项页 一、PADS颜色设置及选项设置 一、颜色设置 1&#xff0e;点击设置—显示颜色&#xff09;&#xff08;快捷键…

Kkfileview | Docker | 文件预览kkfile配置

文章目录 简介DockerRedis部署 简介 kkFileView为文件文档在线预览解决方案&#xff0c;该项目使用流行的spring boot搭建&#xff0c;易上手和部署&#xff0c;基本支持主流办公文档的在线预览&#xff0c;如doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频等等 …

SQLSERVER 临时表 和 表变量 有区别吗

一&#xff1a;背景 1. 讲故事 今天和大家聊一套面试中经常被问到的高频题&#xff0c;对&#xff0c;就是 临时表 和 表变量 这俩玩意&#xff0c;如果有朋友在面试中回答的不好&#xff0c;可以尝试看下这篇能不能帮你成功迈过。 二&#xff1a;到底有什么区别 1. 前置思…

十五、flex弹性元素的样式

目录&#xff1a; 1. 基本布局 2. 弹性元素的属性&#xff1a;flex-grow 3. 弹性元素的属性&#xff1a;flex-shrink 4. 弹性元素的属性&#xff1a;flex-basis 5. flex 统一设置这3个属性&#xff08;常用&#xff09; 6. order 一、基本布局 <style>*{margin: 0;paddin…

【Maven】类或者包提示找不到,报红

背景 使用IDEA&#xff0c;类或者包提示找不到&#xff0c;报红 解决方法 1. maven reload 2. 检查profiles是否对 3. 不要选中offline模式 4. 检查本地仓库位置 5. 清掉idea缓存 6. 到本地maven仓库删掉出错的包然后重新maven reload 7. update本地仓库 8. 排查是不是别人没…

智慧用电安全监控管理系统

智慧用电安全监控管理系统是一种基于物联网技术的用电安全管理系统&#xff0c;它通过远程通信技术和云计算平台&#xff0c;实现了对电气设备的实时监控、数据采集、费用计算、远程控制等功能。该系统不仅可以提高用电安全管理的效率&#xff0c;还可以为用户提供更加便捷、可…

Linux(centos 7)将 ens33 改为 eth0

背景&#xff1a; 先说明一下 eth0 与 ens33 的关系&#xff0c;目前的主流网卡为使用以太网络协定所开发出来的以太网卡&#xff08;Ethernet)&#xff0c;因此我们 Linux 就称呼这种网络接口为 ethN (N为数字)。 举个例子&#xff1a;就是说主机上面有一张以太网卡&#xff0…

C++线性表、单链表

概述 在先说链表前&#xff0c;我们先来理清几个概念。 什么是线性表、顺序表和链表&#xff1f;三者有什么关系&#xff1f; 线性表&#xff1a;元素线性排列&#xff0c;在逻辑上具有次序的存储结构。 顺序表&#xff1a;线性表的顺序存储称为线性表。它是用一组地址连续(逻…

抖音短视频seo源码开发部署-技术分享(四)

一、 抖音短视频seo源码开发流程 抖音短视频SEO源码开发流程如下&#xff1a; 1.分析需求&#xff1a;首先需要明确你的SEO目标。分析竞争对手&#xff0c;了解抖音短视频平台的规则&#xff0c;选定目标关键词和主题。 2.编写代码&#xff1a;根据需求编写代码&#xff0c;…

docker 安装向量数据库 Milvus

Miluvs 官网为 www.milvus.io/ Milvus 向量数据库能够帮助用户轻松应对海量非结构化数据&#xff08;图片 / 视频 / 语音 / 文本&#xff09;检索。单节点 Milvus 可以在秒内完成十亿级的向量搜索&#xff08;请参考&#xff1a;在线教程&#xff09;&#xff0c;分布式架构亦…

This application failed to start?

大家好&#xff0c;最近在搞一个定制的图像分割项目&#xff0c;其中需要自己构建数据集。 这里我用到了基于paddle开发高效智能的交互式分割标注软件 EISeg(Efficient Interactive Segmentation)。 它涵盖了通用、人像、遥感、医疗、视频等不同方向的高质量交互式分割模型。另…

低代码——现代数字化人才培养的创新引擎

如今&#xff0c;随着数字时代的蓬勃发展&#xff0c;催生了各行各业数字化转型的浪潮。如果说技术是衍生数字时代的基石&#xff0c;那数字化人才一定是这场浪潮中不可或缺的推动力量。 随着新兴技术的不断创新和应用&#xff0c;全行业对于复合型、创新型的优秀数字化人才需…

四种常见分布式限流算法实现!

大家好&#xff0c;我是老三&#xff0c;最近公司在搞年终大促&#xff0c;随着各种营销活动“组合拳”打出&#xff0c;进站流量时不时会有一个小波峰&#xff0c;一般情况下&#xff0c;当然是流量越多越好&#xff0c;前提是系统能杠地住。大家都知道&#xff0c;一个分布式…

css 网页色调变为黑白

在html的css中加入 filter: grayscale(1);

Java Springboot设置MySQL的ssl连接访问

一、需求背景 需要修改应用程序通过SSL连接mysql数据库。 环境配置 数据库&#xff1a;MySQL 8.0.21 &#xff08;enabled SSL&#xff09; Java版本&#xff1a;openjdk version "1.8.0_332" Springboot版本&#xff1a;v2.5.3 二、生成证书 下面是MySQL数据库服…