【C语言】指针练习篇(上),深入理解指针---指针和数组练习题和sizeof,strlen的对比【图文讲解,详细解答】

欢迎来CILMY23的博客喔,本期系列为【C语言】指针练习篇(上),深入理解指针---指针数组练习题和sizeof,strlen的对比【图文讲解,详细解答】,图文讲解指针和数组练习题,带大家更深刻理解指针的应用,感谢观看,支持的可以给个赞哇。
前言

作为指针系列的番外练习篇,本篇主要以数组练习题为主,本期博客将用sizeof和strlen的对比开头,并且以做题的视角带入,进行深刻理解指针练习题中不同用法区别。

目录

一、sizeof和strlen的对比

1.1sizeof操作符

1.2strlen

1.3表格总结

1.4sizeof题目

二、指针,数组笔试题

2.1一维数组

[2.2 字符数组](#2.2 字符数组)


一、sizeof和strlen的对比

1.1sizeof操作符

sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据,并且在计算变量的时候,括号可以省略。额外说明size_t就是为sizeof设计的。

就比如以下代码:

cpp 复制代码
#include<stdio.h>

int main()
{
	int a = 23;

	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof a);
	printf("%d\n", sizeof(int));

	return 0;
}

我们可以看到,结果都是4。

1.2strlen

strlen是C语言库函数,函数功能原型如下:

size_t strlen ( const char * str );

strlen字符串长度统计的是从形参str中这个地址开始向后,\0之前字符串中字符的个数。如果没有找到\0,那么strlen函数会在内存中⼀直向后找\0字符,直到找到\0为止,所以可能存在越界查找。

就比如下面这段代码:

cpp 复制代码
#include<stdio.h>
#include<string.h>

int main()
{
	char arr[] = "SILMY23";
	char arr1[] = { 'S','I','L','M','Y' };

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

	return 0;
}

由于前面有\0,后面没有\0,那么第二个原本的长度应该是五,但存在越界查找,所以长度必然不为5.

结果如下:

1.3表格总结

|----|--------------------|--------------------------------------|
| | sizeof | strlen |
| 性质 | 操作符 | 是库函数,使用需要包括头文件#include<string.h> |
| 功能 | 计算操作数所占内存的大小,单位是字节 | 求字符串长度 |
| 特点 | 不关注内存中存放什么数据 | 关注内存中是否有\0,如果没有\0 ,就会持续往后找,可能会越界查找 |

1.4sizeof题目

请思考以下代码,L和S的值:

cpp 复制代码
#include<stdio.h>

int main()
{
	short S = 4;
	int I = 2;
	int L = sizeof(S = I + 23);
	printf("%d \n", L);
	printf("%d \n", S);
	return 0;
}

结果如下:

在上述代码中,S=I+23其实是没有参与计算的,因为在sizeof中的操作数如果是一个表达式,表达式就不参与计算 ,所以最后的S还是4。其次,sizeof计算其实是按照操作类型来推理的,比如上述中S是short两个字节的短整型,所以L是两个字节。

二、指针,数组笔试题

2.1一维数组

如果你不理解数组名可以跳转至http://t.csdnimg.cn/6zjW4,观看第二点

cpp 复制代码
    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));

这是在32位环境和64位环境下的结果

2.1解析:

printf("%d\n", sizeof(a));

a单独放在sizeof后面是整个数组,计算的是整个数组的大小,所以大小为16

printf("%d\n", sizeof(a + 0));

a+0,a没有单独放在sizeof里面,也没有&,所以是数组首元素地址,既然是数组首元素地址那么,a+0 == a,是地址,大小就为4/8字节。

printf("%d\n", sizeof(*a));

a没有单独存放在sizeof后面,所以是数组首元素地址,解引用,*a == a[0],所以计算的是数组第一个元素的大小,即为4个字节

printf("%d\n", sizeof(a + 1));

a + 1同理上面的 a+0 即为4/8字节

printf("%d\n", sizeof(a[1]));

a[1] == *(a + 1),计算的是数组第二个元素的大小,即为4个字节

printf("%d\n", sizeof(&a));

&a, 因为a前面有&操作符,所以这里取出的是整个数组的地址,既然为地址,那么就为4/8字节

printf("%d\n", sizeof(*&a));

