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的前四行地址保存了下来。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解高质量增长的关键动力:ABM、数据、AI与业财融合

企业要穿越周期&#xff0c;不能仅靠节衣缩食&#xff0c;增长与盈利仍是必须。当盲目做大规模无法带来可持续发展&#xff0c;高质量增长便成为必须。在降本增效之上&#xff0c;企业需要变革增长模式。 在纷享销客的《领创者》开年直播上&#xff0c;纷享销客联合创始人、经…

阿里云服务器Ngnix配置SSL证书开启HTTPS访问

文章目录 前言一、SSL证书是什么&#xff1f;二、如何获取免费SSL证书三、Ngnix配置SSL证书总结 前言 很多童鞋的网站默认访问都是通过80端口的Http服务进行访问&#xff0c;往往都会提示不安全&#xff0c;很多人以为Https有多么高大上&#xff0c;实际不然&#xff0c;他只是…

【QT】QDialog/ QMessageBox/提示对话框/颜色(文字)------对话框

QDialog—对话框 什么是对话框&#xff0c;如下样式 非模态对话框&#xff0c;即打开以后&#xff0c;我还可以对其他框进行操作。 模态对话框&#xff0c;打开以后&#xff0c;其他框都不能再操作了 模态对话框是阻塞对话框 QDialog dig(this);//显示模态对话框dig.exec();…

基于redis实现用户登陆

因为session有数据共享问题&#xff0c;不同tomcat服务器中的session不能共享&#xff0c;之后负载均衡就无法实现。所以我们用redis代替session。redis可以被多个tomcat服务器共享&#xff0c;redis基于内存。 之前的session可以看做登陆凭证&#xff0c;本次登陆凭证由sessi…

App Inventor 2 Personal Image Classifier (PIC) 拓展:自行训练AI图像识别模型,开发图像识别分类App

这里仅仅介绍一下AI图像识别App的实现原理&#xff0c;AI的基础技术细节不在本文讨论范围。通过拓展即可开发出一款完全自行训练AI模型&#xff0c;用于特定识别场景的App了。 我们都知道&#xff0c;人工智能AI的基本原理是事先准备好样本数据&#xff08;这里指的是图片&…

设计高并发秒杀系统:保障稳定性与数据一致性

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 一. 系统架构设计 1. 系统架构图 二、 系统流程 三…

英福康INFICON真空计VGC012-103-401使用说明

英福康INFICON真空计VGC012-103-401使用说明

基于深度学习的语音识别的未来

基于深度学习的语音识别是当前人工智能领域的研究热点之一。随着语音技术的不断发展&#xff0c;语音识别技术将在未来扮演更加重要的角色。 语音识别技术的发展已经有几十年的历史&#xff0c;但是基于深度学习的语音识别技术在近年来才取得了突破性的进展。深度学习技术可以…

01-环境搭建、SpringCloud微服务(注册发现、服务调用、网关)

环境搭建、SpringCloud微服务(注册发现、服务调用、网关) 1)课程对比 2)项目概述 2.1)能让你收获什么 2.2)项目课程大纲 2.3)项目概述 随着智能手机的普及&#xff0c;人们更加习惯于通过手机来看新闻。由于生活节奏的加快&#xff0c;很多人只能利用碎片时间来获取信息&…

【BUG】cmd运行wmic提示‘wmic‘ 不是内部或外部命令

cmd运行wmic提示‘wmic‘ 不是内部或外部命令 解决办法 将C:\Windows\System32\wbem添加到系统环境变量

electron 程序与安装包图标放大与制作

原因 electron-builder 在打包时需要最小支持到256x256像素的icon图标。原有历史图标都太小了。需要尝试将图标放大。 工具 convertio.co/zh/ico-png/ 在线ico转png网站 https://github.com/upscayl/upscayl 图片放大工具 csdn下载 greenfish-icon-editor-pro.en.softonic.c…

Flink学习4 - 富函数 + 数据重分区操作 + sink 操作(kafka、redis、jdbc)

1、富函数 - 函数类接口&#xff0c;可以获取运行环境的上下文&#xff0c;实现更复杂的功能 2、数据重分区操作 3、sink操作 sink - kafka 1、引入kafka的pom依赖 <dependency><groupId>org.apache.flink</groupId> <!--<artifactId>flink-conn…

Java基础知识点

Java基础知识点 1.方法重载和重写的区别 方法重载&#xff1a; 同一个类中的方法&#xff0c;方法名相同&#xff0c;返回值可以相同可以不同&#xff0c;参数列表必须不同发生在编译期&#xff0c;在编译期确定执行哪个方法 方法重写&#xff1a; 指的是子类重新定义父类…

【国产MCU】-CH32V307-SysTick中断与延时功能实现

SysTick中断与延时功能实现 文章目录 SysTick中断与延时功能实现1、SysTick介绍2、SysTick中断使用3、SysTick实现微秒和毫秒延时功能CH32V307的RISC-V内核控制器自带的一个64位可选递增或递减的计数器,用于产生SYSTICK异常(异常号:15),可专用于实时操作系统,为系统提供“…

LabVIEW高精度天线自动测试系统

LabVIEW高精度天线自动测试系统 系统是一个集成了LabVIEW软件的自动化天线测试平台&#xff0c;提高天线性能测试的精度与效率。系统通过远程控制测试仪表&#xff0c;实现了数据采集、方向图绘制、参数计算等功能&#xff0c;特别适用于对天线辐射特性的精确测量。 在天线的…

20 easy 70. 爬楼梯

//假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 // // 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; // // // // 示例 1&#xff1a; // // //输入&#xff1a;n 2 //输出&#xff1a;2 //解释&#xff1a;有两种方法可以爬到楼顶。 /…

uniapp H5 $el.querySelectorAll is not a function

在监听是否在可视区域遇到问题&#xff08;网页端&#xff09; 解决方案 <view class"container"> ...省略 业务代码... </view>参考 &#xff1a; https://blog.csdn.net/qq_18841969/article/details/134620559

裸机编程的几种模式、架构、缺陷

目录 裸机编程模式/架构 1&#xff1a;初始化代码的编写 裸机编程模式/架构 2&#xff1a;轮询模式 裸机编程模式/架构 3&#xff1a;轮询加中断执行模式 裸机编程模式/架构 4&#xff1a;中断定时器主循环的前后台架构 裸机编程模式/架构 5&#xff1a;前后台 状态机架构…

常见的几种echarts类型

一&#xff1a;折线图 let option {tooltip: {},animation: false,grid: {top: "20%",bottom: "33%", //也可设置left和right设置距离来控制图表的大小left: 5%,right: 5%},xAxis: {boundaryGap:false,data: [1,2,3,4,5],axisLine: {show: true, //隐藏X轴…

Leetcode : 147. 对链表进行插入排序

给定单个链表的头 head &#xff0c;使用 插入排序 对链表进行排序&#xff0c;并返回 排序后链表的头 。 插入排序 算法的步骤: 插入排序是迭代的&#xff0c;每次只移动一个元素&#xff0c;直到所有元素可以形成一个有序的输出列表。 每次迭代中&#xff0c;插入排序只从输…