不同的数组传参在sizeof与strlen中的不同含义

目录

数组传参的基本了解

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,&数组名,这里的数组名表示整个数组,取出来的是整个数组的地址

除此之外,所有的数组名都是数组首元素的地址

sizeof与strlen的基本了解

strlen和sizeof是C语言中两个常用的字符串操作函数

 sizeof操作符:

用于计算数据类型或变量占用的字节数,可以用于计算数组的大小

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个字节)

 strlen函数:

用于计算字符串长度,函数原型为

size_t strlen(const char *str);

 参数str是一个指向需要计算长度的字符串的指针

函数返回类型为size_t,即无符号整数,例如

char str[] = "Hello, world!";
size_t len = strlen(str); //计算str的长度,结果为13

注意: 

sizeof返回的结果单位为字节,不是字符串或数组元素的个数。

同时,sizeof操作符可以用于任何数据类型的计算,而strlen函数只能用于计算以'\0'结尾的字符串长度

sizeof与int类型数组

我们来看个代码,来解析以下这些代码的输出结果分别是什么,以及怎么得到的

代码:

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与strlen中的不同含义_第1张图片

代码解析: 

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

sizeof与字符数组

代码1,char arr[]={0}: 

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与strlen中的不同含义_第2张图片

代码解析: 

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个字节 

代码2,char arr[] = " ": 

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与strlen中的不同含义_第3张图片

代码解析: 

 sizeof(arr)

数组名单独放在sizeof内部,计算整个数组的大小

char arr[] = "abcdef";//a b c d e f \0

其数组后面隐含一个'\0',所以是7个字节

最主要的就是这个区别,其他与代码1的内容一致, 需要注意的就是字符串后面隐藏的有'\0'

strlen与字符数组 

strlen求字符串长度
//统计的是在字符串中\0之前出现的字符个数 

代码1,char arr[]={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;
}

只出现两个结果,而且输出的似乎也不对,

两个结果是因为第三个的代码传的是错误的,具体看下面代码解析 

不同的数组传参在sizeof与strlen中的不同含义_第4张图片

代码解析: 

 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',所以是随机值

代码2,char arr[] = " ":   

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;
}

 不同的数组传参在sizeof与strlen中的不同含义_第5张图片

代码解析: 

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

sizeof与字符串指针

代码: 

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与strlen中的不同含义_第6张图片 代码解析:

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个字节

strlen与字符串指针 

代码:

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;
}

 不同的数组传参在sizeof与strlen中的不同含义_第7张图片

代码解析: 

 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

 sizeof与二维数组

代码:

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与strlen中的不同含义_第8张图片

代码解析: 

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个字节

表达式的两个属性:值属性  类属性 

你可能感兴趣的:(算法,c语言,开发语言)