指针和数组笔试题详解-篇2

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本文继上一篇指针和数组笔试题,本文主要内容为字符串赋给指针变量和二维数组的一些经典例题,预祝读者学有所成!


提示:以下是本篇文章正文内容,下面案例可供参考

一、字符串赋给指针变量

例题1

代码如下(示例):

int main()
{
	const char*p = "abcdef";
	//把字符串首元素地址赋给p
	printf("%d\n", sizeof(p));
	//p本身是一个指针变量,它是用来存放地址的,地址大小4或8(取决于当前环境是32位还是64位)
	printf("%d\n", sizeof(p+1));
	//p是a的地址,地址加1是跳到下一个字符b的地址,地址大小4或8
	printf("%d\n", sizeof(*p));
	//p是a的地址,*p即对p解引用得到字符a,a的大小是1个字节
	printf("%d\n", sizeof(p[0]));
	//p[0]也就是*(p+0)
	printf("%d\n", sizeof(&p));
	//p是a的地址,&p也就是地址的地址,它仍然是个地址,大小4或8
	printf("%d\n", sizeof(&p+1));
	//同上知&p是一个地址,&p+1是跳过一个char*型变量的大小(本质是指针大小为4)到一个地址,仍然是地址,大小4或8
	printf("%d\n", sizeof(&p[0]+1));
	//p[0]即*(p+0)也就是*p,我们知道p是a的地址,*p就是a,所以&p[0]是&a,还是p,所以p+1仍是地址,大小4或8
	return 0;
}

ps1:把abcdef赋给指针p,并不是整个字符串赋给指针p,而是把字符串首元素地址赋给了p,这里因为是常量字符串,我们就限定了这块空间里只能是abcdef,为了防止这块空间由于指针被修改,我们用const修饰*p是最合适的

ps2: C 语言的数组在很多时候会隐式转成指针, 比如函数传参, 或者参与运算. C 语言的指针支持 [ ] 取下标操作, p[n] 本质上等价于 * (p+n)

例题2

代码如下(示例):

#include<stdio.h>
#include<string.h>
int main()
{
	char*p = "abcdef";//f后面会自动跟一个\0
	printf("%d\n", strlen(p));
	//p传了a的地址,strlen从a开始往后找\0,共6个字符
	printf("%d\n", strlen(p+1));
	//p+1是b的地址,strlen从b开始往后走\0,共5个字符
	printf("%d\n", strlen(*p));
	//注意!!!这里是一个野指针,会报错
	//p是a的地址,*p是对a地址解引用得到a,因为是字符a,ascll码本质是97,计算机会从97这个地址开始找
	printf("%d\n", strlen(p[0]));
	//p[0]即*(p+0),也就是a,和上一行代码一样是野指针
	printf("%d\n", strlen(&p));
	//p是a的地址,&p就是地址的地址,从这块地址往后找我们并不知道什么时候能找到\0,所以会是个随机值
	printf("%d\n", strlen(&p+1));
	//由上一行代码知,&p是一个地址,地址+1仍然是地址,但对于这个地址的前后有什么东西我们是未知的,这里也会出现一个随机值
	printf("%d\n", strlen(&p[0]+1));
	//p[0]即*(p+0),p是a的地址,*p即a,&a即p,p+1是b的地址,所以往后找\0是5个字符
	return 0;
}

ps:关于&p,因为它是访问了地址的地址,对该地址也是未知的,这里其实也是一个野指针,那为什么这里是打印随机值?当访问非法内存的时候, 出现的是 “未定义行为”,意味着你看到的结果是啥样, 是不可预期的,具体你的程序崩溃不崩溃, 和你的编译器, 操作系统, 运行环境都有很大关系。笔者这里的运行环境允许了&p没有崩溃,但在其他环境下就说不准了,重要的是我们要意识到,&p也是一个野指针

二、二维数组

例题

对于二维数组我们要意识到,它本质仍然是数组,除了sizeof(数组名)以及&数组名这两种情况数组名表示整个数组,其他的的时候数组名都是数组首元素的地址
我们先来看一下简单的二维数组a[3][4]在内存中的摆放
在这里插入图片描述

代码如下(示例):

#include<stdio.h>
#include<string.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));
	//这里计算二维数组的大小,数组a共有12个元素,每个元素都是int型占4字节,合计48字节
	printf("%d\n", sizeof(a[0][0]));
	//a[0][0]即0,类型为int型,占4字节
	printf("%d\n", sizeof(a[0]));
	//a[0]是数组a第一行的数组名,这里计算的就是第一行数组的大小,4个元素,每个元素占4个字节,合计16
	printf("%d\n", sizeof(a[0]+1));
	//由上知a[0]是一个数组名,但这里是a[0]+1,a[0]是没有单独放sizeof内部的
	//所以这里a[0]是第一行数组的首元素地址,+1是跳过一个数组元素,是第一行第二个元素地址,地址大小4或8
	printf("%d\n", sizeof(*(a[0]+1));
	//由上一行代码知a[0]+1是一个地址,对其解引用得到0,int型大小4字节
	printf("%d\n", sizeof(a+1));
	//a是数组名,但没有单独放sizeof内部,所以这里是作为数组首元素地址,+1就是第二行的地址,是地址就是4或8个字节
	printf("%d\n", sizeof(*(a+1));
	//由上一行代码知,a+1是第二行数组地址,对其解引用得到第二行数组,16字节
	printf("%d\n", sizeof(&a[0] + 1));
	//a[0]是第一行数组名,对其进行取地址再加1,得到第二行数组地址,大小4或8
	printf("%d\n", sizeof(*(&a[0] + 1)));
	//由上一行代码知&a[0]+1是第二行数组地址,对其解引用得到第二行数组,16字节
	printf("%d\n", sizeof(*a));
	//a表示首元素(第一行数组)的地址,对其解引用得到第一行数组,16字节
	printf("%d\n", sizeof(a[3]));
	//假设a[3]是存在的,即第四行数组的数组名,其单独放在sizeof内部,是计算第四行数组大小,16字节
	printf("%d\n", sizeof(&a + 1));
	//二维数组其实地址是一维的,二维数组是包含12个元素+1也应跳过12个元素得到一个地址,大小4或8
	return 0;
}

ps:关于a[0],我们知道a[0][0]、a[0][1]、a[0][2]、a[0][3]分别是数组a的第一行的元素,我们又知道,一维数组b[x]是用来访问数组b的第x+1个元素,那我们这里可以把a[0]看做b,也就是a[0]是(数组a第一行数组的)一个数组名

ps:关于a+1,二维数组的首元素地址并不是a[0][0]的地址,是第一行数组的地址,以这里的a[3][4]为例,我们把它想象成一个一维数组,共三个元素,第一个元素是第一行的数组

ps:关于a[3],这里只是看了一下这个数组和数组元素的类型,并没有真的去访问这个空间

注意在这里插入图片描述
有时候我们遇到的题目如上图,他不是直接给你sizeof(a)或&a,但我们知道:二维数组a[3][4]中,a[0]、a[1]、a[2]分别表示第1、2、3行数组名,所以这里用sizeof(a[x])和&a[x]也是看成整个数组,而不是数组首元素

在这里插入图片描述
同样的,除了sizeof(a[x])和&a[x],其他情况单独出现a[x]都是表示第x+1行第一个元素的地址


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

劲夫学编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值