目录
7、#include 和#include "filename.h"有什么区别?
16. 在C++程序中调用被C编译器编译后的函数,为什么要加extern"C"?
18. 用一个宏定义求一个结构体struct里某个变量相对struct的偏移量
25. 一个参数可以既是const又是volatile吗?一个指针可以是volatile吗?
1、不使用sizeof,如何求int占用的字节数
#include <stdio.h>
#define MYSIZEOF(value) (char *)(&value+1)-(char *)&value
int main()
{
int i;
double f;
double *p;
printf("%d\n", MYSIZEOF(i));
printf("%d\n", MYSIZEOF(f));
printf("%d\n", MYSIZEOF(q));
return 0;
}
2、struct和union
typedef union {
double i;
int k[5];
char c;
}DATE;
typedef struct data {
int cat;
DATE cow;
double dog;
}too;
DATE max;
printf("%d\n", sizeof(too)+sizeof(max));
假设为32位机器,int型占4个字节, double型占8个字节,char型占1个字节,而DATE是一个联合型变量,联合型变量共用空间,uion里面最大的变量类型是int[5],所以占用20个字节,它的大小是20,而由于 union中 double占了8个字节,因此 union是要8个字节对齐,所占内存空间为8的倍数。为了实现8个字节对齐,所占空间为24.而data是一个结构体变量,每个变量分开占用空间,依次为 sizeof(int)+ sizeof(DATE)+ sizeof( double)=4+24+8=36按照8字节对齐,占用空间为40,所以结果为40+24=64。
3、左值与右值
-
左值是指可以出现在等号左边的变量或表达式,它最重要的特点就是可写(可寻址)。也就是说,它的值可以被修改,如果一个变量或表达式的值不能被修改,那么它就不能作为左值。
-
右值是指只可以出现在等号右边的变量或表达式。它最重要的特点是可读。一般的使用场景都是把一个右值赋值给一个左值。
-
通常,左值可以作为右值,但是右值不一定是左值。
4、a++与++a的区别
a++的具体运算过程如下
int temp = a;
a = a + 1;
return temp;
++a的具体运算过程如下
a = a + 1;
return a;
后置自增运算符需要把原来变量的值复制到一个临时的存储空间,等运算结束后才会返回这个临时变量的值。所以前置自增运算符效率比后置自增要高。
5、堆和栈有什么区别
-
申请方式 栈的空间由操作系统自动分配/释放,堆上的空间手动分配/释放。
-
申请大小的限制栈空间有限。 在Windows下,栈是向低地址扩展的数据结 构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是 一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小堆是很大的自由存储区。
堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
-
申请效率 栈由系统自动分配,速度较快。但程序员是无法控制的。 堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
6、定义常量谁更好? #define还是const?
尺有所短,寸有所长, define与 const都能定义常量,效果虽然一样,但是各有侧重。
define既可以替代常数值,又可以替代表达式,甚至是代码段,但是容易出错,而 const的引入可以增强程序的可读性,它使程序的维护与调试变得更加方便。具体而言,它们的差异主要表现在以下3个方面。
-
define只是用来进行单纯的文本替换, define常量的生命周期止于编译期,不分配内存空间,它存在于程序的代码段,在实际程序中,它只是一个常数;而 const常量存在于程序的数据段,并在堆栈中分配了空间,const常量在程序中确确实实存在,并且可以被调用、传递
-
const常量有数据类型,而 define常量没有数据类型。编译器可以对 const常量进行类型安全检査,如类型、语句结构等,而 define不行。
-
很多IDE支持调试 const定义的常量,而不支持 define定义的常量由于 const修饰的变量可以排除程序之间的不安全性因素,保护程序中的常量不被修改,而且对数据类型也会进行相应的检查,极大地提高了程序的健壮性,所以一般更加倾向于用const来定义常量类型。
7、#include <filename.h>和#include "filename.h"有什么区别?
对于#include <filename.h>,编译器先从标准库路径开始搜索filename.h,使得系统文件调用较快。而对于#include "filename.h",编译器先从用户的工作路径开始搜索filename.h,然后去寻找系统路径,使得自定义文件较快。
8、内存泄漏
在堆上分配的内存,如果不再使用了,就应该及时释放,以便后面其他地方可以重用。而在C语言中,内存管理器不会自动回收不再使用的内存。如果忘了释放不再使用的内存,这些内存就不能被重用了,这就造成了内存泄漏。
9、内存管理有哪几种方式
常见的内存管理方式有块式管理、页式管理、段式管理和段页式管理。最常用的是段页式管理。
-
块式管理:把主存分为一大块一大块的,当所需的程序片断不在主存时就分配一块主存空间,把程序片断载入主存,就算所需的程序片段只有几个字节,也只能把这一块分配给它。 这样会造成很大的浪费,平均浪费了50%的内存空间,但是易于管理。
-
页式管理:用户程序的地址空间被划分成若干个固定大小的区域,这个区域被称为页”,相应地,内存空间也被划分为若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一 块中, 从而实现了离散分配。这种方式的优点是页的大小是固定的,因此便于管理;缺点是页长与程序的逻辑大小没有任何关系。这就导致在某个时刻一个程序可能只有一部分在主存中,