【c语言】指针经典笔试题

前言

我为大家带来指针和数组的笔试题深度解析,下面我会给大家带来一维数组,字符数组,二维数组相关笔试题。

知识点

关于数组名
数组名是数组首元素的地址
但是有2个例外:

  1. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
  2. &数组名 - 数组名也表示整个数组,取出的是整个数组的地址
    除了这个2个例外,你见到的所有的数组名都表示首元素的地址

一维数组

代码片段
下面我可以看一下代码,自己先思考每个代码打印的结果

//一维数组
#include<stdio.h>
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;
}

代码解析

#include<stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	//16,a作为数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节

	printf("%d\n", sizeof(a + 0));
	//a并非单独放在sizeof内部,也没有&,所以数组名a就是数组首元素的地址
	//a+0还是数组首元素的地址,是地址大小就是 4/8 个字节,这里是x86的环境所以地址大小为4
	//如果是x64的环境,地址大小就是8

	printf("%d\n", sizeof(*a));
	//a是首元素的地址,*a就是首元素,sizeof(*a)就算的就是首元素的大小,元素类型为int型 -> 4
	//a  - int*
	//*a - int
	printf("%d\n", sizeof(a + 1));//a是首元素的地址,a+1是第二个元素的地址,sizeof(a+1)计算的是指针的大小 - 4
	//a - int*
	//a+1, 跳过一个int
	printf("%d\n", sizeof(a[1]));//a[1]就是数组的第二个元素,sizeof(a[1])的大小 - 4个字节

	printf("%d\n", sizeof(&a));//&a取出的数组的地址,数组的地址,也是地址呀,sizeof(&a)就是 4 个字节
	//a的类型为int*
	//&a的类型为:int(*)[4]

	printf("%d\n", sizeof(*&a));//&a是数组的地址,是数组指针类型,*&a是都数组指针解引用,访问一个数组的大小
	//16字节
	//sizeof(*&a) ==> sizeof(a)  =16
	
	printf("%d\n", sizeof(&a + 1));//&a数组的地址,&a+1跳过整个数组,&a+1还是地址,是 4 个字节
	printf("%d\n", sizeof(&a[0]));//a[0]是数组的第一个元素,&a[0]是第一个元素的地址,是 4 个字节
	printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一个元素的地址,&a[0]+1就是第二个元素的地址,是 4个字节

	//&a[0] - 类型int*
	//&a[0]+1 -> &a[1]

	return 0;
}

字符数组

代码片段 1

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

代码解析

//字符数组
#include<stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };//这个数组只有六个元素,没有\0
	printf("%d\n", sizeof(arr));
	//arr是数组名,并且是单独放在sizeof内部,计算的是数组总大小,单位字节,6个字节
 
	printf("%d\n", sizeof(arr + 0));
	//arr是数组名,没有单独放在sizeof的内部,arr表示首元素的地址,arr+0还是首元素地址
	//所以sizeof计算的是地址的大小,假设首元素的地址为0x0012ff44,地址里存放的是4个字节(x86)或者8个字节(x64)
	//所以sizeof计算的结果为4/8个字节

	printf("%d\n", sizeof(*arr));
	//arr是数组名,arr是首元素地址值,*arr就是首元素,sizeof计算的是首元素的大小,1个字节

	printf("%d\n", sizeof(arr[1]));
	//arr[1]是数组第二个元素,sizeof计算是第二个元素的大小,1个字节

	printf("%d\n", sizeof(&arr));
	//&arr取出是数组的地址,从值的属性还是指向首元素的地址,sizeof计算的是数组地址的大小,大小为4/8

	printf("%d\n", sizeof(&arr + 1));
	//&arr 的类型为char(*)[6],&arr+1是跳过整个数组,指向'f'的后面,&arr+1本质还是一个地址
	//是地址就是4/8个字节

	printf("%d\n", sizeof(&arr[0] + 1));
	//&arr[0]是'a'的地址,&arr[0]+1是'b'的地址,是地址就是4/8个字节
	return 0;
}

总结

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


代码片段2

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

代码解析

//strlen是计算字符串的长度,是一个库函数 
// strlen 计算的是字符串\0之前出现的字符的个数
//统计到\0为止,如果没有看到\0,会继续往后找

#include<stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));//随机值
	//arr是数组名,arr没有单独放在sizeof的内部,所以arr表示首元素的地址 
	//strlen的到arr后,从arr数组首元素的地方开始计算字符长的长度,直到找到\0
	//但是arr数组中没有\0,arr内存的后边是否有\0,在什么位置是不确定的
	//所以\0之前出现了多少个字符是随机的。

	printf("%d\n", strlen(arr + 0));//随机值
	//arr是数组首元素的地址,arr+0也是首元素的地址

	printf("%d\n", strlen(*arr));//报错
	//arr是首元素地址,*arr是首元素-'a'--97
	//strlen就把'a'的ASCII码值97当做了地址,会非法访问内存

	printf("%d\n", strlen(arr[1]));//报错
	//arr[1]-字符'b',ASCII码值为98,非法访问

	printf("%d\n", strlen(&arr));//随机值
	//&arr是数组的地址,数组的地址也是指向数组起始地址。

	printf("%d\n", strlen(&arr + 1));//随机值
	//&arr+1是跳过字符数组,地址来到'f'的位置,和第一个案例一样

	printf("%d\n", strlen(&arr[0] + 1));//随机值
	//&arr[0]取出第一个元素的地址,&arr[0] + 1第二个元素的地址,我们也不知\0的位置
	return 0;
}

代码片段3

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

代码解析

#include<stdio.h>
int main()
{
	char arr[] = "abcdef";//这里空间中存放有a b c d e f \0
	//字符串中有\0
	printf("%d\n", sizeof(arr));//7
	//arr是数组名,单独在sizeof中,计算的是整个数组的大小

	printf("%d\n", sizeof(arr + 0));//4/8
	//arr是数组名,没有单独放在sizeof中,arr数组名表示首元素的地址
	//arr+0还是首元素的地址,计算的是地址,所以大小为4/8

	printf("%d\n", sizeof(*arr));//1
	//arr是数组名,没有单独放在sizeof中,所以arr是首元素的地址
	//*arr表示第一个元素'a',计算一个数组的大小。

	printf("%d\n", sizeof(arr[1]));//1
	//arr[1]数组第二个元素的大小,计算的是元素的大小,所以为一个字节

	printf("%d\n", sizeof(&arr));//4/8
	//&arr取出的是数组的地址,从值的属性来说它指向的是数组第一个元素的大小
	//所以sizeof计算的也是地址大小

	printf("%d\n", sizeof(&arr + 1));//4/8
	//&arr取出的是数组的地址,+1跳过整个数组,指向'f'后面的地址

	printf("%d\n", sizeof(&arr[0] + 1));//4/8
	//&arr[0] + 1是第二个元素的地址
	return 0;
}

代码片段4

#include<stdio.h>
int amin()
{
	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;
}

代码解析

//求字符长的长度,关注\0的长度
#include<stdio.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//6
	//arr是数组名,是首元素的地址,

	printf("%d\n", strlen(arr + 0));//6
	//首元素地址

	printf("%d\n", strlen(*arr));//err
	//*arr是首个元素,这里我们应该是地址,*arr是一个元素
	//所以这里无法运行

	printf("%d\n", strlen(arr[1]));//err
	//arr[1]是第二个元素,同理上一个

	printf("%d\n", strlen(&arr));//6
	//&arr取出数组的地址,但是从值的属性,arr是首元素的地址

	printf("%d\n", strlen(&arr + 1));//随机值
	//&arr取出数组的地址,+1跳过数组,指向'f'的后面
	//arr内存的后边是否有\0,在什么位置是不确定的
	//所以\0之前出现了多少个字符是随机的。

	printf("%d\n", strlen(&arr[0] + 1));//5
	//&arr[0] + 1是b的地址,从b开始直到\0为止
	return 0;
}

代码片段5

#include<stdio.h>
int amin()
{
	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;
}

代码解析

#include<stdio.h>
int amin()
{
	char* p = "abcdef";
	printf("%d\n", sizeof(p));//4/8
	//p中存放的是字符串的首字符地址,sizeof计算地址的大小

	printf("%d\n", sizeof(p + 1));//4/8
	//p+1也是一个地址

	printf("%d\n", sizeof(*p));//1
    //p中存放的是首字符的地址,解引用拿到了字符a
	//sizeof计算的是字符a的数据类型大小

	printf("%d\n", sizeof(p[0]));//1
	//p[0]等价于*(p+0)等价于 *p

	printf("%d\n", sizeof(&p));//4/8
	//&p是取出首字符地址的地址,sizeof计算的是地址

	printf("%d\n", sizeof(&p + 1));//4/8
	//&p是取出首字符地址的地址,+1跳过整个地址
	//实质还是一个地址

	printf("%d\n", sizeof(&p[0] + 1));//4/8
	//&p[0] + 1指向p的地址

	return 0;
}

代码片段6

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

代码解析

#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));//6
	//p存放首字符的地址

	printf("%d\n", strlen(p + 1));//5
	//p存放首字符的地址,+1指向b的位置

	printf("%d\n", strlen(*p));//err
	//*pa拿到了a,a的ASCII码值为97

	printf("%d\n", strlen(p[0]));//err
	//p[0]就是首元素a

	printf("%d\n", strlen(&p));//随机
	//&p取出首字符地址的地址,向后访问,直到遇到\0
	//但是内存空间不知道在什么位置会出现

	printf("%d\n", strlen(&p + 1));//随机值

	printf("%d\n", strlen(&p[0] + 1));//5
	return 0;
}

