初学C语言:sizeof 和 strlen 你真的了解吗?

前言:本人为C语言初学者,学识尚浅,研究程度存在很大的局限性,眼界很窄。以下所有观点仅代表个人见解和思路,各位游刃有余的前辈可以给予批评和指正!各位与鄙人同路的学子可相互探讨、发表看法,交换观点!

目录

STRLEN

1.直接放数组

2.数组名加法运算

3.取地址数组名

4.取数组和下标引用的地址

5.错误写法

(1)

(2)

SIZEOF

1.直接放数组:

2.数组名加法运算

3.解引用数组名

4.数组名和下标引用

5.取地址数组名

6.取地址和解引用

7.取数组和下标引用的地址


sizeof,耳熟能详的操作符,用于计算数组的空间大小、类型大小、数组元素个数时都非常实用,就以上三点,对应以下代码:

int arr[10] = {0};
sizeof(arr); //计算整个数组的大小
sizeof(arr[0]); //计算数组单个元素的大小
sizeof(int); //计算整数类型大小

strlen,是C语言的一个库函数,用于返回字符串的长度,例如:

char str[] = "abcde";
strlen(str);

到这里,你似乎觉得并没有什么可说的,但是你是否注意到,对于 strlen 函数只能接收地址,且其声明是这样的:size_t strlen( const char *string ); 也就是说,其地址会被强制装进字符类型指针

而对于sizeof,你会发现,你可以把地址丢给它,类型丢给它,数组也可以直接丢给它,真是和void垃圾桶有得一拼

既然都涉及到了地址,如果不玩玩指针,怎么让你学到新游戏呢?啊不对,新东西。

STRLEN

首先,我们定义一个这样的数组:

char arr[] = "abcdef";

1.直接放数组

int ret = strlen(arr);

strlen不是sizeof,数组名在这里就是首元素地址,所以它从首元素开始读取,直到碰到 '\0' 才会停下来,所以结果是6。故由此也可知,你可不要写出这样的数组:

char arr[] = {'a', 'b', 'c'};

没有‘\0’是十分危险的!

2.数组名加法运算

int ret = strlen(arr + 0);

同理,这里也是数组首元素地址加上0,依然为数组首元素地址,结果依然为6。

3.取地址数组名

int ret = strlen(&arr);

首先要明白的是,我们这里是取出了整个数组的地址,但是如果你细心就会发现其实它的地址和数组首元素地址是一样的,只是它们一个是 char[7] 类型的,一个是 char 类型的,这就导致它们的访问权限不同,但是地址仍然是相同的,所以仍然为6。

但是如果你这样写:

int ret = strlen(&arr + 1);

那这个加1就跳过了整个数组,导致后内容未知:

所以其应该为随机值,我们并不知道它什么时候找到 ‘\0’ 

4.取数组和下标引用的地址

int ret = strlen(&arr[0]);

这样获得的还是首元素地址嘛,等同于:strlen(arr);

如果你写成这样:

int ret = strlen(&arr[0] + 1);

其指向的是后一个元素,即等同于:strlen(&arr[1]); 所以结果是5。

5.错误写法

(1)

strlen(*arr);

数组名本就是首元素地址,如果取值,则得到了字符 a,但 strlen 前文已述,只能接收地址,如果你硬是传一个 a 过去,最后被读取成地址,strlen就跑到了:0x00000061 去了,咋不出错呢?

(2)

strlen(arr[0]);

和(1)是异曲同工之妙,只是另一种表达方式

总而言之,对于 strlen,首先要清楚,传进去的一定是地址;其次,要明确该地址的指向!

SIZEOF

注:使用64位系统,方便区分int类型大小和地址大小!

首先,我们定义一个数组如下,记好了,记好了,记好了:

int arr[4] = {1 , 2, 3, 4};

我们最常见的情况是:

1.直接放数组:

int ret = sizeof(arr);

这种情况实际是比较特殊的,其实我们知道,数组名如果直接使用的话是当作首元素地址的,唯独两种情况:(1)sizeof,(2)&arr

很不幸,sizeof就居其一,在这里,sizeof 计算的是整个数组的大小,即我们计算其为 int 类型,然后有4个元素,总共是 4*4 = 16byte,当然,其实我认为更正确的理解方法是:其类型为 int[4],所以占16个字节。当然,你喜欢哪一种都可以。

2.数组名加法运算

int ret = sizeof(arr + 0);

数组名加上一个数字,这个数组名当然就不能被当作整个数组使用了,而是露出了它的真实面目,变为了首元素的地址,所以这里其实等同于:sizeof(&arr[0]); 所以结果其实计算的是地址的长度,因为arr参与了运算,所以自然就当作了数组名的本来用途:首元素的地址。所以这里不管你加几,其实都是8,因为都是地址嘛!(当然,我劝你还是不要越界)

3.解引用数组名

int ret = sizeof(*arr);

arr是啥,懵了吧~再次强调,这里 arr 相当于和*先结合了,所以arr是被当作了首元素地址,例2中也是殊途同归,因为 arr+2 先运算,所以 arr 也被当作了首元素地址。所以这里就等同于:             sizeof(*&arr[0]); 好像有点怪?*&是一对,所以抵消了,你可以这样看。当然如果你先取地址再取值也是一个道理,所以这里进一步等价于:sizeof(1); 1是啥,1是啥!?1是整数啊喂,所以计算的实际上是int的大小,也就是4byte

4.数组名和下标引用

int ret = sizeof(arr[1]);

说的挺玄乎,其实就是这玩意儿,arr[1] 表示的是2呀,一个整数,所以同理,计算的还是 int 的大小,即4byte。

5.取地址数组名

int ret = sizeof(&arr);

呃,你就告诉我取地址得到的是什么吧!(唏嘘不已,小学生都知道)所以地址的大小肯定是8byte了呗。当然这里也有值得我们深入解析的地方:arr 和 & 先结合,所以 arr 被当作首元素地址,但是这又是一种特殊情况,就是 arr 和 & 结合取出的是数组的地址,这一点就是刚开始提到的数组名特殊用法的第二种。所以如果我们写成这样:

int ret = sizeof(&arr + 1);

虽然结果还是8(因为还是地址),但是其实地址是跳过了整个数组的哦!

6.取地址和解引用

int ret = sizeof(*&arr);

如果你嫌麻烦,* & 一抵消,自然就是计算的整个数组的大小,为16byte。

但是如果打破砂锅问到底,这里的 & 和 arr 结合得到的是整个数组的地址,然后再解引用,得到的就是 arr 数组名,但是有人就要问了,这里不是有操作符和 arr 结合嘛,那arr不应该最后被当作首元素地址?实则不然,因为&和*都实施后,只剩下了 arr,故严格意义上来讲,只能说,它曾经有过(为什么我没有),但是最后还是没有。(我**一直没有!)

7.取数组和下标引用的地址

int ret = sizeof(&arr[0]);

当然,看到取地址,直接答8!(前提语法是对的嗷)这里即取出了数组首元素地址~如果对其进行加法,则表明指向后几位元素,但是仍是地址,为8byte。

当然,如果我再用一个指针变量存放arr首元素地址或者诸如此类其它,都只是换汤不换药,逐步分析即可求解!

不知道以上内容有没有帮助你更深入的理解strlen和sizeof呢?如果遗漏,请务必指出哦!

END

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thepale2022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值