零基础自学C语言|大厂指针笔试题

2023-12-14 23:08:54

在正片开始之前,我们先回顾一下strlen和sizeof的区别:

📌sizeof

在学习操作符的时候,我们学习了?sizeof?,?sizeof?计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。
sizeof?只关注占用内存空间的大小,不在乎内存中存放什么数据。
比如:

int main()
{
	int a = 0;
	printf("%zd\n", sizeof(a));
	printf("%zd\n", sizeof(int));
	printf("%zd\n", sizeof a);
	return 0;
}

总结:

  • sizeof是操作符
  • sizeof计算操作数所占内存的大小,单位是字节?
  • 不关注内存中存放什么数据

📌strlen

strlen?是C语言库函数,功能是求字符串长度。函数原型如下:
?

size_t?strlen?(const?char? * str?);

统计的是从?strlen?函数的参数?str?中这个地址开始向后,\0之前字符串中字符的个数。strlen函数会一直向后找\0字符,直到找到为止,所以可能存在越界查找。

int main()
{
	char arr1[] = { 'a','b','c' };
	char arr2[] = "abc";
	
	printf("%zd\n", sizeof(arr1));
	printf("%zd\n", sizeof(arr2));

	printf("%d\n", strlen(arr1));
	printf("%d\n", strlen(arr2));

	return 0;
}

总结:

  • strlen是库函数,使用需要包含头文件?string.h
  • srtlen是求字符串长度的,统计的是\0?之前字符的隔个数
  • 关注内存中是否有\0,如果没有\0,就会持续往后找,可能会越界

正片开始

📌数组与指针的笔试题解析

📍一维数组

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

?解析:

int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	//a是数组名sizeof(数组名)代表计算数组的长度,结果为16
	printf("%d\n", sizeof(a + 0));
	//a是数组名,没有出现sizeof(数组名)或&(数组名)的情况(特殊情况),所以代表的是首元素的地址,+0后还是首元素的地址,sizeof(地址)的结果为4或8
	printf("%d\n", sizeof(*a));
	//没有出现特殊情况,a代表首元素的地址*a就代表首元素,所以结果是4
	printf("%d\n", sizeof(a + 1));
	//没有出现特殊情况,a+1代表第二个元素的地址,所以结果是4或8
	printf("%d\n", sizeof(a[1]));
	//没有出现特殊情况,a[1]代表第二个元素,所以结果是4
	printf("%d\n", sizeof(&a));
	//出现了&(数组名)的情况,&a代表整个数组的地址,整个数组的地址也是地址,所以结果是4或8

	printf("%d\n", sizeof(*&a));
	//*&a相当于a。出现了sizeof(数组名)的情况,代表计算数组的长度,结果为16
	printf("%d\n", sizeof(&a + 1));
	//出现了&(数组名)的情况,&a+1代表整个数组后的地址,所以结果是4或8
	printf("%d\n", sizeof(&a[0]));
	//没有出现特殊情况,a[0]代表首元素,&a[0]代表首元素的地址,所以结果是4或8
	printf("%d\n", sizeof(&a[0] + 1));
	//没有出现特殊情况,&a[0]代表首元素的地址,&a[0]+1代表第二个元素的地址,所以结果是4或8

	return 0;
}

运行结果:?

📍字符数组

代码1:

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	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));
	return 0;
}

?解析:

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%zd\n", sizeof(arr));
	//出现了sizeof(数组名)的情况,代表计算数组的长度,结果为6
	printf("%zd\n", sizeof(arr + 0));
	//没有出现特殊情况,arr代表首元素的地址,所以结果是4或8
	printf("%zd\n", sizeof(*arr));
	//没有出现特殊情况,*arr代表首元素,所以结果是1
	printf("%zd\n", sizeof(arr[1]));
	//没有出现特殊情况,arr[1]代表第二个元素,所以结果是1
	printf("%zd\n", sizeof(&arr));
	//出现了&(数组名)的情况,&arr代表整个数组的地址,整个数组的地址也是地址,所以结果是4或8
	printf("%zd\n", sizeof(&arr + 1));
	//出现了&(数组名)的情况,&a+1代表整个数组后的地址,所以结果是4或8
	printf("%zd\n", sizeof(&arr[0] + 1));
	//没有出现特殊情况,&arr[0]代表首元素的地址,&arr[0]+1代表第二个元素的地址,所以结果是4或8

	return 0;
}

运行结果:

代码2:

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));
	printf("%d\n", strlen(arr + 0));
	printf("%d\n", strlen(*arr));
	printf("%d\n", strlen(arr[1]));
	printf("%d\n", strlen(&arr));
	printf("%d\n", strlen(&arr + 1));
	printf("%d\n", strlen(&arr[0] + 1));
	return 0;
}

