[C/C++] C/C++错题集
1.
解析:
void GetMemory(char *p) { p = (char *)malloc(100); } void Test(void) { char *str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); }
答案:程序崩溃
#include<iostream> using namespace std; class B { public: B() { cout << "default constructor" << " "; } ~B() { cout << "destructed" << " "; } B(int i): data(i) { cout << "constructed by parameter" << data << " "; } private: int data; }; B Play( B b) { return b; } int main(int argc, char *argv[]) { B temp = Play(5); return 0; }
答案:constructed by parameter5 destructed destructed
解析:
·调用Play函数需要将5隐式类型转换为Play函数中的形参b,会调用B的B(int i): data(i),打印“constructed by parameter5”。
·Play函数返回时需要调用B的复制构造函数给对象temp初始化。
·Play函数返回后需要调用b的析构函数,将Play函数的形参释放,打印“destructed”。
·main函数返回后需要释放temp,打印“destructed”。
4.
代码执行后,a和b的值分别为?
#include<iostream> using namespace std; class Test{ public: int a; int b; virtual void fun() {} Test(int temp1 = 0, int temp2 = 0) { a=temp1 ; b=temp2 ; } int getA() { return a; } int getB() { return b; } }; int main() { Test obj(5, 10); // Changing a and b int* pInt = (int*)&obj; *(pInt+0) = 100; *(pInt+1) = 200; cout << "a = " << obj.getA() << endl; cout << "b = " << obj.getB() << endl; return 0; }
答案:200 10
解析:
这么需要考虑虚函数表,指向虚函数表的指针在32位系统下占用4个字节,其地址分布在整个类成员变量的地址的首部,接下来就是变量a的地址、b的地址。当将Test对象obj赋给指向整型的pInt后,指针pInt指向了地址的首部也就是虚函数表指针,所以*(pInt+0)=100改变的是虚函数表的值,接下来*(pInt+1)=200改变的是变量a的值,变量b没有变换。
5.
CONTAINER::iterator iter , tempIt; for (iter = cont.begin() ; iter != cont.end() ; ) { tempIt = iter; ++iter; cont.erase(tempIt); } 假设cont是一个CONTAINER的示例,里面包含数个元素,那么当CONTAINER为: 1、vector 2、list 3、map 4、deque 会导致上面的代码片段崩溃的CONTAINER类型是?
答案:1,4
解析:
typedef struct list_t { struct list_t *next; struct list_t *prev; char data[0]; } list_t;
最后一行char data[0];的作用是?
答案:方便管理内存缓冲区,减少内存碎片化。
解析:柔性数组,具体可参考:http://www.cnblogs.com/lca1826/p/6636549.html
7.在32位系统下,有以下代码:
void Foo (char str[100]){ ... }
请计算 sizeof( str ) = ?
答案:4
解析:数组作为形参时,数组的数组名会退化成一个指向该类型数组的指针,只要是指针,在32位系统中所占的字节数就是4,在64位系统中所占的字节数是8。
8.
char a=101; int sum=200; a+=27;sum+=a; printf("%d\n",sum);
判断程序输出结果?
答案:72
解析:char类型的范围是-128~+127,当a+=27之后a的值超出可表示范围会变为-128。
9.
short i=65537; int j=i+1; printf(“i=%d,j=%d\n”, i, j);
判断程序输出结果?
答案:i=1,j=2
解析:short类型的数据占用2个字节16位,可表示的最大整数值为65535,即1111 1111 1111 1111,而65537转换成二进制为1 0000 0000 0000 0001,最高位的1溢出,因此i的值为0000 0000 0000 0001,即为1,而j=i+1,故j=2。
10.
答案:stra tra ra
解析:char *str[3] = {"stra","strb","strc"};是一个指针数组; char *p = str[0];实际上p指向第一个字符串,所以字符串加1,则指向字符串的下一个字母,而并非是下一个字符串。
11.
解析:访问vector中的数据
使用两种方法来访问vector。
1、vector::at()
2、vector::operator[]
operator[]主要是为了与C语言进行兼容。它可以像C语言数组一样操作。但at()是我们的首选,因为at()进行了边界检查,如果访问超过了vector的范围,将抛出一个异常。由于operator[]容易造成一些错误,所有我们很少用它,下面进行验证一下:
分析下面的代码:
vector<int> v; v.reserve(10); for(int i=0; i<7; i++) v.push_back(i); try { int iVal1 = v[7]; // not bounds checked - will not throw int iVal2 = v.at(7); // bounds checked - will throw if out of range } catch(const exception& e) { cout << e.what(); }
12.若int占2个字节,char占1个字节,float占4个字节,sizeof(xc)大小是:
struct stu { union { char bj[5]; int bh[2]; } class; char xm[8]; float cj; } xc;
答案:20
解析:
解析:union类型的变量在定义时是可以被初始化的,定义如下union类型:
union Test { int a; float b; }; Test test = {1};
test变量的定义可以初始化,初始值的类型必须是union中第一个成员的类型。
14.假设下面的函数foo会被多线程调用,那么让i、j、k三个变量哪些因为线程间共享访问需要加锁保护()。
int i = 0; void foo() { static int j = 0; int k = 0; i++; j++; k++; }
答案:i和j
解析:多线程调用时要进行保护时,主要是针对全局变量和静态变量的,函数内的局部变量不会受到影响。这里i是全局变量,j是局部静态变量,所以要进行保护。
15.在Linux 系统中,在运行一个程序时,程序中未初始化的全局变量会被加载到以下哪个内存段中?
答案:BSS
解析:
BSS(Block Started by Symbol):通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。特点是:可读写的,在程序执行之前BSS段会自动清0。所以,未初始的全局变量在程序执行之前已经成0了。
数据段(data segment):通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。
代码段(code segment/text segment):通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
16.
解析:选项B不对的原因,是运算符优先级的问题。
(volatile int *)0xaae0275c[0]=1 的意思是,先取出0xaae0275c地址处的值,然后把该值强制转换成int*类型,显然,该值是一个数值,不是变量,是右值,向该值再赋值1,就类似于 2=1; 这样的赋值,显然不对。 想改正确很容易,加上括号就OK了。 正确方式如下: ((volatile int *)0xaae0275c)[0]=1; 加上一对括号即可。