C语言指针(5):strlen与sizeof的区别及指针笔试题练习

1、sizeof和strlen的对比

sizeof

        sizeof计算变量所占内存内存空间⼤⼩的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。简单来说,sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。

#inculde <stdio.h>
int main()
{
 int a = 10;
 printf("%d\n", sizeof(a));
 printf("%d\n", sizeof a);//从这里可以看出sizeof是操作符而不是函数,因为函数调用必须有函数调用操作符()。
 printf("%d\n", sizeof(int));
 
 return 0;
}

strlen

        strlen是C语言中的一个库函数,功能是求字符串的长度。函数原型为:

size_t     strlen ( const char * str );
        strlen 统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。如果找不到 \0 ,就会一直向后访问,直到找到为止,所以可能存在越界访问查找。
        
#include <stdio.h>
int main()
{
 char arr1[3] = {'a', 'b', 'c'};
 char arr2[] = "abc";
 printf("%d\n", strlen(arr1));
 printf("%d\n", strlen(arr2));
 
 printf("%d\n", sizeof(arr1));
 printf("%d\n", sizeof(arr1));
 return 0;
}

        如果多次输出结果,你会发现第一个值会不断变化,并且是随机的。这里就体现了strlen的性质,因为arr1中存放的只有abc三个字符,后面没有跟 \0 ,所以函数没有停止,会在c的地址继续向后访问。

sizeof 和 strlen的对比

sizeof
1. sizeof是操作符
2. sizeof计算操作数所占内存的⼤⼩,单位是字节(指针大小:32位:4  /64位:8)
3. 不关注内存中存放什么数据

 strlen

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

 数组和指针笔试题分析

        

        一维数组

int a[] = {1,2,3,4};
//arr是有四个整型元素的数组
printf("%d\n",sizeof(a));
//sizeof(a)是计算的整个数组的大小,16个字节
printf("%d\n",sizeof(a+0));
//sizeof(a+0)是计算的数组首元素的地址的大小,4/8个字节
printf("%d\n",sizeof(*a));
//sizeof(*a)是计算的数组首元素的大小,4个字节
printf("%d\n",sizeof(a+1));
//sizeof(a+1)是计算的数组第二个元素的地址的大小,4/8个字节
printf("%d\n",sizeof(a[1]));
//sizeof(a[1]) == sizeof(*(a+1))
//计算的是数组第二个元素的大小,4个字节
printf("%d\n",sizeof(&a));
//sizeof(&a)是计算的整个数组的地址的大小,4/8个字节
printf("%d\n",sizeof(*&a));
//sizeof(*&a) == sizeof(a)
//计算的是整个数组的大小,16个字节
printf("%d\n",sizeof(&a+1));
//sizeof(&a+1)计算的是a数组后相同空间的地址的大小,4/8个字节
printf("%d\n",sizeof(&a[0]));
//sizeof(&a[0])是计算的第一个元素的地址的大小,4/8个字节
printf("%d\n",sizeof(&a[0]+1));
//sizeof(&a[0]+1)是计算的第二个元素的地址的大小,4/8个字节

字符数组

代码段1:

char arr[] = {'a','b','c','d','e','f'};
//arr数组是存放了a~f 6个字符的数组
printf("%d\n", sizeof(arr));
//sizeof(arr)计算的是整个数组的大小,6个字节
printf("%d\n", sizeof(arr+0));
//sizeof(arr+0)计算的是数组首元素的地址的大小,4/8个字节
printf("%d\n", sizeof(*arr));
//sizeof(*arr)计算的是数组首元素的大小,1个字节
printf("%d\n", sizeof(arr[1]));
//sizeof(arr[1]) == sizeof(*(arr+1))
//计算的是数组第二个元素的大小,1个字节
printf("%d\n", sizeof(&arr));
//sizeof(&arr)计算的是整个数组的地址的大小,4/8个字节
printf("%d\n", sizeof(&arr+1));
//sizeof(&arr+1)计算的是数组地址后与数组大小相同的空间内的地址的大小,4/8个字节
printf("%d\n", sizeof(&arr[0]+1));
//sizeof(&arr[0]+1)计算的是数组第二个元素的地址的大小,4/8个字节

