一直以为自己理解了sizeof和strlen,当碰壁之后才发现自己理解的不够全面。
sizeof是C/C++中的一元运算符(不可重载),用于计算任意数据类型(基本型、符合型)、对象、函数所占据的大小,单位是字节。
strlen是C标准库中函数,只能用于计算字符串的长度(遇'\0'终止,不包括'\0')。
sizeof 类型,该类型所占的空间大小;
sizeof 对象,对象的实际占用空间大小;
sizeof 函数,函数的返回类型所占的空间大小;函数的返回类型不能是void。
sizeof 数组,编译时分配的数组空间大小;
sizeof 指针,存储该指针所用的空间大小。
注意:类、结构体静态成员变量不占用类、结构体内存,原因是编译器将其放在全局变量区。构造函数,成员函数和静态函数不占内存。
其中有2个问题值得去思考一下:
1.空类的sizeof为什么是1?
2.enum的sizeof为什么总是4?
在测试代码的注释中都做了解释。
strlen 从代表该字符串的第一个地址开始遍历,直到遇到结束符'\0';返回的长度大小不包括'\0'。
注意:
当strlen用于数组时,返回的值可能是随机值,stlen会走出数组边界外,直到找到'\0'为止。
理解了下0, /0, NULL,
0是整形常量,可以表示有char,int,long,double,float;
'/0'是字符常量,表示空字符,常用于字符串的结束标志;
NULL是宏定义,在C语言中被定义为0,在C++中为(void *)0;
三者在数值上都是0(经过强转),只是在不同类型下表示的意义不一样。
0, /0, NULL都会占用sizeof的空间,strlen遇到这3者终止计数;如果直接将这三者传入strlen,程序将终止。
#include <iostream.h>
enum eNull
{
};
enum eMonth
{
January, February, March, April, May, June, July, August, September, October, November, December
};
eMonth em;
struct sNull
{
};
sNull sn;
struct sBit
{
int a:1;
};
class cNull
{
};
cNull objectCNull;
class cBit
{
public:
int a:1;
int b:1;
};
cBit cb;
class cChar
{
char x;
};
template<typename dataType>
class cTemplate
{
public:
cTemplate()
{
cout<<"sizeof(dataType) = "<<sizeof(dataType)<<endl;
}
};
union uNull
{
};
union uBit
{
int a:1;
};
short func()
{
return 1;
}
//sizeof 类型——该类型所占的空间大小;
//sizeof 对象——对象的实际占用空间大小;
//sizeof 函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。
void test_sizeof_dataType()
{
cout<<"sizeof(eNull) = "<<sizeof(eNull)<<endl; //4 为什么?
cout<<"sizeof(eMonth) = "<<sizeof(eMonth)<<endl; //4 ?
cout<<"sizeof(em) = "<<sizeof(em)<<endl; //4 ?
cout<<"sizeof(January) = "<<sizeof(January)<<endl; //4 ?
/*
为什么enum无论怎么sizeof都是4?下面的解释在google中找的
The size is four bytes because the enum is stored as an int. With only 12 values, you really only need 4 bits, but 32 bit machines process 32 bit quantities more efficiently than smaller quantities.
0 0 0 0 January
0 0 0 1 February
0 0 1 0 March
0 0 1 1 April
0 1 0 0 May
0 1 0 1 June
0 1 1 0 July
0 1 1 1 August
1 0 0 0 September
1 0 0 1 October
1 0 1 0 November
1 0 1 1 December
1 1 0 0 ** unused **
1 1 0 1 ** unused **
1 1 1 0 ** unused **
1 1 1 1 ** unused **
*/
cout<<"sizeof(sNull) = "<<sizeof(sNull)<<endl; //1
printf("sizeof(sn) = %d \n", sizeof(sn) ); //在GCC编译下位0, 在G++编译下为1
cout<<"sizeof(sBit) = "<<sizeof(sBit)<<endl; //4
cout<<"sizeof(cNull) = "<<sizeof(cNull)<<endl; //空类为什么是1?
cout<<"sizeof(objectCNull) = "<<sizeof(objectCNull)<<endl;
cout<<"sizeof(cChar) = "<<sizeof(cChar)<<endl;
cout<<"sizeof(cBit) = "<<sizeof(cBit)<<endl;//4
//cout<<"sizeof(cb.a) = "<<sizeof(cb.a)<<endl; //invalid application of sizeof to a bit-field 不能用于计算位域的大小
cTemplate<cNull> ct; //1 输出为模板类大小
/*
空类的sizeof为什么是1?(解释来自google)
The only reason for this rule is that objects must be uniquely identifiable. An object is identified by the address it has in memory. To ensure that no two objects have the same address (except in the case of base class objects), objects of empty classes “occupy” memory by having a non-zero size.
*/
cout<<"sizeof(uNull) = "<<sizeof(uNull)<<endl; //1
cout<<"sizeof(uBit) = "<<sizeof(uBit)<<endl; //4
cout<<"sizeof(func()) = "<<sizeof(func())<<endl; //2 函数的返回类型所占的空间大小
}
//sizeof--数组,编译时分配的数组空间大小;
//strlen从代表该字符串的第一个地址开始遍历,直到遇到结束符'\0';返回的长度大小不包括'\0'。
void test_array()
{
char array[] = {'h','e','l','\0','l','o'};
cout<<"sizeof(array) = "<<sizeof(array)<<endl;
cout<<"strlen(array) = "<<strlen(array)<<endl;
char array2[2] = {'h','e'};
cout<<"sizeof(array2) = "<<sizeof(array2)<<endl;
cout<<"strlen(array2) = "<<strlen(array2)<<endl; //随机值
char array3[] = "hello\0\0";
cout<<"sizeof(array3) = "<<sizeof(array3)<<endl;
cout<<"strlen(array3) = "<<strlen(array3)<<endl;
char array4[10][10] = {"hello","abcde"};
cout<<"sizeof(array4) = "<<sizeof(array4)<<endl;
cout<<"strlen(array4[0]) = "<<strlen(array4[0])<<endl;
char array5[1]= {};
array5[0] = 'a';
array5[1] = 'b';
array5[2] = 'c';
array5[3] = 'd';
cout<<array5<<endl; //不会判断边界,越界,
cout<<sizeof(array5)<<endl;
cout<<strlen(array5)<<endl;
}
//sizeof指针——存储该指针所用的空间大小
void test_pointer()
{
char *str = "hel\0lo";
cout<<"sizeof(str) = "<<sizeof(str)<<endl;
cout<<"strlen(str) = "<<strlen(str)<<endl;
char * heap = new char[10];
cout<<"sizeof(heap) = "<<sizeof(heap)<<endl;
cout<<"strlen(heap) = "<<strlen(heap)<<endl;
}
//0是整形常量,可以表示有char,int,long,double,float
//'/0'是字符常量,表示空字符,常用于字符串的结束标志
//NULL是宏定义,在C语言中被定义为0,在C++中为(void *)0
//三者在数值上都是0(经过强转),只是在不同类型下表示的意义不一样
void test_basic()
{
char *p = 0;
char *p1 = '\0';
char *p2 = NULL; //指针可被赋值0,\0 ,NULL
//cout<<strlen(p)<<endl; //Segmentation fault, 不能将NULL, /0, 0传入strlen
/*
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
*/
cout<<"sizeof(0) = "<<sizeof(0)<<endl; //4
cout<<"sizeof(\0) = "<<sizeof('\0')<<endl; // \0在控制台上显示为NULL(什么都没有)
cout<<"sizeof(NULL) = "<<sizeof(NULL)<<endl; //NULL在以32位为索引的编译器中,是4个字节 0x00000000 NULL在64位的情况为8个字节0x0000000000000000
char array[] = "\0\0\0\0\0\0\0\0";
cout<<"sizeof(array) = "<<sizeof(array)<<endl;
cout<<"strlen(array) = "<<strlen(array)<<endl; //随机值
char array2[] = "\n\n\n\n\n\n\n\n";
cout<<"sizeof(array2) = "<<sizeof(array2)<<endl;
cout<<"strlen(array2) = "<<strlen(array2)<<endl; //随机值
char array3[5] = {'\v','\n','\t','\b','\r'}; // 转义符也要占1byte的空间
//char array3[5] = {'\v','\0','b','\0','c'};
cout<<"sizeof(array3) = "<<sizeof(array3)<<endl;
cout<<"strlen(array3) = "<<strlen(array3)<<endl;
char *str = "\0helloworld";
cout<<"sizeof(str) = "<<sizeof(str)<<endl;
cout<<"strlen(str) = "<<strlen(str)<<endl;
}
int main()
{
test_sizeof_dataType();
//test_array();
//test_pointer();
//test_basic();
return 1;
}