把整个数组的地址解引用后,sizeof计算的是整个数组的大小,即为16个字节

printf("%d\n", sizeof(&a + 1));

&a + 1,计算的是跳过数组大小的地址,是地址就为4/8字节

printf("%d\n", sizeof(&a[0]));

&a[0],表示取出的是数组首元素的地址,大小为4/8字节

printf("%d\n", sizeof(&a[0] + 1));

&a[0] + 1表示的是数组第二个元素的地址,大小为4/8字节

2.2 字符数组

2.2.1

cpp 复制代码
	char arr[] = {'S','I','L','M','Y'};

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

结果如下:

2.2.1解析:

printf("%d\n", sizeof(arr));

arr单独放在sizeof后面,计算整个数组大小,所以为5个字节

printf("%d\n", sizeof(arr + 0));

arr+0表示是数组首元素地址,是地址就为4/8字节

printf("%d\n", sizeof(*arr));

*arr将数组首元素地址解引用,sizeof计算首元素的大小,大小为1字节

printf("%d\n", sizeof(arr[1]));

arr[1]表示数组第二个元素,sizeof计算第二个元素大小,大小为1字节

printf("%d\n", sizeof(&arr));

&arr表示取出整个数组的地址,是地址,大小为4/8字节

printf("%d\n", sizeof(&arr + 1));

&arr + 1 表示跳过数组大小,指向数组末尾后面的地址,大小为4/8字节

printf("%d\n", sizeof(&arr[0] + 1));

&arr[0] + 1 表示数组第二个元素的地址,是地址,大小为4/8字节

2.2.2

cpp 复制代码
	char arr[] = { 'S','I','L','M','Y' };

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

32位结果如下:

64位结果如下:

2.2.2解析

printf("%d\n", strlen(arr));

arr表示数组首元素地址,因为数组中没有明确给出字符\0,所以会导致strlen在内存中不断寻找,直到找到第一个\0 为止,因此是随机值

printf("%d\n", strlen(arr + 0));

arr+0也表示数组首元素地址,因为没有\0,所以和第一种情况一样,也是随机值

printf("%d\n", strlen(*arr));

*arr,arr是数组首元素地址,解引用后得到是S,S对应的ASCII码值是83,strlen把八十三当成一个地址,造成非法访问,所以错误

printf("%d\n", strlen(arr[1]));

arr[1]表示数组第二个元素,I对应的ASCII码值是73,同样的也是非法访问。

printf("%d\n", strlen(&arr));

&arr表示取出整个数组的地址,从arr的首元素开始算起,直到找到第一个\0为止,所以是随机值

printf("%d\n", strlen(&arr + 1));

&arr +1 表示跳过数组大小的地址,也就是从Y后面开始算起,同样因为没有\0,所以会是一个随机值,但它和&arr会相差五个元素,一个数组大小。

printf("%d\n", strlen(&arr[0] + 1));

&arr[0] + 1 表示从数组第二个元素开始,因为没有\0,所以也会是一个随机值,但它和&arr相比,会差一个元素

2.2.3

cpp 复制代码
	char arr[] = "SILMY23";

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

结果如下:

2.2.3解析:

printf("%d\n", sizeof(arr));

arr单独放在sizeof后面,所以计算的是整个数组的大小,因为字符串后面自带一个'\0'字符,所以sizeof在计算大小的时候会把'\0'算进去,也就是八个字节。

printf("%d\n", sizeof(arr + 0));

arr + 0 ,表示数组首元素的地址,那是地址大小就是4/8

printf("%d\n", sizeof(*arr));

*arr是数组首元素地址解引用,得到的是S,sizeof单独计算一个S的大小,字节为1

printf("%d\n", sizeof(arr[1]));

arr[1],表示数组的第二个元素,计算大小是为1字节

printf("%d\n", sizeof(&arr));

&arr,表示取出整个数组的地址,是地址,大小为4/8字节

printf("%d\n", sizeof(&arr + 1));

&arr + 1 ,表示跳过整个数组,指向数组末尾的地址,是地址,大小为4/8字节

printf("%d\n", sizeof(&arr[0] + 1));

&arr[0] + 1 表示数组第二个元素的地址,是地址大小就为4/8字节。

2.2.4

