【C语言】指针和数组笔试题解析

目录

一、一维数组

二、字符数组

1、字符数组(题型一)

2、字符数组(题型二)

3、字符数组(题型三)

三、二维数组

四、指针笔试题

1、试题一

 2、试题二

3、试题三

4、试题四

5、试题五

6、试题六

7、试题七 

8、试题八


一、一维数组

一维数组

int main()
{
	int arr[] = { 1,2,3,4 };
	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[1]));
	printf("%d\n", sizeof(&arr));
	printf("%d\n", sizeof(*&arr));
	printf("%d\n", sizeof(&arr+1));
	printf("%d\n", sizeof(&arr[0]));
	printf("%d\n", sizeof(&arr[0]+1));
	return 0;
}

答案解析

int main()
{
int arr[] = { 1,2,3,4 };
printf("%d\n", sizeof(arr)); // 16
//arr作为数组名单独放在sizeof()内部,计算的是整个数组大小,单位为字节
printf("%d\n", sizeof(arr+0)); // 4/8
//arr不是单独放在sizeof()内部,也无&,所以arr表示数组首元素地址,即arr+0也是首元素地址,地址大小在32平台下为4个字节,64平台下为8个字节
printf("%d\n", sizeof(*arr)); // 4
//arr是首元素地址,*arr就是数组首元素的大小
printf("%d\n", sizeof(arr+1)); // 4/8
//arr是首元素的地址,arr+1是数组第二个元素的地址,计算指针的大小,在32平台下为4个字节,64平台下为8个字节
printf("%d\n", sizeof(arr[1])); // 4
//arr[1]就是数组第二个元素的大小
printf("%d\n", sizeof(&arr)); // 4/8
//&arr表示取出数组的地址,也是地址,地址在32平台下为4个字节,64平台下为8个字节
printf("%d\n", sizeof(*&arr)); // 16
//&arr表示取出数组的地址,*&arr是访问整个数组的大小
printf("%d\n", sizeof(&arr+1)); // 4/8
//&arr取出数组的地址,&arr+1表示跳过整个数组,也是地址,大小为4/8
printf("%d\n", sizeof(&arr[0])); // 4/8
//arr[0]表示第一个元素地址,&arr[0]是第一个元素的地址,也是地址,大小为4/8
printf("%d\n", sizeof(&arr[0]+1)); // 4/8
//&arr[0]是第一个元素的地址,&arr[0]+1就是第二个元素的地址,大小为4/8
return 0;
}

关于sizeof()的两个例外:

1、sizeof(数组名) :  数组名表示整个数组,计算的是整个数组的大小,单位是字节。

2、&数组名: 数组名也表示整个数组,取出的是整个数组的地址。

除了这个2个例外,见到的所有的数组名都表示首元素的地址。

二、字符数组

1、字符数组(题型一)

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

    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','b' };
printf("%d\n", sizeof(arr)); // 4
//arr是数组名,单独放在sizeof()内部,计算的是整个数组大小
printf("%d\n", sizeof(arr+0)); // 4/8
//arr不是单独放在sizeof()内部,也无&,计算首元素地址大小
printf("%d\n", sizeof(*arr)); // 1
//arr是首元素地址,*arr就是首元素
printf("%d\n", sizeof(arr[1])); // 1
//arr[1]表示数组第二个元素,计算数组第二个元素的大小
printf("%d\n", sizeof(&arr)); // 4/8
//&arr表示取出数组地址,也是地址,大小为4/8
printf("%d\n", sizeof(&arr+1)); // 4/8
//&arr取出数组地址,&arr+1跳过整个数组,也是地址,大小为4/8
printf("%d\n", sizeof(&arr[0]+1)); // 4/8
//&arr[0]是字符'a'的地址,加1是字符'b'的地址,大小为4/8

printf("%d\n", strlen(arr)); // 随机值
//arr是数组名,但是没有放在sizeof内部,也无&,arr就是首元素的地址
//strlen()得到arr后,从数组首元素的位置开始计算字符串的长度,直到找到\0
//但是arr内存的后边是否有\0,在什么位置是不确定的,所以\0之前出现了多少个字符是随机的。
printf("%d\n", strlen(arr + 0)); // 随机值
//arr是首元素地址,arr+0还是首元素地址
printf("%d\n", strlen(*arr)); // err
//arr是首元素地址,*arr是首元素,strlen就会把‘a’的ASCII码值 97 当成了地址,就会非法访问内存
printf("%d\n", strlen(arr[1])); // err
//arr[1]表示数组第二个元素,即字符'b'
printf("%d\n", strlen(&arr)); // 随机值
//&arr取出数组地址,数组地址也是指向起始位置
printf("%d\n", strlen(&arr + 1)); // 随机值
//&arr取出数组地址,&arr+1跳过整个数组
//arr内存的后边是否有\0,在什么位置是不确定的,所以\0之前出现了多少个字符是随机的。
printf("%d\n", strlen(&arr[0] + 1)); // 随机值
//&arr[0]是字符'a'的地址,加1是字符'b'的地址
//arr内存的后边是否有\0,在什么位置是不确定的,所以\0之前出现了多少个字符是随机的。
return 0;
}

2、字符数组(题型二)

int main()
{
	char arr[] = "abcd";
	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));

	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[] = "abcd";
printf("%d\n", sizeof(arr)); // 5
//字符串末尾有一个结束标志'\0',所以arr数组有5个元素
printf("%d\n", sizeof(arr+0)); // 4/8
//arr不是单独放在sizeof()中,是首元素地址,arr+0也是首元素地址
printf("%d\n", sizeof(*arr)); // 1
//arr是首元素地址,*arr是第一个字符'a',sizeof(*arr)是字符'a'的大小,单位为字节
printf("%d\n", sizeof(arr[1])); // 1
//arr[1]是数组第二个字符'b'
printf("%d\n", sizeof(&arr)); // 4/8
//&arr取出数组地址
printf("%d\n", sizeof(&arr+1)); // 4/8
//&arr取出数组地址,&arr+1也是地址
printf("%d\n", sizeof(&arr[0]+1)); // 4/8
//&arr[0]取出首元素地址,&arr[0]+1也是地址

printf("%d\n", strlen(arr)); // 4
//strlen()遇到字符串末尾的结束标志'\0'停止,'\0'前有4个元素
printf("%d\n", strlen(arr+0)); // 4
//arr+0表示首元素地址
printf("%d\n", strlen(*arr)); // err
//arr表示首元素地址,*arr是首元素,strlen就会把'a'的ASCII码值97当成了地址
printf("%d\n", strlen(arr[1])); // err
//arr[1]是数组第二个元素
printf("%d\n", strlen(&arr)); // 6
//&arr取出数组地址,指向起始位置
printf("%d\n", strlen(&arr + 1)); // 随机值
//&arr取出数组地址,加1则跳过整个数组
printf("%d\n", strlen(&arr[0] + 1)); // 5
//&arr[0]取出首元素地址,加1是第二个元素地址
return 0;
}

3、字符数组(题型三)

int main()
{
	char *arr = "abcd";
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr+1));
	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[0]+1));

	printf("%d\n", strlen(arr));
	printf("%d\n", strlen(arr + 1));
	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[0] + 1));
	return 0;
}

答案解析

