C语言中关于 strlen 和 sizeof 的用法及区别(含例题及解析)

一、前言

首先我们需要知道的是,sizeof既是一个单目操作符,也是一个关键字,其作用是求操作数的类型长度(以字节为单位)。

 

而strlen是一个字符串操作函数,是一个参数为指针类型返回值为size_t(unsigned int)的函数,求的是字符串的长度。

所以现在我们知道sizeof是一个求操作数类型长度的操作符(关键字),而strlen是一个求字符串长度的字符串操作函数 。

 

二、sizeof和strlen的用法

2.1  sizeof操作符在简单变量中的用法

int a = 10;
char c = 'c';

printf("%d\n",sizeof(a));   //答案是4(操作数a的类型为整型,32位机器中占4个字节,64位机器中占8个字节)
printf("%d\n",sizeof(int)); //答案是4
printf("%d\n",sizeof a);  //答案是4(求变量的大小时可以去掉括号)
printf("%d\n",sizeof int);  //错误(求类型的大小时不能去掉括号)

printf("%d\n",sizeof(c));  //答案是1(操作数c的类型为字符型,占1个字节)
printf("%d\n",sizeof(char));  //答案是1
printf("%d\n",sizeof c);   //答案是1(求变量的大小时可以去掉括号)
printf("%d\n",sizeof char);  //错误((求类型的大小时不能去掉括号))

2.2  strlen函数在字符指针变量中的简单用法

char *p = "abcdef";
printf("%d\n",strlen(p)); //答案是6

我们知道strlen()函数的参数是一个指针变量,存放的是一个地址。而strlen()函数就是从这个地址开始往后数,直到遇到字符串结束标志'\0' ,停止计数('\0'不纳入计数范围),并返回字符串的长度。

在上面例子中,p是一个指针变量,存放的是字符串首元素'a'的地址。所以将p作为参数传给strlen()函数后,该函数从a开始计数,直到遇到'f'后边的'\0',停止计数,此时字符串长度为6。

2.3sizeof和strlen在数组中的用法

注意:

1.数组名单独放在sizeof内部时,此时数组名表示整个数组,sizeof求的是整个数组的大小。

2.&数组名,此时数组名也表示整个数组,取出的是整个数组的地址。

3.除上述两种情况外,数组名均表示首元素的地址。

 一维整型数组中:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));  //16
printf("%d\n",sizeof(a+0));  //4
printf("%d\n",sizeof(*a));  //4
printf("%d\n",sizeof(a+1));  //4
printf("%d\n",sizeof(a[1]));  //4
printf("%d\n",sizeof(&a));  //4
printf("%d\n",sizeof(*&a));  //16
printf("%d\n",sizeof(&a+1));  //4
printf("%d\n",sizeof(&a[0]));  //4
printf("%d\n",sizeof(&a[0]+1));  //4

例1:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));  //16

解析:此时数组名a单独放在sizeof内部,表示整个数组,所以求的是整个数组的大小 = 4*4=16。


例2:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a+0)); //4

解析:此时数组名并未单独放在sizeof内部,也没有取地址,所以表示首元素地址,+0后仍表示首元素地址。我们知道只要是地址,在32位机器下便占4个字节,在64位机器下便占8个字节。


例3:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(*a));  //4

解析:此时数组名a表示首元素地址,解引用(*)后表示首元素1,而1是一个整型,32位机器下占4个字节。


例4:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a+1));  //4

解析:此时数组名表示首元素地址,首元素地址+1指向第2个元素,表第二个元素的地址。


例5:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a[1]));  //4

解析:a[1]表示第二个元素2(整型)。


例6:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(&a));  //4

解析:&数组名取的是整个数组的地址(此时的数组名表示整个数组)。


例7:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(*&a));  //16

解析:因为&a中,a表示整个数组,所以*&a,解引用a后计算的是整个数组的大小。


例8:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(&a+1));  //4

解析:由于&a取出的是整个数组的地址,所以&a+1跳过的是整个数组,但仍表示一个地址。


例9:

int a[] = {1,2,3,4};
printf("%d\n", sizeof(&a[0]));   //4

解析:&a[0]取出的是首元素1的地址。


例10:

