strlen函数与单目运算符sizeof的区别
相同之处
Strlen函数与sizeof单目运算符均可以计算字符型数组的长度,示例如下:
#include <iostream>
using namespace std;
void main()
{
char str[] = "超级霸霸强";
cout << sizeof(str)-strlen(str) << endl; // 返回值为1
}
有朋友说,为什么我写strlen(str)-sizeof(str)得出的结果不是-1呢?这就涉及到我们要讲的两者的第二个相同之处。
返回值类型相同
#include <iostream>
using namespace std;
void main()
{
char str[] = "超级霸霸强";
cout << strlen(str) - sizeof(str) << endl;
// 结果为4294967295
}
我现在就讲解一下结果的由来:
Strlen函数的返回值是unsigned int型的结果占四个字节的存储空间,unsigned int所能表示的最大值是[0, 4294967295],这个范围就像一个封闭的环一样,-1就相当于4294967295。
Sizeof一样返回值类型也为unsigned int型变量,无论如何计算均为>=0的值,例如:
#include <iostream>
using namespace std;
void main()
{
char str[] = "超级霸霸强";
cout << sizeof(str)-15 << endl;
// 结果为4294967295-15=4294967280
// 原理如下:
// unsigned int i = 0;
// i -= 5; // 最终i的值还是大于0的数值
}
不同之处
原理不同
Strlen作为针对字符型数组的函数他有很强的针对性,它的功能就是计算字符型数组的长度,其他类型它不支持。
单目运算符sizeof 是一个单目单目运算符,而不是一个函数。与函数 strlen 不同,它的参数可以是数组、指针、类型、对象、函数等。
有些网友会问到:为什么指针变量 的sizeof()打印出来的都是 4?
大家注意,我这里说的是指针变量,不是数组名。因为sizeof单目运算符是对缓存区进行操作的,它从变量的开始地址开始读取,一直读取到变量结束。
对于数组,sizeof计算的是数组长度:
#include <iostream>
using namespace std;
void main()
{
char str[] = "超级霸霸强";
cout << sizeof(str) << endl; // 结果为11,因为字符串结尾有结束符'\0'
}
对于地址变量,sizeof计算的是单个变量的大小:
#include <iostream>
using namespace std;
void main()
{
char str[] = "超级霸霸强";
char *str1 = str;
cout << sizeof(str1) << endl; // 结果为4
}
大家思考一下,为什么下面两个程序会有所不同?
①
#include <iostream>
using namespace std;
void main()
{
char str[] = "超级霸霸强";
char *str1 = str;
cout << strlen(str1) << endl; // 结果为10
}
②
#include <iostream>
using namespace std;
void main()
{
char str[] = "超级霸霸强";
char *str1 = str;
cout << sizeof(str1) << endl; // 结果为4
}
以上结果为什么不同呢?
因为strlen是对变量存储的地址进行操作进而读取字符型数组的大小;而sizeof则是从变量的地址开始读取直至读取完变量所占的所有空间。看上面的例子可以知道,64位的电脑最多可以访问4个字节长的内存空间,因此地址变量无论指向何种类型的数据,存储空间均为4字节,即4 bytes。
Sizeof不能求得动态数组的大小,而strlen函数可以
Sizeof是个单目运算符在系统编译程序之前就已经执行,如果sizeof(a)中a为地址变量,拿结果返回4 bytes,在编译程序之前没人知道a是否动态申请了空间,只知道他是个地址变量。动态申请空间那是程序编译的时候执行的,但是sizeof单目运算符在程序编译之前就已经执行完了。
Sizeof的错误用法:
#include <iostream>
using namespace std;
void main()
{
char *str = new char[2]{ 's','s' };
cout << sizeof(str) << endl;
// 结果为4,代表的是指针所占用内存的大小,而不是动态数组的长度
}
Strlen计算动态申请的空间:
#include <iostream>
using namespace std;
void main()
{
char *str = new char[3]{'s','s','\0' }; // 必须带'\0'字符串结束符
cout << strlen(str) << endl;
// 结果为2,strlen是个函数,它是在编译时执行的,在此之前str已经动态申请了存储空间
}
我们注意到strlen求解数组的大小,其中数组必须最后一个元素是’\0’字符串结束符,strlen函数计算出的字符数组长度不包括’\0’,因此字符型数组真实的长度是strlen(str)+1。
Sizeof单目运算符与strlen函数被执行的次序不同
Sizeof是单目运算符它是在程序编译以前就已经执行完成,因此他与编译过程中执行的strlen函数有很大区别。由于new动态申请数组是在编译过程中执行,因此sizeof不能判断动态申请数组的长度。
// 以C语言中的malloc为例:
char *str = (char*)malloc(sizeof(char) * 4); // 由于char变量大小为1 byte,因此在编译过程中,此语句等价为:char *str = (char)malloc(1 * 4)
// 由于malloc申请的内存空间是void*型的,因此要强制类型转换至char*型的