二维数组

代码片段

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

代码解析

#include <stdio.h>
int main()
{
	//二维数组
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//3*4*4=48
	//a是二维数组的数组名,数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节
	
	printf("%d\n", sizeof(a[0][0]));//4
	//a[0][0]是一个整型元素,大小是4个字节

	printf("%d\n", sizeof(a[0]));//16
	//把二维数组的每一行看做一维数组的时候,a[0]是第一行的数组名,
	//第一行的数组名单独放在sizeof内部
	//计算的是第一行的总大小,单位是字节 - 16

	printf("%d\n", sizeof(a[0] + 1));//4/8
	//a[0]虽然是第一行的数组名,但是并非单独放在sizeof内部
	//a[0]作为第一行的数组名并非表示整个第一行这个数组
	//a[0]就是第一行首元素的地址,a[0]--> &a[0][0] - int*
	//a[0]+1,跳过一个int,是a[0][1]的地址  4/8字节

	printf("%d\n", sizeof(*(a[0] + 1)));//4
	//a[0]+1是第一行第二个元素的地址,所以*(a[0]+1)就是a[0][1],大小是4个字节
	
	printf("%d\n", sizeof(a + 1));//4/8
	//a是二维数组的数组名,没单独放在sizeof内部,也没有&,所以a就是数组首元素的地址
	//二维数组,我们把它想象成一维数组,它的第一个元素就是二维数组的第一行
	//a就是第一行的地址,a+1 是第二行的地址,是地址,大小就是 4/8 个字节
	//a - &a[0]
	//a+1 - &a[1]
	//a+2 - &a[2]

	printf("%d\n", sizeof(*(a + 1)));//16
	//a+1是第二行的地址,*(a+1) 找到的就是第二行,sizeof(*(a + 1))计算的就是第二行的大小
	//*(a+1) --> a[1]
	//sizeof(*(a + 1)) --> sizeof(a[1])
	
	printf("%d\n", sizeof(&a[0] + 1));//4/8
	//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,sizeof(&a[0] + 1)计算的第二行地址大小
	//单位是字节 - 4/8

	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	//&a[0] + 1是第二行的地址,*(&a[0] + 1)拿到的就是第二行,大小就是16个字节
	//*(&a[0]+1) --> a[1]

	printf("%d\n", sizeof(*a));//16
	//a表示首元素的地址,就是第一行的地址 - &a[0]
	//*a - 拿到的就是第一行 - 大小就是16个字节
	//*a -> *(a+0) -> a[0]
	
	printf("%d\n", sizeof(a[3]));//16
	//a[3]是二维数组的第4行,虽然没有第四行,但是类型能够确定,大小就是确定的。
	// 大小就是一行的大小,单位是字节 - 16
	//能够分析出 a[3]的类型是:int [4]
	//任何一个表达式有2个属性
	//3+5
	//值属性:8
	//类型属性:int

	return 0;
}

笔试题1

代码
这个代码会打印出什么呢?

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

代码

#include<stdio.h>
//由于还没学习结构体,这里告知结构体的大小是20个字节
//前提在x86环境下进行
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;//p是一个结构体指针变量

//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
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;
}

代码解析

#include<stdio.h>
//由于还没学习结构体,这里告知结构体的大小是20个字节
//前提在x86环境下进行
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;//p是一个结构体指针变量

//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);//打印0x100014
	//p+0x1==p+1,p是结构体指针变量,+1跳过一个结构体
	//一个结构体Test类型的变量大小是20个字节,就是跳过20个字节
	//0x100000也就是这个+20,但是20是十进制,转换为十六机制为0x100014

	printf("%p\n", (unsigned long)p + 0x1);//0x100001
	//p是指针类型,强制转换为unsigned long
	//这里就转换成整形相加,就是相加了一个1

	printf("%p\n", (unsigned int*)p + 0x1);//0x100004
	//p转换成一个unsigned int*,不再是结构体指针变量
	//p+1跳过整形指针,跳过四个字节

	return 0;
}

在这里插入图片描述

笔试题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", ptr1[-1], *ptr2);
	return 0;
	//%x-是十六进制的格式打印
}

代码解析
在这里插入图片描述

笔试题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]);
	return 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;
}

代码解析
在这里插入图片描述
打印结果
在这里插入图片描述

笔试题6

代码

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

代码解析
在这里插入图片描述

笔试题7

代码

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

代码解析
在这里插入图片描述

  • 18
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值