int main()
{
char* p = "abcd";
printf("%d\n", sizeof(p)); // 4/8
//p是指针变量,存放的是数组首元素地址,大小为4/8
printf("%d\n", sizeof(p+1)); // 4/8
//p存放的是地址,p+1也是地址,大小为4/8
printf("%d\n", sizeof(*p)); // 1
//p存放的是首元素地址,*p是首元素,大小为1,单位为字节
printf("%d\n", sizeof(p[0])); // 1
//p[0]是首元素,p[0] == *(p+0) == *p
printf("%d\n", sizeof(&p)); // 4/8
//p存放的是地址,&p取出p的地址,也是地址
printf("%d\n", sizeof(&p+1)); // 4/8
//&p+1是地址
printf("%d\n", sizeof(&p[0]+1)); // 4/8
//&p[0]+1是地址

printf("%d\n", strlen(p)); // 4
//p是指针变量,指向首元素地址
printf("%d\n", strlen(p + 1)); // 3
//p指向首元素地址,p+1指向第二个元素地址
printf("%d\n", strlen(*p)); // err
//*p是首元素
printf("%d\n", strlen(p[0])); // err
//p[0]是首元素
printf("%d\n", strlen(&p)); // 随机值
//&p取出的是p的地址,无法确定p的元素
printf("%d\n", strlen(&p + 1)); // 随机值
//&p取出的是p的地址,加1跳过p
printf("%d\n", strlen(&p[0] + 1));  // 5
//&p[0]是首元素地址,加1是第二个元素地址
return 0;
}

1、sizeof

sizeof 是计算对象或者类型创建的对象所占内存空间的大小,单位是字节。

sizeof 是操作符,不是函数。

2、strlen

strlen 求字符串长度的,计算的是字符串中\0之前出现的字符的个数。

统计到\0为止,如果没有看到\0,会继续往后找。

strlen 是库函数。

三、二维数组

二维数组

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

答案解析

int main()
{
int arr[3][4] = { 0 };
printf("%d\n", sizeof(arr)); // 48
//arr是二维数组的数组名,数组名是单独放在sizeof内部,计算的是数组的总大小,单位是字节
printf("%d\n", sizeof(arr[0][0])); // 4
//a[0][0]是一个整型元素,大小是4个字节
printf("%d\n", sizeof(arr[0])); // 16
//arr[0]是第一行的数组名,第一行数组名单独放在sizeof内部,计算的是第一行数组的大小
printf("%d\n", sizeof(arr[0] + 1)); // 4/8
//arr[0]是第一行的数组名,但不是单独放在sizeof内部,所以是第一行首元素的地址
//加1是第一行第二个元素地址,就arr[0][1]的地址,大小为4/8
printf("%d\n", sizeof(*(arr[0] + 1))); // 4
//arr[0]是第一行首元素地址,加1是第一行第二个元素的地址,*(arr[0] + 1)是第一行第二个元素
printf("%d\n", sizeof(arr + 1)); // 4/8
//arr是二维数组的数组名,不是单独放在sizeof内部,也没有&,所以arr是首元素地址
//二维数组,我们把它想象成一维数组,它的首元素就是二维数组的第一行
//arr就是第一个的地址,加1是第二行地址,也是地址
printf("%d\n", sizeof(*(arr + 1))); // 16
//arr+1是第二行地址,sizeof(*(arr + 1))计算的就是第二行的大小
//*(arr + 1) == a[1]
printf("%d\n", sizeof(&arr[0] + 1)); // 4/8
//&a[0]是第一行的地址,&a[0]+1就是第二行的地址
printf("%d\n", sizeof(*(&arr[0] + 1))); // 16
&a[0]+1就是第二行的地址,sizeof(*(&arr[0] + 1))计算的是第二行的大小
printf("%d\n", sizeof(*arr)); // 16
//arr是首元素地址,是第一行的地址,sizeof(*arr)计算的是第一行的大小
printf("%d\n", sizeof(arr[3])); // 16
//arr[3]是二维数组的第四行
//虽然没有第四行,但是类型能够确定,大小就是确定的。大小就是一行的大小,单位是字节
return 0;
}

四、指针笔试题

1、试题一

#include <stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	int* ptr = (int*)(&arr + 1);
	printf("%d %d\n", *(arr + 1), *(ptr - 1));
	return 0;
}

 运行结果

43fc167ce58b4abf82541f56a6703465.png

 解析

arr是数组首元素的地址,+1得到第二位元素的地址,对地址进行解引用得到第二位元素 2

&arr取出数组的地址,加1跳过整个数组

对跳过整个数组的地址-1,得到数组最后一位元素的地址,解引用得到 5

 2、试题二