代码段2:

char arr[] = {'a','b','c','d','e','f'};
//arr数组是存放了a~f 6个字符的字符数组
printf("%d\n", strlen(arr));
//strlen(arr)计算的是从字符a开始到首个\0之前的元素个数,因为\0位置随机,所以结果为随机值x。
printf("%d\n", strlen(arr+0));
//strlen(arr+0)计算的是从字符a开始到首个\0之前的元素个数,因为\0位置随机,所以结果为随机值x。
printf("%d\n", strlen(*arr));
//strlen(*arr)表示的是a字符即ascll值97的地址位置为起始,首个\0之前的元素个数,但因为起始地址为不可访问地址,所以会报错,运行失败。
printf("%d\n", strlen(arr[1]));
//strlen(arr[1])表示的是b字符即ascll值98的地址位置为起始,首个\0之前的元素个数,但因为起始地址为不可访问地址,所以会报错,运行失败。
printf("%d\n", strlen(&arr));
//strlen(&arr):&arr表示整个数组的地址,同样表示数组首元素的地址,所以计算的是从字符a开始到首个\0之前的元素个数,因为\0位置随机,所以结果为随机值x。
printf("%d\n", strlen(&arr+1));
//strlen(&arr+1):&arr+1表示数组后与数组空间相同大小的内存处的地址,所以计算的是从字符f后一个位置开始到首个\0之前的元素个数,因为\0位置随机,所以结果为随机值x-6。
printf("%d\n", strlen(&arr[0]+1));
//strlen(&arr[0]+1):&arr[0]+1表示的是数组第二个元素的地址,所以计算的是从字符b开始到首个\0之前的元素个数,因为\0位置随机,所以结果为随机值x-1。

将两个报错代码屏蔽后:

字符串数组

代码段1:

char arr[] = "abcdef";
//arr数组是存放了字符串“abcdef\0”的字符串数组。
printf("%d\n", sizeof(arr));
//sizeof(arr)计算的是整个数组的元素大小,7个字节
printf("%d\n", sizeof(arr+0));
//sizeof(arr+0)计算的是数组首元素的地址的大小,4/8个字节
printf("%d\n", sizeof(*arr));
//sizeof(*arr)计算的是数组首元素的大小,1个字节
printf("%d\n", sizeof(arr[1]));
//sizeof(arr[1])计算的是数组第二个元素的大小,1个字节
printf("%d\n", sizeof(&arr));
//sizeof(&arr+1)表示的是整个数组的地址的大小,4/8个字节
printf("%d\n", sizeof(&arr+1));
//sizeof(&arr+1)表示的是整个数组地址+1的地址的大小,4/8个字节
printf("%d\n", sizeof(&arr[0]+1));
//sizeof(&arr[0]+1))表示的是数组第二个元素的地址,4/8个字节

代码段2:

char arr[] = "abcdef";
//arr数组是存放了字符串“abcdef\0”的字符串数组。
printf("%d\n", strlen(arr));
//strlen(arr)计算的是从a字符到第一个\0之前的元素个数,因为字符串末尾隐藏了一个\0,所以大小为6
printf("%d\n", strlen(arr+0));
//strlen(arr+0)计算的是从数组首元素的地址到\0之前的元素个数,大小为6
printf("%d\n", strlen(*arr));
//strlen(*arr)计算的是数组从以首元素的ascll值为地址的元素到第一个\0之前的元素个数,因为该地址不可访问,所以会报错。
printf("%d\n", strlen(arr[1]));
//计算的是数组从以第二个元素的ascll值为地址的元素到第一个\0之前的元素个数,因为该地址不可访问,所以会报错。
printf("%d\n", strlen(&arr));
//strlen(&arr):表示的是整个数组的地址到第一个\0之前的元素个数,整个数组的地址 == 首元素地址。
//大小为6
printf("%d\n", strlen(&arr+1));//因为起始位置是字符串末尾的\0之后,下一个\0位置未知,所以结果为随机值
printf("%d\n", strlen(&arr[0]+1));
//strlen(&arr[0]+1)表示的是数组第二个元素到字符串末尾\0之前的元素个数,大小为5.

