C++面试中关于sizeof问题总结

原文:http://blog.sina.com.cn/s/blog_7c983ca60100yfdv.html#SinaEditor_Temp_FontName

(1)      sizeof是操作符,不是函数。

MSDN:The sizeof keyword gives the amount of storage, in bytes, associate with a variable or a type(including aggregate types). This keyword returns a value of type size_t(typedef unsigned int size_t).

语法:sizeof(object);=> sizeof(1);   sizeof(typename);=>sizeof(int);  sizeof object;=>sizeof 1;(注意sizeof typename是错误的)

(2)      sizeof不能求得void类型的长度。

你不能用sizeof(void);这样将产生:error C2070: illegal sizeof operand

比如如下代码:

void fun(){

}

int main(){

cout<<sizeof(fun())<<endl;

return 0;

}//这个编译是不会通过的

char fun(){

return ‘a’;

}

int main()

{

cout<<sizeof(fun())<<endl;

return 0;

}//引申一下,这个是测量返回值的长度,因此是1,而不是指针的长度4.结合第八点来看。

(3)      sizeof能求得void类型的指针的长度。

目前基本上所有的编译器都把指针的大小看做是4byte。其实指针也是变量,只不过这个变量很特殊,它是存放其他变量的地址的变量。又由于目前32位计算机平台上的程序段的寻址范围是4GB,寻址的最小单元是Byte,4GB等于232byte。这么多得内存起地址如何编码,只需要用32个bit就行了,而32bit=32、8=4Byte,也就是说只要4Byte就能存储这些内存的地址了。因此对任何类型的指针变量进行sizeof运算其结果就是4.(一个疑问,指针类型用4Byte只存储了指针指向的地址,如何区分是何种类型的指针呢?

(4)      sizeof能求得静态分配的内存的数组的长度。

int a[10];sizeof(a); 这样可求得长度是10*4=40.(引申问题:数组名和指针的区别。参看下篇),另外注意char ch[]=”abc”; sizeof(ch);结果为4,注意字符串数组末尾有’\0’,通常我们可以利用sizeof来计算数组中包含的元素个数。其做法是:int n=sizeof(a)/sizeof(a[0]);

要注意对函数的形参数组使用sizeof的情况。如:

void fun(int arr[10]){

int n = sizeof(arr);

}//n的值为4

这里的原因是在函数参数传递时,数组被转化成指针了。加入直接传递整个数组的话,那么必然涉及到数组元素的拷贝(实参到形参的拷贝),当数组非常大时,这会导致执行效率极低!而只传递数组的地址(即指针)那么只需要拷贝4Byte。

引申:sizeofstrlen的区别:

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

char aa[10];strlen(aa);          //结果是不定的   sizeof(aa);      //结果是10

char aa[10]={‘\0’};strlen(aa);  //结果为0         sizeof(aa);      //结果是10

char aa[]=”LRP”;strlen(aa);     //结果为3             sizeof(aa);      //结果是4

char*aa=”0123456789”;   //字符串常量的情况

sizeof(aa);        //结果为4,指针的长度

sizeof(*aa);       //结果为1,第一个字符的空间

strlen(aa);         //结果为0,该字符串的长度

char aaa[]={"LRPLRP"};

int a,b;

fun(aaa,a,b);

void fun(char aaa[],int&a,int&b)

{

a=strlen(aaa);

b=sizeof(aaa);

}

//得到的a=6,b=4.在函数内部,虽然aaa转化成指针,但是strlen还是测试aaa开始直到’\0’为止的字符串的长度,而sizeof则是测指针的长度。

(5)      sizeof不能求得动态分配的内存的大小

例如int*a = new int[10]; int n = sizeof(a); 得到n的值是4。

(6)      sizeof不能对不完成的数组求长度

假设有两个源文件:file1.cpp和file2.cpp,其中file1.cpp定义:

int arrayA[10]={1,2,3,4,5,6,7,8,9,10};

int arrayB[10]={11,12,13,14,15,16,17,18,19,20};

file2.cpp中包含如下几个语句:extern arrayA[]; extern arrayB[10];

cout<<sizeof(arrayA)<<endl;   //编译出错

cout<<sizeof(arrayB)<<endl;

在file1.cpp中第三条语句编译出错,而第四条语句正确。原因:sizeof(arrayA)试图求不完整数组的大小。这里的不完整的数组是指数组大小没有确定的数组。sizeof运算符的功能是求某种对象的大小,然而声明:extern int arrayA[]只是告诉编译器arrayA是一个整型数组,但是并没有告诉编译器它包含多少个元素,因此对file2.cpp中得sizeof来说它无法求出arrayA的大小,所以编译器干脆不让你编译通过。arrayB明确告诉了arrayB是一个包含10个元素的整型数组,因此大小事确定的。

(7)       当表达式作为sizeof的操作数时,它返回表达式的计算类型大小,但是它不对表达式求值。(这点很重要)

char ch=1;

int num=1;

int n1=sizeof(ch+num);           //结果n1=4

int n2=sizeof(ch=ch+num);     //n2=1,ch=1

由于默认类型转换原因,ch+num的计算结果的类型是int,因此n1的值为4.而表达式ch=ch+num的结果的类型是char,记住虽然在计算ch+num时,结果为int,但是把结果赋值给ch时又进行了类型转换,因此表达式的最终类型还是char,因此n2等于1。

对于n2=sizeof(ch=ch+num); 乍一看改程序貌似实现了让ch加上num并赋值给ch的功能,事实并非如此,由于sizeof只关心类型大小,所以它自然不应该对表达式求值。但是,int len=3; cout<<sizeof(int[++len])<<”,”<<len;输出地答案却是16,4.(原文中作者说得时在Dev C++编译器下,但是经过在VC下测试,编译不通过。后来改成int num = 3;      int aaa[]={1,2,3,4,5,6}; cout<<sizeof(aaa[++num])<<","<<num<<endl;输出结果却是4,3.由此可见++num操作并未执行),因此尽量不要在sizeof中直接对表达式求大小,以免出现错误。

(8)      sizeof可以对函数调用求大小,并且求得的大小等于函数返回类型的大小,但是不执行函数体。

int fun(int &num)

{

int a,b;

a = 10;

b = 2;

num = a/b;

return num;

}

int main()

{

int num = 0;

cout<<sizeof(fun(num))<<endl;

cout<<num<<endl;

return 0;

}//输出结果4 0

sizeof(fun(num))得到的是函数返回类型的大小,而fun(num)的返回值类型是int,所以等价于sizeof(int)得到结果为4.另外不要认为这个长度为fun函数内部的局部变量所占空间的大小(认为结果为8,即a和b两个int的长度也是错误的)另外也注意,sizeof(fun(num))也不是求函数指针的大小,切记是求得返回值类型的长度大小

这里跟特征7很类似。sizeof的操作对象是函数调用时,它不执行函数体。为此,建议大家不要把函数体放在sizeof后面的括号里,这样让人误以为函数体执行了,其实它根本没执行。另外可知:不能对返回类型是void的函数使用sizeof求其大小,如2中讲得编译报错。

另外注意sizeof(fun)的大小是多少呢?其实得不到答案,原因是编译不通过。(很多人可能认为fun是函数名,而再把函数名等价于函数的地址,地址是指针),于是得到了其值是4.但是事实却不是这样,却是编译不通过。

(9)      sizeof求得结构体(及其对象)的大小并不等于各个数据成员对象的大小之和

结构体的大小跟结构体成员对其有密切关系,而并非简单地各个成员的大小之和。比如两个结构体AA和BB。,使用sizeof分别得出结果是24和16.可以看出sizeof(AA)并不等于sizeof(int)+sizeof(double)+sizeof(int)


struct AA{

int aa;

double bb;

int cc;

};


struct BB{

int aa;

int bb;

double cc;

};

结构体成员对齐的规则:(1)结构体大小等于结构体内最大成员大小的整数倍;(2)结构体内的成员的首地址相对于结构体首地址的偏移量是其类型大小的整数倍,比如说double型成员相对于结构体的首地址的偏移量应该是8的整数倍;(3)为了满足规则1和规则2编译器会再结构体成员之后进行字节填充。

在进行设计时,组号仔细安排结构体中各个成员的顺序。

(10)  sizeof不能用于求结构体的位域成员的大小,但是可以求得包含位域成员的结构体的大小。

位域:类型的大小都是以字节(byte)为基本单位的,比如sizeof(char)为1byte。但是bool类型取值只有true和false,按理只用1bit就够了,但事实上sizeof(bool)等于1.为了提供一种能对变量的存储空间进行精打细算的机制,这就是位域。简单来说在结构体成员变量后面跟上的一个冒号+一个整数,就代表位域,请仔细看以下结构体:

struct A{

bool b:1;

char ch1:4;

char ch2:4;

}item;

该结构体试图让bool类型的变量b只占用1个bit,让ch1和ch2分别只占用4个bit,以此来达到对内存精打细算的功能。语句sizeof(item.b)和sizeof(item.ch1)等对位域成员求大小的语句均不能通过编译。其原因:sizeof以byte为单位返回操作数的大小。

对包含位域的结构体可以使用sizeof求其大小,但其求值规则比较复杂,不涉及到成员对齐,还与集体编译环境有关。

延伸:class A{};sizeof(A)的结果为1,其原因:类的实例化是在类内存中分配一块地址,每个实例在内存中得都有独一无二的地址,同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以其长度为1。(编译器为了区分不同的类,在类中加了一个char类型,另外,如果一个文件中有256个空类,即大于char类型表示的范围,就不能区分空类了)

时间: 2024-10-24 16:20:03

C++面试中关于sizeof问题总结的相关文章

面试中有关C++的若干问题

面试中有关C++的若干问题 By 晴天, 2014.5.16晚 什么是多态?简要说一下C++中的多态的概念. (1)定义:多态是指相同对象收到不同消息或者不同对象收到相同消息产生不同的行为. (2)C++中多态分为两种 a) 编译时多态(静态绑定) 通过函数重载来实现 b) 运行时多态(动态绑定) 通过虚函数来实现 (3)它与这几关键词联系在一起 动态绑定 virtual关键字/虚函数 函数重载 虚函数表 只有基类用virtual修饰的函数才有可能实现多态.跟派生类用不用virtual修饰没有关

JAVA面试中问及HIBERNATE与 MYBATIS的对比,在这里做一下总结(转)

hibernate以及mybatis都有过学习,在java面试中也被提及问道过,在项目实践中也应用过,现在对hibernate和mybatis做一下对比,便于大家更好的理解和学习,使自己在做项目中更加得心应手. 第一方面:开发速度的对比 就开发速度而言,Hibernate的真正掌握要比Mybatis来得难些.Mybatis框架相对简单很容易上手,但也相对简陋些.个人觉得要用好Mybatis还是首先要先理解好Hibernate. 比起两者的开发速度,不仅仅要考虑到两者的特性及性能,更要根据项目需求

面试中注意3个javascript的问题

JavaScript 是所有现代浏览器的官方语言.因此,各种语言的开发者面试中都会遇到 JavaScript 问题. 本文不讲最新的 JavaScript 库,通用开发实践,或任何新的 ES6 函数.而是讲讲面试中经常出现的 3 个 JavaScript 问题.我问过这些问题,我的朋友说他们也问. 当然不是说你在准备 JavaScript 面试时只要学习这 3 个问题 -- 你还有很多途径去更好的准备即将到来的面试 -- 但面试官很有可能通过下面 3 个问题来判断你了解和掌握 JavaScrip

面试中对Hibernate缓存机制的回答