?解析:

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));
	//arr是首元素的地址,数组中没有\0,因此结果是随机值
	printf("%d\n", strlen(arr + 0));
	//arr+0是首元素的地址,数组中没有\0,因此结果是随机值
	printf("%d\n", strlen(*arr));
	//*arr是首元素,但是strlen要求输入地址,因此结果会发生错误
	printf("%d\n", strlen(arr[1]));
	//arr[1]是第二个元素,但是strlen要求输入地址,因此结果会发生错误
	printf("%d\n", strlen(&arr));
	//出现了& (数组名)的情况,& arr代表整个数组的地址,数组中没有\0,因此结果是随机值
	printf("%d\n", strlen(&arr + 1));
	//出现了& (数组名)的情况,& arr+1代表整个数组之后的地址,不一定有没有\0,因此结果是随机值
	printf("%d\n", strlen(&arr[0] + 1));
	//&arr[0]代表首元素的地址,&arr[0] + 1代表第二个元素的地址,数组中没有\0,因此结果是随机值
	return 0;
}

运行结果(去掉两行报错代码):

?代码3:

int main()
{
	char arr[] = "abcdef";

	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));

	return 0;
}

解析:

int main()
{
	char arr[] = "abcdef";//数组中共有七个元素:a、b、c、d、e、f、\0

	printf("%d\n", sizeof(arr));
	//出现了sizeof(数组名)的情况,代表计算数组的长度,结果为7
	printf("%d\n", sizeof(arr + 0));
	//没有出现特殊情况,arr代表首元素的地址,所以结果是4或8
	printf("%d\n", sizeof(*arr));
	//没有出现特殊情况,*arr代表首元素,所以结果是1
	printf("%d\n", sizeof(arr[1]));
	//没有出现特殊情况,arr[1]代表第二个元素,所以结果是1
	printf("%d\n", sizeof(&arr));
	//出现了&(数组名)的情况,&arr代表整个数组的地址,整个数组的地址也是地址,所以结果是4或8
	printf("%d\n", sizeof(&arr + 1));
	//出现了&(数组名)的情况,&a+1代表整个数组后的地址,所以结果是4或8
	printf("%d\n", sizeof(&arr[0] + 1));
	//没有出现特殊情况,&arr[0]代表首元素的地址,&arr[0]+1代表第二个元素的地址,所以结果是4或8

	return 0;
}

运行结果:

代码4:

int main()
{
	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));
	printf("%d\n", strlen(arr + 0));
	printf("%d\n", strlen(*arr));
	printf("%d\n", strlen(arr[1]));
	printf("%d\n", strlen(&arr));
	printf("%d\n", strlen(&arr + 1));
	printf("%d\n", strlen(&arr[0] + 1));
	return 0;
}

解析:

int main()
{
	char arr[] = "abcdef";//数组中共有七个元素:a、b、c、d、e、f、\0

	printf("%d\n", strlen(arr));
	//没有出现特殊情况,arr代表首元素的地址,strlen从首元素开始计算,直到遇见\0,所以结果为6
	printf("%d\n", strlen(arr + 0));
	//没有出现特殊情况,arr+0代表首元素的地址,所以结果为6
	printf("%d\n", strlen(*arr));
	//*arr是首元素,但是strlen要求输入地址,因此结果会发生错误
	printf("%d\n", strlen(arr[1]));
	//arr[1]是第二个元素,但是strlen要求输入地址,因此结果会发生错误
	printf("%d\n", strlen(&arr));
	//出现了& (数组名)的情况,& arr代表整个数组的地址,数组中没有\0,因此结果是随机值
	printf("%d\n", strlen(&arr + 1));
	//出现了& (数组名)的情况,& arr+1代表整个数组之后的地址,不一定有没有\0,因此结果是随机值
	printf("%d\n", strlen(&arr[0] + 1));
	//&arr[0]代表首元素的地址,&arr[0] + 1代表第二个元素的地址,因此结果是5

	return 0;
}

运行结果(去掉两条错误代码):?

代码5:
?

int main()
{

	char* p = "abcdef";
	printf("%d\n", sizeof(p));
	printf("%d\n", sizeof(p + 1));
	printf("%d\n", sizeof(*p));
	printf("%d\n", sizeof(p[0]));
	printf("%d\n", sizeof(&p));
	printf("%d\n", sizeof(&p + 1));
	printf("%d\n", sizeof(&p[0] + 1));

	return 0;
}

解析:

int main()
{

	char* p = "abcdef";//p代表了a的地址
	printf("%zd\n", sizeof(p));//没有出现特殊情况,p代表a的地址,所以结果是4或8
	printf("%zd\n", sizeof(p + 1));//没有出现特殊情况,p+1代表b的地址,所以结果是4或8
	printf("%zd\n", sizeof(*p));//没有出现特殊情况,*p代表字符a,所以结果是1
	printf("%zd\n", sizeof(p[0]));//没有出现特殊情况,p[0]代表*(p+0),所以结果是1
	printf("%zd\n", sizeof(&p));//没有出现特殊情况,&p是二级指针,结果是4或8
	printf("%zd\n", sizeof(&p + 1));//没有出现特殊情况,&p+1是二级指针,结果是4或8
	printf("%zd\n", sizeof(&p[0] + 1));//没有出现特殊情况,&p[0]+1=&*(p+0)+1,结果还是指针,指向了b,所以结果是4或8

	return 0;
}

运行结果:

代码6:

int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));
	printf("%d\n", strlen(p + 1));
	printf("%d\n", strlen(*p));
	printf("%d\n", strlen(p[0]));
	printf("%d\n", strlen(&p));
	printf("%d\n", strlen(&p + 1));
	printf("%d\n", strlen(&p[0] + 1));
	return 0;
}


解析:

int main()
{

	char* p = "abcdef";//常量字符串,且后面有\0

	printf("%d\n", strlen(p));
	//p是a的地址,所以结果为6
	printf("%d\n", strlen(p + 1));
	//p+1是b的地址,所以结果是5
	printf("%d\n", strlen(*p));
	//*p是a,不是地址,结果error
	printf("%d\n", strlen(p[0]));
	//p[0]也是a,不是地址,结果error
	printf("%d\n", strlen(&p));
	//&p代表p的地址,结果为随机值
	printf("%d\n", strlen(&p + 1));
	//&p+1代表p后面的地址,结果为随机值
	printf("%d\n", strlen(&p[0] + 1));
	//&p[0]+1代表b的地址,结果是5

	return 0;
}

运行结果(去掉两行错误代码):

📍二维数组

int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a[0][0]));
	printf("%d\n", sizeof(a[0]));
	printf("%d\n", sizeof(a[0] + 1));
	printf("%d\n", sizeof(*(a[0] + 1)));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(*(a + 1)));
	printf("%d\n", sizeof(&a[0] + 1));
	printf("%d\n", sizeof(*(&a[0] + 1)));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a[3]));
	return 0;
}

解析:

int main()
{
	int a[3][4] = { {1,2,3,4},{5,6,7,8},{8,9,0,1} };

	printf("%zd\n", sizeof(a));
	//出现了sizeof(数组名),计算的是整个数组的长度,结果是48
	printf("%zd\n", sizeof(a[0][0]));
	//a[0][0]代表的是第一行第一个元素0,结果是4
	printf("%zd\n", sizeof(a[0]));
	//a[0]是第一行的一维数组名,出现了sizeof(数组名),结果是16
	printf("%zd\n", sizeof(a[0] + 1));
	//a[0] + 1代表的是第一行第二个元素的地址,结果是4或8
	printf("%zd\n", sizeof(*(a[0] + 1)));
	//*(a[0] + 1)代表的是第一行第二个元素,结果是4
	printf("%zd\n", sizeof(a + 1));
	//a + 1代表的是第二行的一维数组的地址,结果是4或8
	printf("%zd\n", sizeof(*(a + 1)));
	//*(a + 1)代表的是第一行的一维数组解引用,得到的就是第一行的一维数组,结果是16
	printf("%zd\n", sizeof(&a[0] + 1));
	//&a[0]属于&(数组名)的情况,&a[0] + 1得到的就是第二行的一维数组的地址,结果是4或8
	printf("%zd\n", sizeof(*(&a[0] + 1)));
	//&a[0] + 1得到的就是第二行的一维数组的地址,*(&a[0] + 1)得到的就是第二行的一维数组,结果是16
	printf("%zd\n", sizeof(*a));
	//a代表第一行一维数组的地址,*a就是第一行一维数组,结果是16
	printf("%zd\n", sizeof(a[3]));
	//a[3]代表的是第三行一维数组后的一个数组,其中内容为随机值,结果为16

	return 0;
}

运行结果:

📍大厂指针运算笔试题解析?

题目1:

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));
	return 0;
}

分析:

运行结果:

代码2:

注:在x86环境下

struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p = (struct Test*)0x100000;

int main()
{
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

分析:

运行结果:

代码3:

int main()
{
 int a[3][2] = { (0, 1), (2, 3), (4, 5) };
 int *p;
 p = a[0];
 printf( "%d", p[0]);
 return 0; }

分析:

运行结果:

代码4:
?

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]);
	return 0;
}

分析:

运行结果:

代码5:
?

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));
	return 0;
}

分析:

运行结果:
?

代码6:

int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

?分析:

?运行结果:

代码7:

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

?分析:

?“printf("%s\n", **++cpp)”执行后:

“printf("%s\n", *-- * ++cpp + 3)”执行后:


运行结果:

?

文章来源:https://blog.csdn.net/Dumpling527/article/details/134893312
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。