#include <stdio.h>
//已知,结构体Test类型的变量大小是20个字节
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
int main()
{
    p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

运行结果 

 5eb0a55693c24d80b085019a4ecba4fc.png

 解析

1、已知结构体的变量大小是20个字节,p是结构体指针类型,所以+1就是跳过20个字节,十进制的20等价于十六进制的14,所以 0x100000 + 0x00000014 = 0x00100014

2、这里将其强制类型转换成unsigned long,整数+1就是+1,所以 0x100000 + 0x00000001 = 0x00100001

3、这里将其强制类型转换为unsigned int*,+1就向后跳过4个字节,所以 0x100000 + 0x00000004 = 0x00100004;

3、试题三

#include <stdio.h>
int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (int*)((int)a + 1);
	printf("%x,%x\n", ptr1[-1], *ptr2);
	return 0;
}

 运行结果

54bc0624c3ce4bb6afb05e6b5f73f0a6.png

解析 

1、&a是数组地址,+1跳过整个数组,ptr1[-1] == *(ptr-1),输出结果为4

2、将a强制类型转换为int 类型,再+1,在强制类型转化为指针实际上是向右移动一个字节,

对ptr2进行解引用,以16进制输出结果为2000000。

4、试题四

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d\n", p[0]);
	return 0;
}

 运行结果

092efe0eebc2404990e757839fe35696.png

解析

数组的初始化内容有逗号表达式,实际上初始化内容为1,3,5

p[0] == *(p+0)  == *(p[0]+0)

5、试题五

#include <stdio.h>
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;
}

 运行结果

ff32a9becefc4d4cb90298a506b22f53.png

 解析

1、由于二维数组和一维数组一样,在空间中都是连续存储的,把a赋值给p,&p[4][2]取出的是二维数组第19个元素的地址,&a[4][2]取出的是二维数组第23个元素的地址,由小地址-大地址得 -4。

2、因为-4的补码为11111111 11111111 11111111 11111100,内存中以补码的形式存储,以%p的形式打印,输出结果为FFFFFFFC。

6、试题六

#include <stdio.h>
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;
}

 运行结果

d99a491b560a474eacc122e517a040fe.png

 解析

1、&aa取出数组地址,加1则跳过整个数组,*(ptr1-1)的输出结果为10

2、aa是数组名,是首元素地址,二维数组中首元素地址就是第一行地址,加1则跳过第一行,得到第二行地址,对其进行解引用,就得到第二行,相当于第二行数组名,即为第二行首元素地址,*(ptr-1)的输出结果为5。

7、试题七 

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

运行结果

0bbc596534004d5fbf0e22899e13cddd.png

 解析

a[]是一个指针数组,其中a[0]存放的是'w'的地址,a[1]存放的是'a'的地址,a[2]存放的是'a'的地址

pa = a 中,a为首元素地址,即为a[0]的地址,pa是一个二级指针,指向a[0],pa++指向a[1]

*pa输出结果为at

8、试题八

#include <stdio.h>
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;
}

 运行结果

37257a76c4de4df7baf0949d9044fb34.png

 解析

1、由于++cpp指向cp[1],解引用找到cp[1]中的元素c+2,再解引用找到字符’P’的地址,以%s的形式打印得到’POINT’

2、++cpp指向cp[2],解引用找到cp[2]中的元素c+1,然后前置--使得c+1变为c,在解引用找到字符'E'的地址,加3找到字符'E'的地址,以%s的形式打印得到‘ER’。

3、由于*cpp[-2] + 3 == *(*(cpp-2)+3,其中cpp-2解引用指向cp[0]中的元素c+3,再解引用找到字符'F'的地址,加3找到字符'S'的地址,以%s的形式打印得到’ST‘。

4、cpp[-1][-1]+1 == *(*(cpp-1)-1)+1,其中cpp-1解引用指向cp[1]中的元素c+2,在减1,得到c+1,在解引用,得到字符'N'的地址,以%s的形式打印得到'EW'。

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柒个葫芦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值