sizeof
问:C++里定义一个空的类型,里面没有任何成员变量和成员函数。对该类型求sizeof,得到的结果是多少?
答:1
问:为什么不是0?
答:空类型的实例中不包含任何信息,本来求sizeof应该是0,但是当我们声明该类型的实例的时候,它必须在内存中占有一定的空间,否则无法使用这些实例。至于占用多少内存,由编译器决定。Visual Studio中每个空类型的实例占用1字节的空间。
问:如果在该类型中添加一个构造函数和析构函数,再对该类型求sizeof,得到的结果又是多少?
答:和前面一样,还是1。调用构造函数和析构函数只需要知道函数的地址即可,而这些函数的地址只与类型相关,而与类型的实例无关,编译器也不会因为这两个函数而在实例内添加任何额外的信息。
问:那如果把析构函数标记为虚函数呢?
答:C++编译器一旦发现一个类型中有虚函数,就会为该类型生成虚函数表,并在该类型的每一个实例中添加一个虚函数表的指针。在32位的机器上,一个指针占4字节的空间,因此求sizeof得到4;如果是64位的机器,一个指针占8字节的空间,因此求sizeof则得到8。
数组与指针
运行下面的代码,结果是什么?
int _tmain(int argc, _TCHAR* argv[])
{
char str1[] = "hello world";
char str2[] = "hello world";
char* str3 = "hello world";
char* str4 = "hello world";
if(str1 == str2)
printf("str1 and str2 are same.\n");
else
printf("str1 and str2 are not same.\n");
if(str3 == str4)
printf("str3 and str4 are same.\n");
else
printf("str3 and str4 are not same.\n");
return 0;
}
str1和str2是两个字符串数组,我们会为它们分配两个长度为12个字节的空间,并把”hello world”的内容分别复制到数组中去。这是两个初始地址不同的数组,因此str1和str2的值也不相同,所以输出的第一行是”str1 and str2 are not same”。
str3和str4是两个指针,我们无须为它们分配内存以存储字符串的内容,而只需要把它们指向”hello world”在内存中的地址就可以了。由于“hello world”是常量字符串,它在内存中只有一个拷贝,因此str3和str4指向的是同一个地址。所以比较str3和str4的值得到的结果是相同的,输出的第二行是”str3 and str4 are same”。
关于(&a + 1)和*(a + 1)
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
程序输出为:2,5
解释:
*(a+1)
其实很简单就是指a[1]
,输出为2.
问题关键就在于第二个点,*(ptr-1)
输出为多少?
解释如下,&a+1
不是首地址+1,系统会认为加了一个整个a数组,偏移了整个数组a的大小(也就是5个int的大小)。所以int *ptr=(int *)(&a+1)
;其实ptr实际是&(a[5])
,也就是a+5
.
原因为何呢?
&a
是数组指针,其类型为int(*)[5]
;
而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同,a是长度为5的int数组指针,所以要加5*sizeof(int)
,所以ptr实际是a[5],但是ptr与(&a+1)
类型是不一样的,这点非常重要,所以ptr-1只会减去sizeof(int*)
,a,&a的地址是一样的,但意思就不一样了,a是数组首地址,也就是a[0]
的地址,&a是对象(数组)首地址,a+1
是数组下一元素的地址,即a[1]
,&a+1
是下一个对象的地址,即a[5]
。