sizeof( )和strlen( )的用法和区别

1.sizeof( )的用法和说明:


sizeof()的定义:


在 C 语言中,sizeof() 是一个判断数据类型或者表达式长度的运算符。

其返回值类型为size_t,在头文件stddef.h中定义。这是一个依赖于编译系统的值,一般定义为 typedef unsigned int size_t;

在C99及以上标准中,sizeof(char)、sizeof(int)、sizeof(long)、sizeof(long long)、sizeof(float)、sizeof(double)、sizeof(long double)的值分别:1,4,4,8,4,8,16。

sizeof()的语法:


实际上,sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象其sizeof值都是一致的。这里,对象可以进一步延伸至表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。

sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用,我们来看一个完整的例子:

char foo()
{
printf("foo()hasbeencalled.\n");
return 'a';
}
int main()
{
size_tsz=sizeof(foo());
//foo()的返回值类型为char,所以sz=sizeof(char),foo()并不会被调用
printf("sizeof(foo())=%d\n",sz);
}

C99标准规定,函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算sizeof值,即下面这些写法都是错误的:

sizeof(foo);//error
void foo2(){}
sizeof(foo2());//error
struct S
{
unsigned int f1:1;
unsigned int f2:5;
unsigned int f3:12;
};
sizeof(S.f1);//error

sizeof()的常量性:


sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用,如:

char ary[sizeof(int)*10];//ok

最新的C99标准规定sizeof也可以在运行时刻进行计算,如:

int n=10;//n动态赋值
char ary[n];//C99也支持数组的动态定义
printf("%d\n",sizeof(ary));//ok.输出10

指针变量的sizeof


在32位计算机中,一个指针变量的返回值是4个字节,在64位系统中,指针变量的sizeof结果为8。

指针变量的sizeof值与指针所指的对象没有任何关系,正是由于所有的指针变量所占内存大小相等,所以MFC消息处理函数使用两个参数WPARAM、LPARAM就能传递各种复杂的消息结构(使用指向结构体的指针)。

数组的sizeof:


数组的sizeof值等于数组所占用的内存字节数,如:

char a1[] = "abc"; int a2[3]; 
sizeof( a1 ); // 结果为4,字符末尾还存在一个NULL终止符
sizeof( a2 ); // 结果为3*4=12(依赖于int)

假设有如下一段代码:

void foo3(char a3[3])
{
int c3=sizeof(a3);
}
void foo4(char a4[])
{
int c4=sizeof(a4);
}

写到这里,提一问,下面的c3,c4值应该是多少呢?

这里函数参数a3已不再是数组类型,而是蜕变成指针,相当于char* a3,为什么?仔细想想就不难明白,我们调用函数foo3时,程序会在栈上分配一个大小为3的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为4。

结构体的sizeof:


在结构体中运用sizeof,会出现结构体内存对齐问题。
字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:

1)结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

2)结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;

3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

还有一点要注意,“空结构体”(不含数据成员)的大小不为0,而是1。试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢?于是,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。如下:

struct S5 { }; sizeof( S5 ); // 结果为1含位域结构体的sizeof

前面已经说过,位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof,只是考虑到其特殊性而将其专门列了出来。

C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。使用位域的主要目的是压缩存储,其大致规则为:

1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;

4) 如果位域字段之间穿插着非位域字段,则不进行压缩;

5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

2.strlen()的用法和说明:


strlen()的定义:


strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符’\0’为止,然后返回计数器值(长度不包含’\0’)。

strlen()的函数原型:


原型为size_t strlen(const char *s);

其中size_t实际上是unsigned int,在VC6.0中可以看到这样的代码:typedef unsigned int size_t; 。

头文件:string.h

格式:strlen (字符数组名)

功能:计算给定字符串的(unsigned int型)长度,不包括’\0’在内

说明:返回s的长度,不包括结束符NULL。

3.sizeof( )和strlen( )的区别:


1)strlen(char*)函数求的是字符串的实际长度,它求得方法是从开始到遇到第一个’\0’,如果你只定义没有给它赋初值,这个结果是不定的,它会从首地址一直找下去,直到遇到’\0’停止。

2)sizeof()返回的是变量声明后所占的内存数,不是实际长度,此外sizeof不是函数,仅仅是一个取字节运算符,strlen是函数。

3)sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以”\0”结尾的。

4)sizeof还可以用函数做参数,比如:

short f();
printf("%d\n",sizeof(f()));

输出的结果是sizeof(short),即2。

5)数组做sizeof的参数不退化,传递给strlen就退化为指针了。

6)大部分编译程序在编译的时候就把sizeof计算过了是类型或是变量的长度。这就是sizeof(x)可以用来定义数组维数的原因

char str[20]="0123456789";
long a=strlen(str); //a=10;
int b=sizeof(str); //b=20;

7)strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小。

8)sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。

9)当适用于一个结构类型时或变量时, sizeof 返回实际的大小,当适用于一静态空间数组, sizeof 归还全部数组的尺寸。sizeof 操作符不能返回动态被分派了的数组或外部的数组的尺寸。

10)数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值