这是面试中经常问到的一个问题,可以按照下面的思路回答,准你回答得很完美.首先说下Hibernate缓存的作用(即为什么要用缓存机制),然后再具体说说Hibernate中缓存的分类情况,最后可以举个具体的例子.Hibernate缓存的作用: Hibernate是一个持久层框架,经常访问物理数据库,为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据Hibernat

程序员如何快速准备面试中的算法

前言 我决定写篇短文,即为此文.之所以要写这篇文章,缘于微博上常有朋友询问,要毕业找工作了,如何备战算法.尽管在微博上简单梳理过,如下图所示: 但因字数限制,特撰此文着重阐述下:程序员如何快速准备面试中的算法,顺便推荐一些相关的书籍或资料. 备战面试中算法的五个步骤 总体来说,备战面试中的算法,分为五个步骤,如下: 1.首选你得确保自己已经掌握好一门编程语言 如果是C的话,推荐Dennis M. Ritchie & Brian W. Kernighan著的<C程序设计语言>,和<

[HTML面试]HTML5 面试中最常问到的 10 个问题

1. HTML5 新的 DocType 和 Charset 是什么?HTML5 现在已经不是 SGML 的子集,DocType 简化为:                  <!doctype html>HTML 5 指定 UTF-8 编码的方式如下:                 <meta charset="UTF-8"> 2. 如何在 HTML5 页面中嵌入音频?HTML 5 包含嵌入音频文件的标准方式,支持的格式包括 MP3.Wav 和 Ogg:<

面试题_125_to_133_Java 面试中其他各式各样的问题

这部分包含 Java 中关于 XML 的面试题,JDBC 面试题,正则表达式面试题,Java 错误和异常及序列化面试题 125)嵌套静态类与顶级类有什么区别?(答案)一个公共的顶级类的源文件名称与类名相同,而嵌套静态类没有这个要求.一个嵌套类位于顶级类内部,需要使用顶级类的名称来引用嵌套静态类,如 HashMap.Entry 是一个嵌套静态类,HashMap 是一个顶级类,Entry是一个嵌套静态类. 126)你能写出一个正则表达式来判断一个字符串是否是一个数字吗?(解决方案)一个数字字符串,只

Android重难点解析——面试中可能被问到的那些问题

这篇项目主要介绍Android中的一些重难点概念,也包括面试中可能被问到的经典问题. 因为这些知识点比较琐碎,不太适合写成一篇文章,所以采用Github管理,内容会首先在Github更新,这里不定时同步,如果你想第一时间收到通知,请关注Github中的该项目. 项目地址 Android重难点解析,欢迎star,follow,将持续分享Android开发知识 文章列表 谈谈你对Application类的理解 Android为什么要设计出Bundle而不是直接使用HashMap来进行数据传递? 谈谈

[转载]java面试中经常会被问到的一些算法的问题

Java面试中经常会被问到的一些算法的问题,而大部分算法的理论及思想,我们曾经都能倒背如流,并且也能用开发语言来实现过, 可是很多由于可能在项目开发中应用的比较少,久而久之就很容易被忘记了,在此我分享一下在面试中经常被问到的一些基本的算法,也当做一次知识的巩固. 排序算法的一些特点: * 排序算法的分类如下:* 1.插入排序(直接插入排序.折半插入排序.希尔排序):* 2.交换排序(冒泡泡排序.快速排序):* 3.选择排序(直接选择排序.堆排序):* 4.归并排序:* 5.基数排序.* * 关于