填空题:
(1)从变量的定义位置分,可分为全局变量与局部变量。其中,局部变量定义在函数或复合语句中,供函数或复合语句中使用。
(2)变量的存储类型分为auto,extern,register, static。当声明一个静态(static)变量,它既具有局部变量的性质,又具有全局变量的性质。
(3)C++程序的内存分为4个区:全局数据区,代码区,栈区,堆区。全局变量,静态变量,字符串常量存放在全局数据区,所有在函数和代码存放在代码区,为运行函数而分配的函数参数,局部变量、返回地址存放在栈区。动态分配的内存在堆区。
(4)全局变量,静态变量具有静态生存期;局部变量生存期为动态。
(5)函数原型中形参标识符的作用域为为函数原型,函数的形参与
函数体作用域为块作用域;函数,全局变量与常量有文件作用域。
( 6)C++源程序中以#开头,以换行符结尾的行称为预处理命令。预处理命令编译前由预处理器执行。
( 7)可以通过3种方法使用名字空间,个别使用声明方式,全局声明方式,全局声明个成员。
2.
(1)在C++中,函数默认的存储类别为:auto。
(2)函数的形式参数是局部变量,在一个函数体内定义的变量只在本函数范围内有效, 在函数的复合语句中定义的变量只在此复合语句中有效 。
( 3) # define PI 3.14 预处理命令必须以 #开头,凡是以 #开头的都是
预处理命令行,在程序执行前执行预处理命令。
( 4)动态分配的内存要用 delete释放,局部 auto变量分配的内存在
函数调用结束时释放,全局变量的内存在程序结束时释放。
memset问题
memset初始化函数:将某一块内存中的内容全部设置为指定的值,即做初始化工作。
memset原型:
题目:请解释以下该函数以及其参数的含义:void *memset(void *s,int ch,size_t n);?
【答案】
作初始化函数,将某一块内存中的内容全部设置为指定的值。
参数:s是需要初始化的变量,ch是替换s首n个字节的值,n是n个字节。
题目:以下代码是否正确?
char *s=”Golden Global View”;
memset(s,’G’,6);
【答案】
是错误的。因为s已指向一个常量字符串。所以无法用memset函数来对此s进行修改值。
题目:
char buffer[20];
memcpy(buffer,”123”,3)
是否正确?
【答案】
错误。因为buffer没有被初始化,也就是没有值,如果直接使用memcpy函数的话,就会打印出后面的值是乱码的。
应该修改为:
char buffer[20];
memset(buffer,0,sizeof(char)*20);
memcpy(buffer,”123”,3);
题目:memset函数对哪些类型不能初始值为1?
【答案】
char data[10];
memset(data,0,sizeof(data));//0
memset(data,-1,sizeof(data));//-1
memset(data,1,sizeof(data));//1
一般memset设置值的范围为0—255.这是因为后八位才是有效的值,后八位的前面位数无论设置多少的值,一律都按后八位的值来计算。比如说:0100 0000 0110 0001,就算设置了这个值,处理结果仍然按照后八位0110 0001来输出。如果data是char类型,输出结果范围为-128到127。
那么在int ,float,double类型方面就不同了,结果有效值只为0或-1,不能设置为1,否则,输出结果就会是随机数。
如果是bool类型,则结果有效值为0到255。
如果是其他对象:
structdata data;
memset(&data,0,sizeof(structdata));
题目:
struct Data
{
int *p;
};
Data data;
data.p=new int[10];
memset(data,0,sizeof(data));
是否正确?
【答案】
不正确。虽然编译通过,但是当解引用结构体内的p指向的内容会使程序崩溃。因为memset函数只是初始化该结构体,但是对p指向的堆内存并没有进行初始化,并且调用该函数时,p将会设置值为0,即空指针。这也会造成内存泄漏的问题,导致无法获知地址并无法释放掉此堆内存。
malloc问题
题目:在调用malloc()的时候,错误“不能把void*转换为int*”是什么意思?
【答案】
说明你用的是C++编译器而不是C编译器。
题目:我有个程序分配了大量的内存,然后又释放了。但是从操作系统看,内存的占用率却并没有变回去。
【答案】
多数malloc/free的实现并不把释放的内存返回操作系统,而是留着供同一程序的后续malloc()使用。
题目:free()怎么知道有多少字节需要释放?
【答案】
malloc/free的实现会在分配的时候记下每一块的大小,所以在释放的时候就不必再考虑它的的大小了。(通常,这个大小就记录在分配的内存块旁边,因此,对超出分配内存块边界的内存哪怕是轻微的改写,也会导致严重的后果。)
题目:为什么sizeof不能告诉我它所指的内存块的大小?
【答案】
sizeof操作符并不知道你使用了malloc为指针分配内存,sizeof只能得到指针本身的大小。没有什么可移植的办法得到malloc分配的内存块的大小。
题目(7.35)calloc()和malloc()有什么区别?应该用哪一个?利用calloc的零填充功能安全吗?free()可以释放calloc()分配的内存吗,还是需要一个cfree()?
【答案】
calloc(m,n)本质上等价于
p=malloc(m*n);
memset(p,,m*n);
除了参数个数不同和用零填充之外,这两个函数并无其他重要的区别。
题目:什么情况下会发生段错误?
【答案】
段错误通常发生在访问非法内存地址的时候,比如使用野指针,或者试图修改字符串常量的内容
题目:new和malloc的区别?
【答案】(答案摘自某博文)
1、new分配内存按照数据类型进行分配,malloc分配内存按照指定的大小分配;
2、new返回的是指定对象的指针,而malloc返回的是void*,因此malloc的返回值一般都需要进行类型转化。
3、new不仅分配一段内存,而且会调用构造函数,malloc不会。
4、new分配的内存要用delete销毁,malloc要用free来销毁;delete销毁的时候会调用对象的析构函数,而free则不会。
5、new是一个操作符可以重载,malloc是一个库函数。
6、malloc分配的内存不够的时候,可以用realloc扩容。扩容的原理?new没用这样操作。
7、new如果分配失败了会抛出bad_malloc的异常,而malloc失败了会返回NULL。
8、申请数组时: new[]一次分配所有内存,多次调用构造函数,搭配使用delete[],delete[]多次调用析构函数,销毁数组中的每个对象。而malloc则只能sizeof(int) * n。
题目:A* a = new A; a->i = 10;在内核中的内存分配上发生了什么?(题目不严谨,应是在函数内定义A *a)
【答案】
1)A *a:a是一个局部变量,类型为指针,故而操作系统在程序栈区开辟4/8(在32位机器下,为4个字节)字节的空间(0x000m),分配给指针a。
2)new A:通过new动态的在堆区申请类A大小的空间(0x000n)。
3)a = new A:将指针a的内存区域填入栈中类A申请到的地址的地址。即*(0x000m)=0x000n。
4)a->i:先找到指针a的地址0x000m,通过a的值0x000n和i在类a中偏移offset,得到a->i的地址0x000n + offset,进行*(0x000n + offset) = 10的赋值操作,即内存0x000n + offset的值是10。
题目:对于虚函数,说说类的内存分布?
【答案】
virtual修饰符
如果一个类是局部变量则该类数据存储在栈区,如果一个类是通过new/malloc动态申请的,则该类数据存储在堆区。
如果该类是virutal继承而来的子类,则该类的虚函数表指针和该类其他成员一起存储。虚函数表指针指向只读数据段中的类虚函数表,虚函数表中存放着一个个函数指针,函数指针指向代码段中的具体函数。
如果类中成员是virtual属性,会隐藏父类对应的属性。
题目:静态变量何时分配内存并初始化?
【答案】
静态变量中的数据段和BSS段,在执行代码之前初始化,也属于编译器初始化。但对于静态对象来说,当对象首次创建,则就会对这些对象进行构造并初始化,直至程序退出才会销毁内存。
题目:栈溢出一般是由什么原因导致的?
【答案】
没有回收垃圾资源。
题目:全局变量可不可以定义在可被多个.C 文件包含的头文件中?为什么?
【答案】
可以,在不同的C 文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。
题目:如何引用一个已经定义过的全局变量?
【答案】
可以用引用头文件的方式,也可以用extern 关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern 方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
题目:A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?
【答案】
static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。
他们都放在静态数据区,但是编译器对他们的命名是不同的。如果要使变量在其他模块也有意义的话,需要使用extern 关键字。
该函数被C 编译器编译后在库中的名字为_foo,而C++ 编译器则会产生像_foo_int_int之类的名字。 C++提供了C 连接交换指定符号extern“C”来解决名字匹配问题。