前言:
sizeof是操作符,strlen是库函数。虽然定义简单,但是有很多需要注意的知识点...
目录:
三、sizeof与strlen的比较(其实就是字符数组和字符串数组的比较)
一、sizeof操作符
sizeof 返回变量或类型占用的内存量(以字节为单位),它与变量的值无关
注意事项:
”与变量的值无关“ -- sizeof()不会计算括号内部的表达式
如图案例所示:假设有第五行的数组,此时第五行数组的大小是4*4=16,sizeof操作符()内部不参与实际运算,所以实际上没有去越界访问。
sizeof是关键字,是在编译阶段处理的
也就是说你程序没有运行前,sizeof(arr)就被替换成了一个固定的常量,保存在了test.out中了。你可以试试这样写
sizeof ptr
也是不会报错的,这也说明了sizeof不是函数。如图案例所示:如果sizeof内部是一个表达式,首先sizeof并不会对括号内部的表达式进行计算,并且sizeof是再编译期间将表达式替换成固定的常量4,所以返回内存量是4个字节。
当在用户自定义的类型上使用时,
sizeof
仍然返回该类型的实例使用的内存量,但值得指出的是,这并不一定等于其成员的总和如图案例:因为自定义结构体存在内存对齐,所以实际占用的内存量是对齐后的结果12。明显不是成员的总和,总和的话是简单的相加4+1+4=9。
计算数组大小
由于数组名的特殊性,sizeof计算数组大小的时候,要特别区分计算的是整个数组的大小,还是一个数组数据类型的大小。
只有数组名arr单独放在sizeof内部,即sizeof(arr)的时候,计算的才是整个数组的大小。
sizeof的计算大致有三种情况:
(1)计算变量大小
(2)计算数据类型的大小
在变量上使用 <==> 等同于在变量的数据类型上使用
(3)计算数组的大小
二、strlen库函数
strlen 求字符串长度 -- 单位是字节 (如果不是字符串,可能会出现错误)
注意事项:
① strlen函数内部实现:计算从字符串起始地址开始,到末尾的结束标志'\0'结束。 也就是说,strlen的计算依赖于末尾的结束标志'\0'。
② 库函数使用时,记得引头文件
代码示例:
三、sizeof与strlen的比较
两者的比较基于:字符数组和字符串数组
字符数组末尾不自带结束标志'\0',字符串数组末尾自带结束标志。
解释:
sizeof计算内存量。计算数组时,如果数组名单独放在其中,计算整个数组大小
sizeof(arr1)=3:因为arr1中只有三个字符,占三个字节大小;
sizeof(arr2)=4:因为arr2中,由于字符末尾自动带’0‘。'\0'也算一个字符,占用一个字节空间。所以sizef (arr2)=3+1=4。
strlen计算依赖结束标志'\0'
strlen(arr1)=随机值19:arr1中末尾没有结束标志,此时程序一直往后读,直到找到0。什么时候找到0是不确定的,所以是随机值19;
strlen(arr2)=字符串长度3:arr2中,有结束标志0。但值得注意的是,strlen并不会将结束标志计入长度。
四、练习总结
1. 整型数组中sizeof的案例
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
return 0;
}
详解 :
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a)); //4*4=16,a单独放在sizeof内部,计算整个数组的大小
printf("%d\n", sizeof(a + 0)); //4/8,a没有单独放在sizeof内部,就是它原本的意思--数组首元素地址
printf("%d\n", sizeof(*a)); //4,解引用首元素地址--首元素的值。值是int型,占用内存4个字节
printf("%d\n", sizeof(a + 1)); //4/8,数组第二个元素的地址。只要是地址,占用内存大小就是4或者8
printf("%d\n", sizeof(a[1])); //4,数组第二个元素的值,int类型,4个字节
printf("%d\n", sizeof(&a)); //4/8,整个数组的地址,是地址,占用内存都是4或8
printf("%d\n", sizeof(*&a)); //4*4=16,相当于a,a单独放在sizeof内部,求的是整个数组的大小
printf("%d\n", sizeof(&a + 1)); //4/8,跳过整个数组后,接着的那个地址
printf("%d\n", sizeof(&a[0])); //4/8,数组首元素的地址
printf("%d\n", sizeof(&a[0] + 1));//4/8,数组第二个元素的地址
return 0;
}
2. 字符数组中的sizeof计算
#include<stdio.h>
int main()
{
char arr[] = { 'a ', 'b', 'c', 'd', 'e', 'f' };
printf("%d \n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d \n", sizeof(&arr[0] + 1));
return 0;
}
详解:
#include<stdio.h>
int main()
{
char arr[] = { 'a ', 'b', 'c', 'd', 'e', 'f' };
printf("%d \n", sizeof(arr)); //6,arr单独放在sizeof内部,求整个数组的大小
printf("%d\n", sizeof(arr + 0)); //4/8,arr不单独,表首元素地址
printf("%d\n", sizeof(*arr)); //1,*(数组首元素地址)->数组首元素的值
printf("%d\n", sizeof(arr[1])); //1,数组第二个元素的值
printf("%d\n", sizeof(&arr)); //4/8,&arr整个数组的地址,但在数值上等于arr
printf("%d\n", sizeof(&arr + 1)); //4/8,跳过一整个数组后接着的地址
printf("%d \n", sizeof(&arr[0] + 1));//4/8,数组第二个元素的地址
return 0;
}
3. 字符数组中的strlen计算
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = { 'a ', 'b', 'c', 'd', 'e', 'f' };
printf("%d\n", str1en(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", str1en(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", str1en(&arr));
printf("%d\n", str1en(&arr + 1));
printf("%d\n", str1en(&arr[0] + 1));
return 0;
}
详解:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = { 'a ', 'b', 'c', 'd', 'e', 'f' };
printf("%d\n", str1en(arr)); //随机值,有起始地址arr,但无结束标志'\0'
printf("%d\n", strlen(arr + 0)); //随机值,arr==arr+0
printf("%d\n", str1en(*arr)); //error,无起始地址,*arr表示首元素字符'a',其ASCII码是97
//strlen会将97当作地址来处理,此时会造成越界访问,运行时会报错
printf("%d\n", strlen(arr[1])); //error,arr[1]==*(arr+1),原理同上
printf("%d\n", str1en(&arr)); //随机值,&arr--数组地址。有起始地址,无结束标志
printf("%d\n", str1en(&arr + 1)); //随机值,跳过一个数组后的地址。有起始地址,无结束标志
printf("%d\n", str1en(&arr[0] + 1));//随机值,数组第二个元素的地址。有起始地址,无结束标志
return 0;
}
4. 字符串数组中的sizeof计算
#include<stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d \n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
return 0;
}
详解;
#include<stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); //7,arr单独放,求整个数组的大小。字符串末尾自带'\0',也算一个字节。
printf("%d\n", sizeof(arr + 0)); //4/8,arr没单独放,表数组首元素地址
printf("%d\n", sizeof(*arr)); //1,数组首元素的值'a'
printf("%d\n", sizeof(arr[1])); //1,数组第二个元素的值'b'
printf("%d \n", sizeof(&arr)); //4/8,数组地址
printf("%d\n", sizeof(&arr + 1)); //4/8,跳过一个数组地址后的地址
printf("%d\n", sizeof(&arr[0] + 1));//4/8,数组第二个元素的地址
return 0;
}
5. 字符串数组中的strlen计算
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", str1en(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}
详解:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef"; //字符串末尾自带结束标志'\0'
printf("%d\n", strlen(arr)); //6,arr数组首元素地址。有起始地址,有结束标志
printf("%d\n", strlen(arr + 0)); //6,arr==arr+0
printf("%d\n", strlen(*arr)); //error,数组首元素的值,无起始地址
printf("%d\n", str1en(arr[1])); //error,数组第二个元素的值,无起始地址
printf("%d\n", strlen(&arr)); //6,&arr--数组地址。数值上等同于arr,有起始地址
printf("%d\n", strlen(&arr + 1)); //随机值,跳过整个数组后的地址
printf("%d\n", strlen(&arr[0] + 1));//5,数组第二个元素的地址,有起始地址
return 0;
}
6. 字符串指针中的sizeof计算
#include<stdio.h>
int main()
{
char* p = "abcdef";
printf("%d \n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
return 0;
}
详解:
#include<stdio.h>
int main()
{
char* p = "abcdef";
printf("%d\n", sizeof(p)); //4/8,是一个指针,指向'a'的地址。指针的大小是4或者8
printf("%d\n", sizeof(p + 1)); //4/8,指针+1,往后走一个char字节。还是指针,指向'b'的地址
printf("%d\n", sizeof(*p)); //1,表示'a'
printf("%d\n", sizeof(p[0])); //1,表示字符'b'
printf("%d\n", sizeof(&p)); //4/8,&p表示存放指针p的地址,存放地址的又是个指针
printf("%d\n", sizeof(&p + 1)); //4/8,&p+1表示取出p后面的地址,同样是个指针
printf("%d\n", sizeof(&p[0] + 1));//4/8,指针指向'b'的地址
return 0;
}
由于数组名的特性,起始这里的p等同于arr
#include<stdio.h>
int main()
{
char arr[3] = "abc";
int* p = arr;
return 0;
}
sizeof与strlen总结:
sizeof
sizeof的定义:计算一个变量类型的所占内存大小
注意:sizeof返回该类型使用的内存量,但值得指出的是,这不必等于其成员的总和
举例:sizeof(&arr)中,&arr整个数组地址,计算的并不是数组每个元素所占内存的总和,而是&arr指针类型所占的内存量
sizeof的使用:
首先关注数组名是否单独 -> 不是单独,关注是否特殊有无& -> 其他判断是地址还是量(变量or变量的赋值)
关于字符串数组
如果求的是字符数组,和整型数组无区别;求字符串数组,注意末尾的0也算一个字节strlen
strlen的定义:计算字符串的长度
strlen的使用:
需要开始信号--地址,结束标志--'\0'。开始信号为非地址报错,无结束标志结果为随机值
关于字符数组
(本来strlen的功能只能求字符串,你非要求字符数组)
开始信号如果不是地址,即便开始也会报错。结束地址没有0,所求值就是随机值。