将报错代码注释掉后:

代码段3:

char *p = "abcdef";
//p为指针变量,指向的是字符串的首元素a的地址。
printf("%d\n", sizeof(p));
//sizeof(p):p为指针变量,所以大小为4/8个字节
printf("%d\n", sizeof(p+1));
//sizeof(p+1)表示的是字符串中第二个元素b的地址的大小,4/8个字节
printf("%d\n", sizeof(*p));
//sizeof(*p)表示的是字符串首元素a的大小,1个字节(char)
printf("%d\n", sizeof(p[0]));
//sizeof(p[0])表示的是a的大小,1个字节(char)
printf("%d\n", sizeof(&p));
//sizeof(&p)表示的是指针变量p的地址的大小,4/8个字节
printf("%d\n", sizeof(&p+1));
//表示的是p的地址+1处的地址的大小,4/8个字节
printf("%d\n", sizeof(&p[0]+1));
//sizeof(&p[0]+1)表示的是字符串内第二个元素的地址的大小,4/8个字节

代码段4:

char *p = "abcdef";
//p是指针变量,指向字符串的元素的的地址
printf("%d\n", strlen(p));
//strlen(p)计算的是以p指针指向的地址为起始位置,到第一个\0之前的元素个数,大小为6
printf("%d\n", strlen(p+1));
//strlen(p+1)计算的是以p指针+1指向的地址为起始位置,到第一个\0之前的元素个数,大小为5
printf("%d\n", strlen(*p));//报错,解释同前
printf("%d\n", strlen(p[0]));//报错,解释同前
printf("%d\n", strlen(&p));
//strlen(&p)表示的是p指针变量的地址,\0位置不确定,所以大小为随机值
//从p这个指针变量的起始位置开始向后数的,p变量存放的地址是什么,不知道,所以答案是随机值
printf("%d\n", strlen(&p+1));
//strlen(&p+1)表示的是p指针变量+1的地址,\0位置不确定,所以大小为随机值
printf("%d\n", strlen(&p[0]+1));
//strlen(&p[0]+1)表示的是b的地址,计算的是以b的地址为起始位置,到第一个\0之前的元素个数,大小为5

二维数组

二维数组名的意义:
1. sizeof(数组名),这⾥的数组名表⽰整个二维数组,计算的是整个二维数组的⼤⼩。
2. &数组名,这⾥的数组名表⽰整个二维数组,取出的是整个二维数组的地址。
3. 除此之外所有的数组名都表⽰⾸元素(首行)的地址。
int a[3][4] = {0};
//a是三行四列的二维数组,并且全部初始化为0
printf("%d\n",sizeof(a));
//sizeof(a)计算的是整个二维数组的大小,12*4 = 48个字节
printf("%d\n",sizeof(a[0][0]));
//sizeof(a[0][0])计算的是数组首行首元素的大小,大小为4个字节
printf("%d\n",sizeof(a[0]));
//sizeof(a[0])计算的是数组首行的元素的大小,大小为16个字节
printf("%d\n",sizeof(a[0]+1));
//sizeof(a[0]+1)计算的是数组首行第二个元素的地址的大小,大小为4/8个字节
printf("%d\n",sizeof(*(a[0]+1)));
//计算的是数组首行第二个元素的大小,4个字节
printf("%d\n",sizeof(a+1));
//sizeof(a+1)计算的是数组第二行的地址的大小4/8个字节
printf("%d\n",sizeof(*(a+1)));
//sizeof(*(a+1))计算的是数组第二行的元素的大小,16个字节
printf("%d\n",sizeof(&a[0]+1));
//sizeof(&a[0]+1)计算的是数组第二行的地址的大小,4/8个字节
printf("%d\n",sizeof(*(&a[0]+1)));
//sizeof(*(&a[0]+1))计算的是数组第二行元素的大小,16个字节
printf("%d\n",sizeof(*a));
//sizeof(*a)计算的是数组首行元素的大小,16个字节
printf("%d\n",sizeof(a[3]));
//表示的是数组越界访问的第四行的元素大小,16个字节

3、指针运算笔试题解析  

