2012年8月22学习笔记---程序员面试宝典

1 空类与多重继承的空类以及虚函数的内存占用:

#include <iostream>

using namespace std;

class A {};
class A1 {};
class B : public A {};
class C : public virtual B {};
class D : public A, public A1 {};

int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
cout << sizeof(D) << endl;
return 0;
}

     空类所占空间为1,单一继承的空类空间也为1,多重继承的空类空间也为1,但是虚继承涉及到虚表(虚指针),所以大小为4。

深入理解sizeof与strlen的区别

1、sizeof操作符的结果类型是size_t,它在头文件中的typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
2、sizeof运算符,strlen是函数。
3、sizeof可以用类型或函数做参数,strlen只能用char*做参数,且必须以"\0"结尾的。
4、数组做sizeof的参数不退化,传递给strlen就退化为指针。
5、大部分编译程序在编译的时候就把sizeof计算过了,是类型或是变量的长度,这就是sizeof(x)可以用来定义数组维数的原因。
6、strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,而不是类型占内存的大小。
7、sizeof后如果是类型必须加括号,如果是变量名可以不加括号,这是因为sizeof是操作符而不是函数。
8、当使用了一个结构类型或变量时,sizeof返回实际的大小。当使用一静态的空间数组时,sizeof返回全部数组的尺寸。sizeof不能返回被动态分配的数组或外部的数组的尺寸,sizeof计算栈中分配的大小,不计算静态变量。
9、数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:func(char [8]), func(char []), func(char*)等价。在C++中传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小,如果想在函数内知道数组的大小,需要进入函数后用memcpy将数组复制出来,长度由另一个形参传进去。
10、计算结构变量的大小就必须讨论数据对齐问题。
11、sizeof操作符不能用于函数类型、不完全类型或位字段。不完全类型指具有未知存储大小数据的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。


3 内存分配的三种方式:

(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。

(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

4 内存的动态分配:

例如:

void GetMemory(char *p)
{
 p = (char *)malloc(100);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(str);
 strcpy(str, "hello world");
 printf(str);
}

请问运行Test 函数会有什么样的结果?
答:程序崩溃。因为GetMemory 并不能传递动态内存,Test 函数中的 str 一直都是 NULL。

解析: 当Test函数调用GetMemroy(char* p),将str当参数传递给p,其实就是调用之后,p为str副本,就是将str指向的地址赋值给p,但是str是null,是”不存在的“,暂时没分配的;哈哈其实调用GetMemroy时,系统会为其产生一个过程栈使用,而参数p其实就存在“过程栈”上,也就是说调用时,在栈上分配了一个指针char* p,指针吗,其实就是一个会指向其他内存位置的一块地址,の......,其实发现,调用时,传递的str与p自始至终没有任何联系.......这.....这就从根本上说明,动态分配压根不可行........

图示如下:


strcpy(str, "hello world");将使程序崩溃。因为....str为null的,

char* p;
p="hello";
会报错(vs),因为p本身并不指向一个存在的地址。

char *GetMemory(void)
{
 char* p = "hello world";
 return p;
}
void Test(void)
{
 char *str = NULL;
 str = GetMemory();
 printf(str);
}

请问运行Test 函数会有什么样的结果?
答:可能是乱码。
    因为GetMemory 返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。

void GetMemory2(char **p, int num)
{
 *p = (char *)malloc(num);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(&str, 100);
 strcpy(str, "hello");
 printf(str);
}


请问运行Test 函数会有什么样的结果?
答:
(1)能够输出hello
(2)内存泄漏


void Test(void)
{
 char *str = (char *) malloc(100);
 strcpy(str, “hello”);
 free(str);
if(str != NULL)
{
 strcpy(str, “world”);
 printf(str);
}
}


请问运行Test 函数会有什么样的结果?


答:篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str 成为野指针,


if(str != NULL)语句不起作用。
**********************************************************************************************
void GetMemory2(char **p, int num)
{
 *p = (char *)malloc(sizeof(char) * num);
}
void Test2(void)
{
 char *str = NULL;
 GetMemory2(&str, 100); // 注意参数是 &str,而不是str
 strcpy(str, "hello");
 cout<< str << endl;
 free(str);
}

如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”.由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。

char *GetMemory3(int num)
{
 char *p = (char *)malloc(sizeof(char) * num);
 return p;
}
void Test3(void)
{
 char *str = NULL;
 str = GetMemory3(100);
 strcpy(str, "hello");
 cout<< str << endl;
 free(str);
}


这里强调不要用return 语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡。

 char *GetString(void)
{
 char *p = "hello world";
 return p; // 编译器将提出警告
}
void Test4(void)
{
 char *str = NULL;
 str = GetString(); // str 的内容是垃圾
 cout<< str << endl;
}

用调试器逐步跟踪Test4,发现执行str = GetString 语句后str 不再是NULL 指针,但是str 的内容不是“hello world”而是垃圾。同样是因为存在于过程栈中,用完就有可能释放啦,即使是指针,这种跨栈访问也是危险的。
 char *GetString2(void)
{
 char *p = "hello world";
 return p;
}
void Test5(void)
{
 char *str = NULL;
 str = GetString2();
 cout<< str << endl;
}

函数Test5 运行虽然不会出错,但是函数GetString2 的设计概念却是错误的。因为
GetString2 内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内
恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。

总结起来:

因为这个函数返回的是一个局部变量地址,当调用这个函数后,这个局部变量str就随着过程栈的释放而释放啦,所以返回的结果是不确定的,而且还是不安全的。
下面的代码:
#include <iostream>
using namespace std;
char strone[14];
char* strA()
{
strcpy(strone,"hello world");
return strone;
}
int main()
{
    char* str=NULL;
	cout<<str<<endl;
	char* p=strA();
	cout<<p;
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值