目录
数组传参的基本了解
sizeof与strlen的基本了解
sizeof操作符:
strlen函数:
注意:
sizeof与int类型数组
代码:
代码解析:
sizeof与字符数组
代码1,char arr[]={0}:
代码解析:
代码2,char arr[] = " ":
代码解析:
strlen与字符数组
代码1,char arr[]={0}:
代码解析:
代码2,char arr[] = " ":
代码解析:
sizeof与字符串指针
代码:
编辑 代码解析:
strlen与字符串指针
代码:
代码解析:
sizeof与二维数组
代码:
代码解析:
数组名是地址,通常来说,数组名是数组首元素的地址
但是有两个例外
1,sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
2,&数组名,这里的数组名表示整个数组,取出来的是整个数组的地址
除此之外,所有的数组名都是数组首元素的地址
strlen和sizeof是C语言中两个常用的字符串操作函数
用于计算数据类型或变量占用的字节数,可以用于计算数组的大小
char str[] = "Hello, world!";
size_t strSize = sizeof(str); //计算str数组占用的总字节数,结果为14(包括字符串末尾的'\0')
int arr[] = {1, 2, 3, 4};
size_t arrSize = sizeof(arr); //计算arr数组占用的总字节数,结果为16(4个int类型,每个占4个字节)
用于计算字符串长度,函数原型为
size_t strlen(const char *str);
参数str是一个指向需要计算长度的字符串的指针
函数返回类型为size_t,即无符号整数,例如
char str[] = "Hello, world!";
size_t len = strlen(str); //计算str的长度,结果为13
sizeof返回的结果单位为字节,不是字符串或数组元素的个数。
同时,sizeof操作符可以用于任何数据类型的计算,而strlen函数只能用于计算以'\0'结尾的字符串长度
我们来看个代码,来解析以下这些代码的输出结果分别是什么,以及怎么得到的
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;
}
sizeof(a)
单独放的数组名,所以计算的是整个数组的大小
sizeof(a + 0)
并非单独放在sizeof内部,也没有&
所以表示数组首元素地址,a+0依旧是首元素地址,计算地址的大小 是地址就是4/8个字节
x64环境下8字节,x86环境下4字节,博主环境为x86
sizeof(*a)
a并未单独放在sizeof内部,也没有&,所以是数组首元素地址
*a就是首元素,int类型大小4Byte, *a == *(a+0)
sizeof(a + 1)
a并未单独放在sizeof内部,也没有&,所以是数组首元素地址
a + 1就是第二个元素的地址 a+1== &a[1],是地址就是4/8个字节
sizeof(a[1])
a[1]就是数组的第二个元素,这里计算的就是第二个元素的大小
sizeof(&a)
&a是取出数组的地址,数组的地址也是地址,是地址就是4/8个Byte
数组的地址和数组首元素的地址的本质的区别是类型的区别,并非大小的区别
a -- int* int* p = a;
&a -- int(*)[4] int (*p)[4] = &a;
sizeof(*&a)
对数组指针解引用访问一个数组的大小,计算的是整个数组的大小
sizeof(*&a) == sizeof(a)
sizeof(&a + 1)
&a数组的地址,&a+1还是地址 ,是地址就是4/8个Byte
sizeof(&a[0])
&a[0]是首元素的地址,计算的是地址的大小 ,是地址就是4/8个Byte
sizeof(&a[0] + 1)
&a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,是地址就是 4/8个Byte
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;
}
sizeof(arr)
数组名单独放在sizeof内部,计算的是整个字符数组的大小,一个字符占一个字节
sizeof(arr + 0)
数组名并非单独放在sizeof内部,表示的是首元素的地址
arr+0表示的依旧是首元素的地址,是地址就是4/8个字节
sizeof(*arr)
并非单独放在sizeof内部,表示的是首元素的地址
*arr表示的就是首元素,一个字符占1个字节
sizeof(arr[1])
并非单独放在sizeof内部,arr[1]表示第二个元素,一个字符占一个字节
sizeof(&arr)
&arr,取得是整个字符数组的地址,是地址就是4/8个字节
sizeof(&arr + 1)
并非单独放在sizeof内部,取得是首元素的地址
+1就是第二个元素的地址,是地址就是4/8个字节
sizeof(&arr[0] + 1)
arr[0]代表第一个元素,&arr[0]就是首元素地址,
+1就是第二个元素地址,是地址就是4/8个字节
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;
}
sizeof(arr)
数组名单独放在sizeof内部,计算整个数组的大小
char arr[] = "abcdef";//a b c d e f \0
其数组后面隐含一个'\0',所以是7个字节
最主要的就是这个区别,其他与代码1的内容一致, 需要注意的就是字符串后面隐藏的有'\0'
strlen求字符串长度
//统计的是在字符串中\0之前出现的字符个数
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}
只出现两个结果,而且输出的似乎也不对,
两个结果是因为第三个的代码传的是错误的,具体看下面代码解析
strlen(arr)
arr是首元素的地址,之所以输出是19,是因为
char arr[] = { 'a','b','c','d','e','f' }后没有'\0'结尾
我们在上面讲到strlen函数只能用于计算以'\0'结尾的字符串长度
不知道后面什么时候才会遇到'\0',所以是一个随机值
strlen(arr + 0)
arr是首元素的地址,arr+0还是首元素地址
遇到'\0'才会停止,所以是个随机值
strlen(*arr)
arr是首元素地址,*arr就是首元素 'a' -->97
站在strlen的角度,认为传参进来的'a' -->97就是地址
97作为地址直接进行访问,就是非法访问
strlen(arr[1])
arr[1]是字符数组第二个元素,也就是'b'
'b'-98,非法访问
strlen(&arr))
&arr
作为参数,将整个字符串数组的地址传递给了strlen()
函数,计算出字符串数组的长度,所以还是随机值
strlen(&arr + 1)
取得整个字符串数组的地址,+1就是跳过了整个字符串
指向arr数组后面的未知内存区域,它不是一个有效的字符串地址,因此strlen函数会出现未定义的行为,结果是无法预测的,所以也是随机值
strlen(&arr[0] + 1)
&arr[0]表示数组的首地址,+1表示从第二个元素的地址开始计算
没有'\0',所以是随机值
int main()
{
char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}
strlen(arr)
arr代表首元素地址,从首元素开始计算,一直到结尾的'\0'结束
该字符串中,隐藏的有'\0',所以答案为6
strlen(arr + 0)
arr是首元素的地址,arr+0还是首元素地址
从首元素开始计算,一直到结尾的'\0'结束,答案6
strlen(*arr)
arr是首元素地址,*arr就是首元素 'a' -->97
站在strlen的角度,认为传参进来的'a' -->97就是地址
97作为地址直接进行访问,就是非法访问
strlen(arr[1])
arr[1]是字符数组第二个元素,也就是'b'
'b'-98,非法访问
strlen(&arr)
&arr
作为参数,将整个字符串数组的地址传递给了strlen()
函数,计算出字符串数组的长度,所以答案6
strlen(&arr + 1)
取得整个字符串数组的地址,+1就是跳过了整个字符串
指向arr数组后面的未知内存区域,它不是一个有效的字符串地址,因此strlen函数会出现未定义的行为,结果是无法预测的,所以是随机值
strlen(&arr[0] + 1)
&arr[0]表示数组的首地址,+1表示从第二个元素的地址开始计算
一直到结尾的'\0'结束,答案为5
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;
}
sizeof(p)
p指向的是一个字符串常量"abcdef" ,计算的是指针变量p的大小。
指针相当于地址
指针p的大小在32位系统中是4字节,在64位系统中是8字节
sizeof(p + 1)
p是一个字符数组
"abcdef"
的首元素地址,加 1 后指向数组的第二个元素,即字符
'b'
的地址但依旧是地址,是地址就是4/8个字节
sizeof(*p)
p是一个字符数组
"abcdef"
的首元素地址,*p就是指向的就是首元素'a'一个字符占一个字节
sizeof(p[0])
p指向的是一个字符串常量"abcdef"
p[0]被访问时,它指向字符串的第一个字符'a',等价于*(p+0)
sizeof(&p)
p存的是 "abcdef" 的首元素的地址,&p取得是p的地址
依旧是地址,是地址就是4/8个字节
sizeof(&p + 1)
&p+1 指向的是指针 p 所在的内存地址再向后移动一个指针所占的字节,
也就是指向p后面的地址,&p+1 的值是不确定的
但依旧是地址,是地址就是4/8个字节
sizeof(&p[0] + 1)
&p[0]+1 指向的是字符串 "abcdef" 的第二个字符 'b' 的内存地址。
因为&p[0]表示的是字符数组的第一个元素的内存地址
再加1就相当于指向字符数组的第二个元素的内存地址
但依旧是地址,是地址就是4/8个字节
int main()
{
char* p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
return 0;
}
strlen(p)
p指向的是一个字符串常量"abcdef" ,p存放的是首元素的地址
后面隐藏'\0',所以答案为6
strlen(p + 1)
p存放的是首元素的地址,加1就是指向第二个元素也就是‘b’的地址
答案为5
strlen(*p)
*p指向a,调用
strlen()
函数时,应该传入一个char*
类型的指针这里传的是一个字符,所以编译错误
strlen(p[0])
p[0]被访问时,它指向字符串的第一个字符'a',等价于*(p+0)
传参错误
strlen(&p)
&p给strlen函数,实际上传递的是p的地址
从p的地址往后找,知道遇到'\0'结束,所以是随机值
strlen(&p + 1)
取得是p的地址,加1是p后面的地址从p后面的地址往后找,知道遇到'\0'结束,是随机值
strlen(&p[0] + 1)
&p[0]+1 指向的是字符串 "abcdef" 的第二个字符 'b' 的内存地址。
因为&p[0]表示的是字符数组的第一个元素的内存地址
再加1就相当于指向字符数组的第二个元素的内存地址
答案为5
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0][0]));
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[0] + 1));
printf("%d\n", sizeof(*(a[0] + 1)));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(*(a + 1)));
printf("%d\n", sizeof(&a[0] + 1));
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a[3]));
return 0;
}
sizeof(a)
单独放数组名,计算整个数组大小
sizeof(a[0][0])
计算第一个元素的大小
sizeof(a[0])
二维数组其实是数组的数组,是一维数组的数组
a[0]是第一行这个一维数组的数组名,数组名单独放sizeof内部
计算的是整个第一行这个一维数组的大小
sizeof(a[0] + 1)
a[0]并非单独放在sizeof内部,也没有&
所以表示第一行这个一维数组首元素的地址,也就是第一行第一个元素地址
a[0]< -- >&a[0][0] a[0]+1 -- > &a[0][1]
sizeof(*(a[0] + 1))
a[0]+1 是第一行第二个元素的地址,*(a[0]+1)第一行第二个元素
sizeof(a + 1)
a作为二维数组的数组名,并非单独放在sizeof内部,也没有&
a表示的就是数组首元素的地址,也就是第一行的地址
a+1就是第二行的地址,是地址就是-- 4/8个字节
sizeof(*(a + 1))
a+1是第二行的地址,*(a+1)就是第二行,计算的是第二行的大小--16个字节
另一个角度 -- *(a+1) --》a[1],
a[1]是第二行这个一维数组的数组名,数组名单独放sizeof内部
sizeof(&a[0] + 1)
a[0]是第一行的地址,&a[0]取出的是第一行的地址,类型就是int(*)[4]
&a[0]+1就是第二行的地址,是地址就是--4/8个字节
sizeof(*(&a[0] + 1))
a[0]是第一行的地址,&a[0]取出的是第一行的地址,类型就是int(*)[4]
&a[0]+1就是第二行的地址解引用后,得到的就是第二行 -- 16个字节
sizeof(*a)
a表示数组首元素的地址,也就是第一行的地址
*a就是对第一行的地址解引用,相当于第一行的数组名 -- 16个字节
sizeof(a[3])
不会越界,sizeof是根据类型计算,并不会去真正的访问--16个字节
表达式的两个属性:值属性 类属性