题目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  5

 题目2:

// X86 环境下
// 假设结构体的⼤⼩是 20 个字节
// 程序输出的结构是啥?
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 ;
}

 

 题目三:

# 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 ;
}
        这道题很容易让人进坑。
        题目中给的数组是由三个逗号表达式组成的数组,本质上是赋了3个初值,如果你当成了6个数,那就翻车了。
        结果:1

 题目四:

// 假设环境是 x86 环境,程序输出的结果是啥?
# 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 ;
}
//p是int (*)[4]类型,说明p只将a的前四行地址保存了下来。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/437466.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spring-jpa

一、介绍 1.1ORM 1.2 Java Persistence API 放在javaee版本 优点 支持持久化复杂的Java对象&#xff0c;简化Java应用的对象持久化开发支持使用JPQL语言进行复杂的数据查询使用简单&#xff0c;支持使用注解定义对象关系表之间的映射规范标准化&#xff0c;由Java官 方统一规…

K8s Pod控制器

目录 前言&#xff1a; 1.Deployment 查看控制器配置 查看历史版本 2.SatefulSet 安装CoreDNS&#xff0c;仅二进制部署环境需要安装CoreDNS 方法一 方法二 查看statefulset的定义 清单定义StatefulSet 创建pv 定义PV 创建statefulset 滚动更新 总结 扩展伸缩…

PEIS源码 健康体检中心源码 C/S

目录 一、系统概述 二、系统开发环境 三、系统功能 检前管理 检中管理 检后管理 设备对接-PACS 设备对接-彩超 LIS-结果录入、审核、外送结果自动导入 一、系统概述 体检系统&#xff0c;是专为体检中心/医院体检科等体检机构&#xff0c;专门开发的全流程管理系…

学习 考证 帆软 FCP-FineBI V6.0 心得

学习背景&#xff1a; 自2024年1月起&#xff0c;大部分时间就在家里度过了&#xff0c;想着还是需要充实一下自己&#xff0c;我是一个充满热情的个体。由于之前公司也和帆软结缘&#xff0c;无论是 Fine-Report 和 Fine-BI 都有接触3年之久&#xff0c;但是主要做为管理者并…

小火星露谷管理器如何设置N网API KEY

在小火星露谷管理器的设置页面点击设置API KEY&#xff0c;其中描述了如何获取API KEY。 如何获取API KEY&#xff1f; 打开N网NexusMods登录N网账号查看N网的账号详情页的API标签页滑动到网页底部复制Personal API Key 框内的文本 在管理器的设置页面填写API KEY

C语言数据类型详解及相关题——各种奇奇怪怪的偏难怪

文章目录 一、C语言基本数据类型溢出 二、存储原理符号位原码反码补码补码操作的例子 三、赋值中的类型转换常见返回类型——巨坑总结 一、C语言基本数据类型 溢出 因为数据范围&#xff08;即存储单元的位的数量&#xff09;的限制&#xff0c;可以表达的位数是有限的。 溢出…

我的创作周年纪念日

机缘 最初成为创作者的初心&#xff1a;整理自己的知识体系&#xff0c;普及前端知识 实战项目中的经验分享日常工作学习过程中的记录通过文章进行技术交流归纳和整理自己的知识体系 收获 创作的过程中收获&#xff1a; 获得了909粉丝的关注获得了很多正向的反馈&#xff0c…

第五十一天| 309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费

第四十八天| 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II-CSDN博客 第五十天| 123.买卖股票的最佳时机III、188.买卖股票的最佳时机IV-CSDN博客 Leetcode 309.最佳买卖股票时机含冷冻期 题目链接&#xff1a;309 最佳买卖股票时机含冷冻期 题干&#xff1a;给定一个…

vue api封装

api封装 由于一个项目里api是很多的&#xff0c;随处都在调&#xff0c;如果按照之前的写法&#xff0c;在每个组件中去调api&#xff0c;一旦api有改动&#xff0c;遍地都要去改&#xff0c;所以api应该也要封装一下&#xff0c;将api的调用封装在函数中&#xff0c;将函数集…

Keepalive 解决nginx 的高可用问题