cpp 复制代码
	char arr[] = "SILMY23";

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

32位结果如下:

64位结果如下:

2.2.4解析

printf("%d\n", strlen(arr));

arr表示数组首元素地址,strlen计算的是到\0之前的字符,所以是7个字节

printf("%d\n", strlen(arr + 0));

arr+0表示数组首元素地址,7个字节

printf("%d\n", strlen(*arr));

arr表示数组首元素地址,但是解引用后访问的是S的ASCII码,地址83,非法访问

printf("%d\n", strlen(arr[1]));

arr[1] 表示数组第二个元素,解引用后访问的是I的ASCII码,地址73,非法访问

printf("%d\n", strlen(&arr));

&arr,表示整个数组的地址,也是指向数组起始位置的,那因为有\0,所以计算的是到\0之前的地址,所以是7个字节

printf("%d\n", strlen(&arr + 1));

&arr + 1 ,表示跳过整个数组,指向数组末尾的地址,由于找不到\0,所以会在内存中寻找\0,因此是随机值

printf("%d\n", strlen(&arr[0] + 1));

&arr[0] + 1,表示数组第二个元素的地址,计算后的大小为6.

2.2.5

cpp 复制代码
char* p = "SILMY23";

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

32位结果如下图:

64位结果如下图:

2.2.5解析:

printf("%d\n", sizeof(p));

p是个char* 的指针变量,指向的对象数据类型是char,是指针变量,大小就为4/8字节

printf("%d\n", sizeof(p + 1));

p + 1,表示字符I的地址,本身还是指针变量,大小就为4/8字节

printf("%d\n", sizeof(*p));

*p,p本身存储的是S的地址,解引用后获得S,那么S对应的类型是char,所以大小为1字节

printf("%d\n", sizeof(p[0]));

p[0],表示*(p+0)== *p,所以大小为1字节

printf("%d\n", sizeof(&p));

&p,表示的是指针变量p的地址,所以大小为4/8字节

printf("%d\n", sizeof(&p + 1));

&p +1 ,表示跳过一个指针变量的大小的地址,是地址,大小为4/8

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

&p[0] + 1,表示指向I的地址,是地址,大小为4/8

2.2.6

cpp 复制代码
	char* p = "SILMY23";

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

32位结果如下:

64位结果如下:

2.2.6解析:

printf("%d\n", strlen(p));

p是char* 的指针变量,指向的是S这个起始位置,末尾有\0,计算大小为7

printf("%d\n", strlen(p + 1));

p + 1 指向的是I这个起始位置,末尾有\0,计算大小为6

printf("%d\n", strlen(*p));

*p,p表示字符串S地址,但是解引用后访问的是S的ASCII码,地址83,非法访问

printf("%d\n", strlen(p[0]));

p[0] == *(p+0) == *p, 同样是非法访问

printf("%d\n", strlen(&p));

&p,表示的是p的地址,那从p的起始地址开始往后找\0,因为不确定\0在哪,所以是随机值

printf("%d\n", strlen(&p + 1));

&p +1 ,表示跳过一个指针变量的大小的地址,从p的末尾开始查找,因为不确定\0在哪,所以是随机值

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

&p[0] + 1,表示指向I的地址,计算的大小为6
感谢各位同伴的支持,本期指针练习篇(上)就讲解到这啦,还有指针练习篇(下),如果你觉得写的不错的话,可以给个赞,若有不足,欢迎各位在评论区讨论。

相关推荐
可峰科技2 分钟前
斗破QT编程入门系列之二:认识Qt:编写一个HelloWorld程序(四星斗师)
开发语言·qt
oliveira-time3 分钟前
golang学习2
算法
全栈开发圈7 分钟前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫
面试鸭11 分钟前
离谱!买个人信息买到网安公司头上???
java·开发语言·职场和发展
小白学大数据12 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
Python大数据分析@15 分钟前
python操作CSV和excel,如何来做?
开发语言·python·excel
上海_彭彭40 分钟前
【提效工具开发】Python功能模块执行和 SQL 执行 需求整理
开发语言·python·sql·测试工具·element
334554321 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
沈询-阿里1 小时前
java-智能识别车牌号_基于spring ai和开源国产大模型_qwen vl
java·开发语言
南宫生1 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法