设为首页 加入收藏

TOP

malloc与sizeof的合用的陷阱(一)
2014-11-23 21:42:12 来源: 作者: 【 】 浏览:50
Tags:malloc sizeof 合用 陷阱
摘要:在编程过程中,我们经常这样运用malloc: int * myarray=(int *)malloc(sizeof(int)*length),但是你是否知道,这一句简单的代码隐含了2个陷阱?
1.关于malloc与void *指针
还是分析上述代码:
首先,malloc返回的值是void *类型,没有必要进行类型转化。而且这样会降低代码的易读性,很容易让你忽略malloc这个函数,从而导致忘记添加#include
第二,sizeof不是一个函数,它只是一个运算符,sizeof部分在编译之前就已经确定。
第三,我们推荐的用法是malloc后面的单位最好与前面的变量能够绑定(这样有利于代码的易维护性),所以,我们最好使用sizeof *myarray
综上,我们推荐的写法是: int * myarray = malloc(length * sizeof *myarray),是的!!这样很别扭——因为你一直使用的是错误的用法。
2.关于sizeof
下文,全部摘自:C/C++刁钻问题各个击破之细说sizeof
Sizeof的作用非常简单:求对象或者类型的大小。然而sizeof又非常复杂,它涉及到很多特殊情况,本篇把这些情况分门别类,总结出了sizeof的10个特性:
(0)sizeof是运算符,不是函数;
(1)sizeof不能求得void类型的长度;
(2)sizeof能求得void类型的指针的长度;
(3)sizeof能求得静态分配内存的数组的长度!
(4)sizeof不能求得动态分配的内存的大小!
(5)sizeof不能对不完整的数组求长度;
(6)当表达式作为sizeof的操作数时,它返回表达式的计算结果的类型大小,但是它不对表达式求值!
(7)sizeof可以对函数调用求大小,并且求得的大小等于返回类型的大小,但是不执行函数体!
(8)sizeof求得的结构体(及其对象)的大小并不等于各个数据成员对象的大小之和!
(9)sizeof不能用于求结构体的位域成员的大小,但是可以求得包含位域成员的结构体的大小!
概述:
Sizeof是C/C++中的关键字,它是一个运算符,其作用是取得一个对象(数据类型或者数据对象)的长度(即占用内存的大小,以byte为单位)。其中类型包含基本数据类型(不包括void)、用户自定义类型(结构体、类)、函数类型。数据对象是指用前面提到的类型定义的普通变量和指针变量(包含void指针)。不同类型的数据的大小在不同的平台下有所区别,但是c标准规定所有编译平台都应该保证sizeof(char)等于1。关于sizeof的更多概述你可以在msdn总输入sizeof进行查询。
看了上面这些,或许你看了没有多少感觉。没关系,下面我将详细列出sizeof的诸多特性,这些特性是造成sizeof是一个较刁钻的关键字的原因:
十大特性:
特性0:sizeof是运算符,不是函数
这个特性是sizeof的最基本特性,后面的很多特性都是受到这个特性的影响,正因为sizeof不是函数,因此我们不把它所要求得长度的对象叫做参数,我本人习惯上叫做操作数(这不严谨,但是有助于我记住sizeof是个操作符)。
特性1:sizeof不能求得void类型的长度
是的,你不能用sizeof(void),这将导致编译错误:illegalsizeof operand。事实上你根本就无法声明void类型的变量,不信你就试试void a;这样的语句,编译器同样会报错:illegal use of type 'void'。或许你要问为什么,很好,学东西不能只知其然,还要知其所以然。我们知道声明变量的一个重要作用就是告诉编译器该变量需要多少存储空间。然而,void是“空类型”,什么是空类型呢,你可以理解成不知道存储空间大小的类型。既然编译器无法确定void类型的变量的存储大小,那么它自然不让你声明这样的变量。当然了,声明void类型的指针是可以的!这就是特性2的内容。
特性2:sizeof能求得void类型的指针的长度
在特性1中说过,可以申明void类型的指针,也就是说编译器可以确定void类型的指针所占用的存储空间。事实上确实如此,目前,几乎所有平台上的所有版本的编译器都把指针的大小看做4byte,不信你试试sizeof(int*);sizeof(void*);sizeof(double*);sizeof(Person*);等等,它们都等于4!为什么呢?问得好,我将尽全力对此作出解释:其实指针也是变量,只不过这个变量很特殊,它是存放其他变量的地址的变量。又由于目前32位计算机平台上的程序段的寻址范围都是4GB,寻址的最小单元是byte,4GB等于232Byte,这么多的内存其地址如果编码呢,只需要用32个bit就行了,而32bit = 32/8 = 4byte,也就是说只需要4byte就能存储这些内存的地址了。因此对任何类型的指针变量进行sizeof运算其结果就是4!
特性3:sizeof能求得静态分配内存的数组的长度!
Int a[10];int n = sizeof(a);假设sizeof(int)等于4,则n= 10*4=40;特别要注意:charch[]=”abc”;sizeof(ch);结果为4,注意字符串数组末尾有’\0’!通常我们可以利用sizeof来计算数组中包含的元素个数,其做法是:int n = sizeof(a)/sizeof(a[0]);
非常需要注意的是对函数的形参数组使用sizeof的情况。举例来说,假设有如下的函数:
void fun(int array[10])
{
int n = sizeof(array);
}
你会觉得在fun内,n的值为多少呢?如果你回答40的话,那么我很遗憾的告诉你,你又错了。这里n等于4,事实上,不管形参是int的型数组,还是float型数组,或者其他任何用户自定义类型的数组,也不管数组包含多少个元素,这里的n都是4!为什么呢?原因是在函数参数传递时,数组被转化成指针了,或许你要问为什么要转化成指针,原因可以在很多书上找到,我简单说一下:假如直接传递整个数组的话,那么必然涉及到数组元素的拷贝(实参到形参的拷贝),当数组非常大时,这会导致函数执行效率极低!而只传递数组的地址(即指针)那么只需要拷贝4byte。
特性4:sizeof不能求得动态分配的内存的大小!
假如有如下语句:int*a = new int[10];int n = sizeof(a);那么n的值是多少呢?是40吗?答案是否定的!其实n等于4,因为a是指针,在特性2中讲过:在32位平台下,所有指针的大小都是4byte!切记,这里的a与特性3中的a并不一样!很多人(甚至一些老师)都认为数组名就是指针,其实不然,二者有很多区别的,要知详情,请看《c专家编程》。通过特性3和特性4,我们看到了数组和指针有着千丝万缕的关系,这些关系也是导致程序潜在错误的一大因素,关于指针与数组的关系问题我将在《C/C++刁钻问题各个击破之指针与数组的秘密》一文中进行详细介绍。
特性3指出
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C语言的那些事――scanf()和gets(.. 下一篇Linux环境下的C/C+基础调试技术2..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: