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

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.xdnf.cn/news/17963.html

相关文章:

  • 获取农历日期
  • Jeecg后端经验汇总
  • strings命令和findstr命令验证iso文件中ntkrnlmp.exe系统版本
  • 如何避免网盘中资源被和谐?
  • LeetCode算法日记 - Day 12: 寻找旋转排序数组中的最小值、点名
  • Erlang notes[2]
  • Vue 侦听器(watch 与 watchEffect)全解析1
  • 图解软件知识库体系
  • GaussDB 常用数值类型
  • 分布式锁:从理论到实战的深度指南
  • python自学笔记8 二维和三维可视化
  • 深入解析Prompt缓存机制:原理、优化与实践经验
  • 云原生俱乐部-杂谈1
  • CVE-2014-6271(bash破壳漏洞 )
  • Android数据缓存目录context.getCacheDir与Environment.getExternalStorageDirectory
  • Git 中切换到指定 tag
  • 会议系统进程池管理:初始化、通信与状态同步详解
  • Fiddler抓包
  • 【FreeRTOS】刨根问底4: 优先级反转是啥?咋解决?
  • 为什么Integer缓存-128 ~ 127
  • 学习设计模式《二十二》——职责链模式
  • 搭建 Docker 私有仓库
  • springboot项目不同平台项目通过http接口AES加密传输
  • UE5配置MRQ编解码器输出MP4视频
  • 机器人“ChatGPT 时刻”倒计时
  • 电池模组奇异值分解降阶模型
  • 两种方法实现,本地部署Qwen-Image,并开放API服务
  • MyBatis学习总结(六)
  • 高并发内存池 性能瓶颈分析与基数树优化(9)
  • vLLM(Vectorized Large Language Model Serving) 的深度解析