int a[] = {1,2,3,4};
printf("%d\n", sizeof(&a[0] + 1));   //4

解析:&a[0]取出的是首元素1的地址,加1后指向第二个元素2,表第二个元素的地址。

 

字符数组中:

sizeof的用法:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(c));  //6
printf("%d\n",sizeof(c+0));  //4
printf("%d\n",sizeof(*c));  //1
printf("%d\n",sizeof(c[1]));  //1
printf("%d\n",sizeof(&c));  //4
printf("%d\n",sizeof(&c+1));  //4
printf("%d\n",sizeof(&c[0]+1));  //4

例1:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(c));   //6

解析:此时数组名c单独放在sizeof内部,表整个数组,所以求的是整个数组的大小 。


例2:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(c+0));   //4

解析:此时数组名并未单独放在sizeof内部,也没有取地址,所以此时的数组名表示首元素'a'的地址,加0后仍表示首元素的地址。


例3:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(*c));   //1

解析:此时的数组名表示首元素的地址,解引用后表示首元素(字符型)。


例4:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(c[1]));   //1

解析:c[1]表示第二个元素'b'(字符型)。


例5:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(&c));   //4

解析:&数组名取出的是整个数组的地址。


例6:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(&c+1));   //4

解析:&数组名取出的是整个数组的地址,&数组名+1跳过整个数组。


例7:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(&c[0]+1));   //4

解析:&c[0]取的是首元素的地址,加1后表第二个元素的地址。

 

strlen()的用法:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(c));  //随机值
printf("%d\n",strlen(c+0));  //随机值
printf("%d\n",strlen(*c));  //错误
printf("%d\n",strlen(c[1]));  //错误
printf("%d\n",strlen(&c));  //随机值
printf("%d\n",strlen(&c+1));  //随机值
printf("%d\n",strlen(&c[0]+1));  //随机值

例1:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(c));   //随机值

解析:由于strlen()函数求的是字符串长度,而字符串又是以'\0'作为字符串结束标志 。此时的数组中并无'\0'元素,所以当strlen()函数从'a'开始往后数,遇到'\0'停下来的时候我们并不知道确切的字符串长度。


例2:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(c+0));   //随机值

解析:给首元素地址加0后仍从首元素开始往后数,此时仍不知道何时会遇到'\0'并停止计数。


例3:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(*c));   //错误

解析:在文章最开始时我们就已经知道strlen()函数需要的参数是一个指针类型,而*c表示的是首元素,并不是一个地址,强行调用会引发程序中断。


例4:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(c[1]));   //错误

解析:此时c[1]也不是指针类型,而是字符型。


例5:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(&c));   //随机值

解析:当取得了整个数组的地址后,strlen()函数从该地址开始往后数,由于不知道什么时候会遇到'\0',所以此字符串长度仍为随机值。


例6:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(&c+1));   //随机值

解析:给整个数组的地址加1跳过的是整个数组,即从元素'f'后边开始计数,且字符串长度仍为随机值。但我们可以确定的是strlen(&c) 和 strlen(&c+1)相差的是整个数组的大小6。


例7:

char c[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(&c[0]+1));   //随机值

解析:首元素地址加1表第二个元素的地址,此时函数从'b'处往后数,直到遇到'\0'停止计数。

 

sizeof的用法

char c[] = "abcdef";
printf("%d\n",sizeof(c));  //7
printf("%d\n",sizeof(c+0));  //4
printf("%d\n",sizeof(*c));  //1
printf("%d\n",sizeof(c[1]));  //1
printf("%d\n",sizeof(&c));  //4
printf("%d\n",sizeof(&c+1));  //4
printf("%d\n",sizeof(&c[0]+1));  //4

例1:

char c[] = "abcdef";
printf("%d\n",sizeof(c));  //7

解析:通过调试并监视c,我们发现此时由于数组是一个字符串,所以会将'\0'存入该数组中,计算字符串长度时,由于'\0'也是数组的一个元素,所以最后字符串长度为7而不是6。 


例2:

char c[] = "abcdef";
printf("%d\n",sizeof(c+0));  //4

解析:首元素地址加0仍表示首元素地址。


例3:

char c[] = "abcdef";
printf("%d\n",sizeof(*c));  //1