一 说明 keepalived利用 VRRP Script 技术&#xff0c;可以调用外部的辅助脚本进行资源监控&#xff0c;并根据监控的结果实现优先动态调整&#xff0c;从而实现其它应用的高可用性功能 参考配置文件&#xff1a; /usr/share/doc/keepalived/keepalived.conf.vrrp.localche…

GPT-4技术解析:与Claude3、Gemini、Sora的技术差异与优势对比

【最新增加Claude3、Gemini、Sora、GPTs讲解及AI领域中的集中大模型的最新技术】 2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚…

干货分享③:免费制作产品管理系统!

他来了&#xff0c;他来了&#xff0c;他带着码上飞CodeFlying走来了&#xff01;今天继续为大家带来一期干货分享&#xff0c;教大家如何免费使用码上飞来的开发产品管理系统 &#xff01; 一、登陆官网 码上飞 CodeFlying | AI 智能软件开发平台&#xff01; 点击立即体验注…

代码随想录算法训练营Day38 || leetCode 7509. 斐波那契数 || 70. 爬楼梯 || 746. 使用最小花费爬楼梯

动态规划和我们数电中学习的时序电路类似&#xff0c;某一时刻的状态不仅与当前时刻的输入有关&#xff0c;还与之前的状态有关&#xff0c;所以推导过程中我们需要模拟题目中的情况&#xff0c;来找到每一时刻状态间的关系。 做题思路如下 509. 斐波那契数 此题简单 状态方程…

对于simplex算法的代码实现最优解存在性的证明

对于任何线性规划系统,并不是都存在最优解,如果在约束条件中,每个常量都是大于等于0的,那么线性规划系统肯定是有最优解的,此时将每个变量选取为0就可以了。而只有当约束条件中的常量有小于0的情况的时候,才需要验证系统是否存在最优解,给出一个反例,进行最优解的存在性…

[项目设计] 从零实现的高并发内存池(五)

&#x1f308; 博客个人主页&#xff1a;Chris在Coding &#x1f3a5; 本文所属专栏&#xff1a;[高并发内存池] ❤️ 前置学习专栏&#xff1a;[Linux学习] ⏰ 我们仍在旅途 ​ 目录 8 使用定长内存池脱离new 9. 释放对象时不传大小 10.性能优化 10.1…

电脑要用多少V的电源?电脑电源输入电压是市电

台式电源的输出电压是多少&#xff1f; 电脑电源输出一般有三种不同的电压&#xff0c;分别是&#xff1a; 12V、5V、3.3V。 电脑电源负责给电脑配件供电&#xff0c;如CPU、主板、内存条、硬盘、显卡等&#xff0c;是电脑的重要组成部分。 工作电流根据不同的硬件及其使用状…

前端技术研究越深入,越觉得技术不是决定录用唯一条件。

一、拒绝抬杠 我说技能不是唯一条件&#xff0c;不是说技能不重要&#xff0c;招聘前端条件是1X,其中1是技能&#xff0c;X是其他条件。 如果X条件很优秀&#xff0c;1这个条件可以降格为0.8、0.5&#xff0c;甚至更低。 有人就抬杠&#xff0c;那为啥不招聘清洁工来干前端&…

软考一年一次,自学的人扛不住了...

相信大家最近也看到了&#xff0c;软考有些科目已经改为一年一次&#xff0c;对于自学的人来讲&#xff0c;无疑是雪上加霜... 2024年软考考试时间安排&#xff1a; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字…

构建读写分离的数据库集群

目录 1. 基础环境配置 &#xff08;1&#xff09;修改主机名 &#xff08;2&#xff09;编辑hosts文件 &#xff08;3&#xff09;配置Yum安装源 &#xff08;4&#xff09;安装JDK环境 2. 部署MariaDB主从数据库集群服务 &#xff08;1&#xff09;安装MariaDB服务 &a…

记录一次Dubbo远程调用的错误

情景&#xff1a;有一个生成PDF的接口中&#xff0c;如下&#xff1a; GET Path("/getPDF") public void getPDF(QueryParam("id") String id, Context HttpServletResponse response) {………… }之前实现的代码都写在了Controller里面&#xff0c;代码里…