当前位置: 首页 > news >正文

C语言——深入理解指针(四)

C语言——深入理解指针(四)

数组名的意义

  • sizeof(数组名),且数组名单独放在sizeof内部,则这里的数组名表示整个数组,计算的是整个数组的大小
  • &数组名,这里的数组名表示的是整个数组,取出的是整个数组的地址
  • 除此之外所有的数组名都表示首元素的地址

sizeof和strlen的比较

1.sizeof是操作符,用于计算变量所占内存大小(不关注内存中存放什么数据),单位是字节
在这里插入图片描述
2.strlen是库函数(需要包含头文件<string.h>),求字符串长度。其统计的是从strlen函数的参数str中这个地址开始向后,\0之前字符串中字符的个数。函数原型:

size_t strlen (const char* str)//返回类型注意为size_t

在这里插入图片描述
但若没有\0,就可能会存在越界查找,结果就是一个随机数,如下图所示:
在这里插入图片描述
3.比较
在这里插入图片描述

实例:

(一)一维数组

这里千万要注意前面提到的数组名的意义

#include<stdio.h>
int main()
{int a[] = { 1,2,3,4 };
printf("%zu\n", sizeof(a));//16
//a单独在sizeof里面代表整个数组,即四个元素乘以它们的类型所占字节
printf("%zu\n", sizeof(a+0));//4/8
//a没有单独在里面,所以代表首元素的地址,那么a+0还是首元素的地址,这里计算的是一个地址的大小不同环境有差别
printf("%zu\n", sizeof(*a));//4
//这里a没有单独放在sizeof内,a就是首元素地址,*a就是首元素1
printf("%zu\n", sizeof(a+1));//4/8
//a是首元素的地址,a+1就是第二个元素的地址
printf("%zu\n", sizeof(a[1]));//4
//第二个元素
printf("%zu\n", sizeof(&a));//4/8
//&a取出的是数组的地址,数组的地址也是地址
printf("%zu\n", sizeof(*&a));//16
//&a取出的是数组的地址,它的类型为int(*)[4]
//对于数组指针解引用,访问的则是这个数组
printf("%zu\n", sizeof(&a+1));//4/8
//&a是数组的地址,&a+1是跳过数组后的地址
printf("%zu\n", sizeof(&a[0]));//4/8
//第一个元素的地址
printf("%zu\n", sizeof(&a[0]+1));//4/8
//跳过第一个元素的地址,到达第二个元素的地址
return 0;
}

运行结果:
在这里插入图片描述

(二)字符数组

(1)操作符sizeof

#include<stdio.h>
int main()
{char arr[] = { 'a','b','c','d','e','f'};printf("%zu\n", sizeof(arr));//6,计算整个数组printf("%zu\n", sizeof(arr + 0));//4/8,首元素的地址printf("%zu\n", sizeof(*arr));//1,*arr就是首元素printf("%zu\n", sizeof(arr[1]));//1,第二个元素printf("%zu\n", sizeof(&arr));//4/8,数组的地址printf("%zu\n", sizeof(&arr + 1));//4/8,依旧是地址printf("%zu\n", sizeof(&arr[0] + 1));//4/8,第二个元素的地址return 0;
}

运行结果:
在这里插入图片描述

#include<stdio.h>
int main()
{char* p = "abcdef";printf("%zu\n", sizeof(p));//4/8//p是一个指针变量,我们假设地址0x0012ff30printf("%zu\n", sizeof(p + 0));//4/8//p+1就是b的地址printf("%zu\n", sizeof(*p));//1//char*类型指针解引用只能访问一个字符printf("%zu\n", sizeof(p[0]));//1//p[0]->*(p+0)->*p,就是第一个元素printf("%zu\n", sizeof(&p));//4/8//&p是指针变量p的地址,是二级指针printf("%zu\n", sizeof(&p+ 1));//4/8printf("%zu\n", sizeof(&p[0] + 1));//4/8//&p[0]+1就是b的地址return 0;
}

在这里插入图片描述
在这里插入图片描述
(2)库函数strlen():

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%zu\n", strlen(arr));//随机值//arr是数组首元素地址,strlen算的是整个数组,由于字符串中找不到\0,所以为随机值printf("%zu\n", strlen(arr + 0));//随机值//(arr+0)也是首元素地址printf("%zu\n", strlen(*arr));//程序崩溃//arr是首元素地址,*arr就是首元素即‘a’——97//这里就会出现非法访问内存printf("%zu\n", strlen(arr[1]));//程序崩溃//同上printf("%zu\n", strlen(&arr));//随机值//整个数组的地址,从数组的起始位置数字符串的长度,但是没有\0printf("%zu\n", strlen(&arr + 1));//随机值//跳过这个数组的地址,向后找\0printf("%zu\n", strlen(&arr[0] + 1));//随机值//从第二个元素的地址,向后找\0return 0;
}
int main()
{char* p = "abcdef";printf("%zu\n", strlen(p));//6//p就是a的地址,直至遇到\0向后数有6个字符printf("%zu\n", strlen(p+1));//5//p+1指向b,向后数直到遇到\0有五个字符printf("%zu\n", strlen(*p));//error//*p就是第一个字符printf("%zu\n", strlen(p[0]));//error//同上printf("%zu\n", strlen(&p));//随机值//p变量在内存中后续的空间内容不确定printf("%zu\n", strlen(&p+1));//随机值//同上printf("%zu\n", strlen(&p[0]+1));//5//&p[0]就是a的地址,&p[0]+1就是b的地址,从b的位置向后数return 0;
}

(三)二维数组

  • 这里还是要特别注意:数组名单独放在sizeof内,表示整个数组
  • 还要注意的一个点:sizeof在计算变量,数组的大小时,是通过类型来推导的,不会真实去访问内存,举个栗子:

在下图中,括号内s=a+2,其中a和2都是int类型,算出来s=12,但sizeof并不会去计算,而是看s本身是什么类型,short类型占两个字节,所以打印出来的仍是2而不是4;而打印s的值时,也不会因为在sizeof里面的算式而改变。

在这里插入图片描述

  • 实例
#include<stdio.h>
int main()
{int a[3][4] = { 0 };printf("%zu\n", sizeof(a));//48printf("%zu\n", sizeof(a[0][0]));//4printf("%zu\n", sizeof(a[0]));//16//a[0]是第一行一维数组名,单独放在sizeof内部// 表示第一行这个数组printf("%zu\n", sizeof(a[0]+1));//4/8//a[0]没有单独放在sizeof中// 则a[0]是第一行第一个元素的地址,a[0]+1是第一行第二个元素的地址printf("%zu\n", sizeof(*(a[0] + 1)));//4//*(a[0] + 1)是第一行第二个元素printf("%zu\n", sizeof(a+1));//4/8//a未单独放在sizeof中,表示数组首元素的地址,就是第一行的地址// a+1就是第二行的地址printf("%zu\n", sizeof(*(a+1)));//16//a+1是第二行的地址,解引用就是a[1]这行数组,计算的是整个数组的大小printf("%zu\n", sizeof(&a[0]+1));//4/8//表示第二行的地址printf("%zu\n", sizeof(*( & a[0] + 1)));//16//第二行的地址解引用就是这一行printf("%zu\n", sizeof(*a));//16//a没有单独放在里面,是第一行的地址,解引用就是a[0]printf("%zu\n", sizeof(a[3]));//16//sizeof在计算变量,数组的大小时,是通过类型来推导的,不会真实去访问内存//所以这里不会有越界访问return 0;
}

在这里插入图片描述
我们来测试一下运行结果:
在这里插入图片描述

本次内容到这里就结束了,谢谢观看,如有不对欢迎在评论区留言指正。
心向往之行必能至!

http://www.dtcms.com/a/332713.html

相关文章:

  • 完整技术栈分享:基于Hadoop+Spark的在线教育投融资大数据可视化分析系统
  • 使用XXL-SSO实现登录认证以及权限管控
  • 解决 MySQL 查询速度缓慢的问题
  • Filebeat 轻量级日志采集实践:安装、配置、多行合并、JSON 解析与字段处理
  • Java集合Map与Stream流:Map实现类特点、遍历方式、Stream流操作及Collections工具类方法
  • 【软件设计模式】前置知识类图、七大原则(精简笔记版)
  • C++ 调试报错 常量中有换行符
  • 基于桥梁三维模型的无人机检测路径规划系统设计与实现
  • Cursor 分析 bug 记录
  • 3D视觉与空间智能
  • imx6ull-驱动开发篇25——Linux 中断上半部/下半部
  • 智谱开源了最新多模态模型,GLM-4.5V
  • 关系型数据库从入门到精通:MySQL 核心知识全解析
  • 高并发系统性能优化实战:实现5万并发与毫秒级响应
  • Kafka生产者——提高生产者吞吐量
  • LeetCode 面试经典 150_数组/字符串_最长公共前缀(20_14_C++_简单)(暴力破解)(求交集)
  • 简单使用 TypeScript 或 JavaScript 创建并发布 npm 插件
  • 从零到一:发布你的第一个 npm 开源库(2025 终极指南)
  • IT资讯 | VMware ESXi高危漏洞影响国内服务器
  • Day62--图论--97. 小明逛公园(卡码网),127. 骑士的攻击(卡码网)
  • 嵌入式 C 语言编程规范个人学习笔记,参考华为《C 语言编程规范》
  • 使用CMAKE-GU生成Visual Studio项目
  • ​Visual Studio 2013.5 ULTIMATE 中文版怎么安装?iso镜像详细步骤
  • Pushgateway安装和部署,以及对应Prometheus调整
  • 六维力传感器:工业机器人的“触觉神经”如何突破自动化瓶颈?
  • Linux crontab定时任务
  • 3.1. CPU拓扑配置
  • 4.2 寻址方式 (答案见原书 P341)
  • Nginx蜘蛛请求智能分流:精准识别爬虫并转发SEO渲染服务
  • 嵌入式学习日记(29)进程、线程