解析:此时数组名表示首元素地址,解引用后表示首元素(字符型)。


例4:

char c[] = "abcdef";
printf("%d\n",sizeof(c[1]));  //1

解析:c[1]表示第二个元素(字符型)。


例5:

char c[] = "abcdef";
printf("%d\n",sizeof(&c));  //4

解析:&数组名取的是整个数组的地址。


例6:

char c[] = "abcdef";
printf("%d\n",sizeof(&c+1));  //4

解析:&数组名+1跳过整个数组。


例7:

char c[] = "abcdef";
printf("%d\n",sizeof(&c[0]+1));  //4

解析:首元素地址加1指向第二个元素,表第二个元素的地址。

 

strlen的用法:

char c[] = "abcdef";
printf("%d\n",strlen(c));  //6
printf("%d\n",strlen(c+0));  //6
printf("%d\n",strlen(*c));  //错误
printf("%d\n",strlen(c[1]));  //错误
printf("%d\n",strlen(&c));  //6
printf("%d\n",strlen(&c+1));  //随机值
printf("%d\n",strlen(&c[0]+1));  //5

例1:

char c[] = "abcdef";
printf("%d\n",strlen(c));  //6

解析:此时c在内存中的存储形式如下。由于字符串计算长度时不将'\0'计算在内,所以此字符串长度为6。 


例2:

char c[] = "abcdef";
printf("%d\n",strlen(c+0));  //6

解析:首元素地址加0仍从首元素开始往后数,不将'\0'纳入长度计算范围内。


例3:

char c[] = "abcdef";
printf("%d\n",strlen(*c));  //错误

 解析:所传参数*c是字符型而不是指针类型。


例4:

char c[] = "abcdef";
printf("%d\n",strlen(c[1]));  //错误

解析:所传参数c[1]是字符型而不是指针类型。


例5:

char c[] = "abcdef";
printf("%d\n",strlen(&c));  //6

解析:&数组名取的是整个数组的地址,该地址在数值上跟首元素地址一样,所以也从字符串首元素开始往后数。


例6:

char c[] = "abcdef";
printf("%d\n",strlen(&c+1));  //随机数

解析:&数组名加1后跳过整个数组,从该数组的'\0'后面开始往后数。


例7:

char c[] = "abcdef";
printf("%d\n",strlen(&c[0]+1));  //5

解析:&c[0]加1表示从第二个元素开始往后数。

 

sizeof的用法:

char *p = "abcdef";
printf("%d\n",sizeof(p));  //4
printf("%d\n",sizeof(p+1));  //4
printf("%d\n",sizeof(*p));  //1
printf("%d\n",sizeof(p[0]));  //1
printf("%d\n",sizeof(&p));  //4
printf("%d\n",sizeof(&p+1));  //4
printf("%d\n",sizeof(&p[0]+1));  //4

例1:

char *p = "abcdef";
printf("%d\n",sizeof(p));  //4

解析:此时p指向字符串所在空间,所以p是一个指针变量,存的是该字符串首元素的地址。 


例2:

char *p = "abcdef";
printf("%d\n",sizeof(p+1));  //4

 解析:给p加1后,指向第二个元素,表第二个元素的地址。


例3:

char *p = "abcdef";
printf("%d\n",sizeof(*p));  //1

解析:因为p指向首元素,所以解引用后*p='a'(字符型)。


例4:

char *p = "abcdef";
printf("%d\n",sizeof(p[0]));  //1

解析:p[0]表首元素(字符型)。


例5:

char *p = "abcdef";
printf("%d\n",sizeof(&p));  //4

解析:&p表示将存有字符串首元素地址的变量p的地址取出来,此时的指针变量char **pp = &p(第二颗*表示pp是一个指针变量,char *表示pp变量所存地址的类型)。


例6:

char *p = "abcdef";
printf("%d\n",sizeof(&p+1));  //4

解析:char **pp = &p    ,所以&p+1相当于跳过一个char *型的字节,即4个字节。


例7:

char *p = "abcdef";
printf("%d\n",sizeof(&p[0]+1));  //4

解析:&p[0]取出的是首元素的地址,加1表示第二个元素的地址。

 

strlen的用法:

char *p = "abcdef";
printf("%d\n",strlen(p));  //6
printf("%d\n",strlen(p+1));  //5
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));  //5

例1:

char *p = "abcdef";
printf("%d\n",strlen(p));  //6

解析:从首元素'a'开始往后数,遇到'f'后面的'\0'停止计数。


例2:

char *p = "abcdef";
printf("%d\n",strlen(p+1));  //5

解析:从第二个元素开始往后数。


例3:

char *p = "abcdef";
printf("%d\n",strlen(*p));  //错误

解析:strlen()函数要求所传参数必须为指针类型。


例4:

char *p = "abcdef";
printf("%d\n",strlen(p[0]));  //错误

解析:strlen()函数要求所传参数必须为指针类型。


例5:

char *p = "abcdef";
printf("%d\n",strlen(&p));  //随机数

解析:由于p是一个指针变量,从该变量的地址开始往后数计算字符串长度。


例6:

char *p = "abcdef";
printf("%d\n",strlen(&p+1));  //随机值

解析:char **pp = &p    ,所以&p+1相当于跳过一个char *型的字节之后开始计数字符串的长度。


例7:

char *p = "abcdef";
printf("%d\n",strlen(&p[0]+1));  //5

解析:&p[0]+1后指向第二个元素,所以从'b'开始往后计数字符串的长度。

 

二维数组:

我们知道二维数组在内存中是以一维数组形式存储的。

以int a[3][4]为例,存储形式如下:

那么我们可以将a[0]当成 第一行元素的数组名,a[1]作为第二行元素的数组名,同理,a[2]就是第三行元素的数组名。

int a[3][4] = {0};
printf("%d\n",sizeof(a));  //48
printf("%d\n",sizeof(a[0][0]));  //4
printf("%d\n",sizeof(a[0]));  //16
printf("%d\n",sizeof(a[0]+1));  //4
printf("%d\n",sizeof(a+1));  //4
printf("%d\n",sizeof(&a[0]+1));  //4
printf("%d\n",sizeof(*a));  //16
printf("%d\n",sizeof(a[3]));  //16

例1:

int a[3][4] = {0};
printf("%d\n",sizeof(a));   //48

解析:此时数组名单独放在sizeof内部表示整个数组,所以求的是整个数组的大小。


例2:

int a[3][4] = {0};
printf("%d\n",sizeof(a[0][0]));   //4

解析:a[0][0]表示数组首元素。


例3:

int a[3][4] = {0};
printf("%d\n",sizeof(a[0]));   //16

解析:由于a[0]是二维数组第一行的数组名且单独放在sizeof内部,所以此时求的是二维数组第一行的大小。


例4:

int a[3][4] = {0};
printf("%d\n",sizeof(a[0]+1));   //4

解析:由于此时a[0]没有单独放在sizeof内部且没有取地址,所以表示的是第一行首元素即a[0][0]的地址,加1表示a[0][1]的地址。


例5:

int a[3][4] = {0};
printf("%d\n",sizeof(a+1));   //4

解析:此时a并没有单独放在sizeof内部且没有取地址,所以表示的是首元素第一行a[0]的地址,加1表示第二行a[1]的地址。


例6:

int a[3][4] = {0};
printf("%d\n",sizeof(&a[0]+1));   //4

解析:因为&数组名取的是整个数组的地址,所以&a[0]取的是数组第一行的地址,加1将跳过这个数组,即表示数组第二行的地址。


例7:

int a[3][4] = {0};
printf("%d\n",sizeof(*a));   //16

解析:此时a并没有单独放在sizeof内部且没有取地址,所以表示的是首元素第一行a[0]的地址,解引用表示第一行。


例8:

int a[3][4] = {0};
printf("%d\n",sizeof(a[3]));   //16

解析:由于此二维数组并不含有a[3]元素,但sizeof操作符在求操作数的类型长度是在程序编译阶段就已经完成,而且其内部元素并不参与运算,所以a[3]就相当于a[0],a[1],a[2]。

 

总结:在二维数组中,对于数组名a来说,它的首元素就是a[0],即第一行,加1就是第二行;而对于第一行a[0]来说,它的首元素就是a[0][0],加1就是a[0][1]

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值