1. 在C++语言中,下列说法正确的是(D)
A inline函数表示编译器一定会将函数体直接插入到调用此函数的地方,这样可以加快程序速度
B 局部变量和全局变量不能重名
C 静态局部变量内存是运行期分配的,存储在堆栈区
D C++不是类型安全语言
分析:A选项,内联函数与其他普通函数的区别是,内联函数在生成可执行文件时,其代码块是直接嵌入到调用处的,以此减少函数调用的开销提高程序性能,它与宏很类似。但是,C++ primer 上明明白白的写过这么一句话:内联说明(inlinespecification)对于编译器来说只是一个建议,编译器可以选择忽略这个建议。也就是说,是否以嵌入式方式存在,是由编译器决定的,并不是一定。
B选项,因为局部变量和全局变量是可以重名的,而且一般来说在某个函数体内,局部变量是会覆盖全局变量的。
C选项,静态局部变量存在静态存储区,而局部变量存储在堆栈区,确切的说是栈区。
D选项,什么叫类型安全的语言?就C++而言,我们可以把0作为false,非零作为true。一个函数就算是bool类型的,我们还是可以返回int类型,并且自动把0转化成false,非零转化成true。相比之下java不能把int类型转化成bool类型。所以java是一种类型安全的语言,而C++并不是。
补充:
内联说明只是向编译器发出一个请求,编译器可以选择忽略这个请求。一般来说,内联机制用于优化规模较小、流程直接、频繁调用的函数。
C/C++里面有指针,而指针在使用和引用的时候,容易出错。而Java就没有指针,C/C++不是类型安全的。
2. 若变量已正确定义为float类型,要通过输入函数scanf(“%f%f%f”,&a,&b,&c)给a赋值10,b赋值22,c赋值33,以下不正确的输入形式(BC)
A 10 22 33 B 10.0,22.0,33.0 C 10.0 22.0,33.0 D 10 22 33
分析:在VS2013上用scanf测试,空格、换行和制表符都可以用来分割,但是逗号不行。
3. C++中关于堆和栈的说法,哪个是错的(C)
A 堆的大小仅受操作系统的限制,栈的大小一般较小
B 在堆上频繁调用new/delete容易产生内存碎片,栈没有这个问题
C 堆和栈都可以静态分配
D 堆和栈都可以动态分配
分析: A,堆和栈的大小都可以设置,栈一般只有几KB。堆上内存由程序员分配,但是堆的最大值由操作系统分配。
B,堆在动态分配时,要申请连续的内存空间,释放后会产生碎片。
C,静态分配是指在编译阶段就能确定大小,由编译器进行分配,堆不可以进行静态分配,堆的申请都是在执行过程中进行的。
D,堆是使用malloc()、calloc()、realloc()等函数动态分配的,而使用alloca()函数可以动态分配栈的内存空间,释放的时候由编译器自己释放。
关于堆栈学习,可以参考点击打开链接
4. 1<<3+2的值是 32
分析:运算符+的优先级高于左移<<,所以先计算2+3=5;1<<5等于二进制100000=32(十进制)
5. scanf VS. gets
1).不同点: scanf不能接受空格、制表符Tab、回车等; 而gets能够接受空格、制表符Tab和回车等;
2).相同点: 字符串接受结束后自动加'\0'。
6. 分析下列程序:
void Func(charstr_arg[2]) {
int m=sizeof(str_arg);
int n=strlen(str_arg);
cout<<m<<endl<<n<<endl;
}
int main(void) {
char str[]=”hello”;
Func(str);
}
分析:数组作为函数参数传递时退化为指针,所以sizeof的值为4,而strlen只是对传递给Func函数的那个字符串求长度,跟str_arg中的那个2没有任何关系,即使把2改成200也不影响strlen的输出结果。
7. 设m和n都是int型,那么以下for循环语句,
#include<iostream>
using namespacestd;
int main() {
int m,n;
for(m=0,n=-1;n=0;m++,n++)
n++;
cout<<n;
}
分析:循环体一次也不执行。
在C/C++中,n=0代表当前条件为false,不执行循环体,n只要不是0,当前条件为true,无限循环
。在JAVA中, 会提示“Type mismatch: cannot convert from int to boolean”这样的错误,编译不通过。
8. 重载:必须同名函数,必须参数表不同(包括参数个数不同;参数类型不同;或者参数个数与类型都不同),与返回值类型无关。因为判断方法重载的方法主要是根据方法的参数不同来判定的。
9.若Myclass是一个类名,其有如下语句序列:
Myclass c1,*c2;
Myclass *c3=newMyclass;
Myclass &c4=c1;
上面语句序列调用构造函数个数是(2)
分析:只有c1和c3会调用构造函数。
c2是一个没有分配内存的指针,用来动态描述对象的,不需要类的定义,即不会调用类的构造函数。
C3的右边新创建一个对象会调用构造函数,但是注意这里的赋值运算符不是类中的赋值运算符,而是普通的赋值运算符。因此没有调用赋值构造函数。如char *p=”hello”;只是把指针p指向了字符串,而不是赋值给指针p。所以此处只是将指针指向新new出的内容,并没有发生拷贝。这里面的new创建出一个临时变量,对c3初始化,相当于把临时变量扶正,和赋值不一样,如Myclass c3;c3=new Myclass;
c4只是一个c1的别名,c4就是c1,不占空间。
9. 下面程序段包含4个函数,其中具有隐含this指针的(f4)
int f1();
class T {
public :static intf2();
private :friendint f3();
protect:int f4();
};
分析:静态成员函数属于整个类拥有,没有this指针;
友元函数不是这个类的成员,没有;
类的非静态成员函数有this指针;每个成员函数,包括构造函数和析构函数都有一个this指针;
10. 下面有关C++ traits,说法正确的是(ABCD)
A 一个traits包括了enum、typedef、模板偏特化
B typedef定义了各个类的各自不同的类型定义
C 模板偏特化用于实现各个类的不同功能
D 当函数,类或者一些封装的通用算法中的某些部分会因为数据类型不同而导致处理或逻辑不同,traits会是一种很好的解决方案。
分析:traits是C++的自动类型判断。
出发点:因为C++没有反射的机制。所以利用traits来完成。
大量使用场景:STL(STL中大量使用traits来区分类别。注释POD标量类型和类类型的构造函数等)
机制:
template <typename T> //泛化
struct is_void {
static const bool value = false;
};
template <> //特化
struct is_void<void> {
static const bool value = true;
};
int main(){
std::cout<<is_void<int>::value;
std::cout<<is_void<void>::value;
}
根据模板的自动类型推导。在调用void的时候会使用特化版本。而其他类型呢?对,使用泛化版本。
这样就巧妙的区分了不同的类型。这就是traits的基本原理。
C++11中提供了大量的traits,可参考: