首页 > 代码库 > C++考点问答题
C++考点问答题
实参和形参的区别是什么?
答:形参是“形式化的参数”,相当于函数中的自变量,?而实参是形参的初始值, 相当于自变量所取的值。
请指出下列函数哪个有错误
(a) int f() { string s;
// ...
return s; }
(b) f2(int i) { /* ... */ }
(c) int calc(int v1, int v1) /* ... */ }
(d) double square(double x) return x * x;
答:(a)错误在于f()返回类型为int,所以不可以返回string型的s.可改为:
string f() { string s;
// ...
return s; }
(b)错误在于没有返回类型,可改为:
void f2(int i) { /* ... */ }
(c)错误在于函数体的括号缺左半部分。可改为:
int calc(int v1, int v1) {/* ... */ }
(d)错误在于函数体没有使?用括号括起来,可改为:
double square(double x) { return x * x; }
说明形参、局部变量及局部静态变量的区别。编写一个函数,同时用到这三种形式。
答: 形参相当于函数的自变量,其作用域为函数声明与定义的范围。 局部变量是在函数体中所声明并定义的变量,其作用域在该函数体内。局部静态变量为在函数体中声明的变量,但其作?用域是在此函数体及函数体后?面程序段落中,生物周期自它被声明之时起,?至整个程序结束终?止。
函数?示例及变量说明如下:
void func(int intpara) //intpara为形参。
{
int localvar; //localvar为局部变量。
static int localstavar; //localstavar为局部静态变量。
return;
}
假设T是某种类型的名字,说明以下两个函数声明的区别:?一个是 void f(T),另?一个是void f(&T)。
答:前者说明其只有一个形参,且类型为T.以一个类型为T的实参调?用该函数,调?用过程不改变实参本?身的值。 后者说明其只有?个形参,且是一个引?用型形参,被引?用变量类型为T.以类型为T的实参调?用该 函数时,实参在函数作?用域内可能被改变。
为下?的函数编写函数声明,从给定的名字中推测函数具备的功能。
(a)名为compare的函数,返回布尔值,两个参数都是matrix类的引?用。
(b)名为change_value的函数,返回vector<int>的迭代器,有两个参数:?个是int,另?个是 vector<int>的迭代器。
bool compare(matrix &mat1, matrix &mat2); //该函数功能应是比较两个matrix类的对象的大小。
vector<int>::iterator change_value(int val, vector<int>::iterator iter);//功能应是更动vector中指定位置的值,并返回对应迭代器。
在error_msg函数的第二个版本中包含有Errcode类型的参数,其中循环内的elem是什么类型?
答:elem是const std::string&类型。
编写?个函数的声明,使其返回数组的引?用并且该数组包含10个string对象。不要使?用位置返回类型、decltype或者类型别名。
答:string (&func())[10]
说明在下面的每组声明中第?条声明语句是何含义。如果有非法的声明,请指出来。
Int calc(int,int);
答: (a)中第二句非法,它对第一句中的函数进?行了重复声明。
(b)中第二名是非法声明,因为它与第一句形参完全相同,返回类型不同;
(c)中第二句合法。
下面的哪个调用是非法的?为什么?哪个调?用虽然合法但显然与程序员的初衷不符?为什么? char *init(int ht, int wd = 80, char bckgrnd = ‘ ‘); (a) init();? (b) init(24,10);? (c) init(14, ‘*‘);
答: (a)非法,因为第一个形参并?无默认初始化参数,因此?无法执行该调?用。
(b)合法。
(c)虽然合法,但与程序员初衷不符。因为该调?用执?行时向14被传递为ht,’*’被传递给wd,bckgrnd 被默认初始化为空字符。程序员的期望是wd被传值14.
说明下?循环的含义,它对assert的使?合理吗? string s;? while (cin >> s && s != sought) { } // empty body assert(cin);
答:代码中对assert的使用是不合理的。assert适于检查不能发生的条件,?而该句中只要用户有 输入cin便为true,assert就将发生。 将其改为assert(s == sought)更为合理。
已知有第217页对函数f的声明,对于下面的每一个调用列出可?函数。其中哪个函数是最佳匹配?如果调?用不合法,是因为没有可匹配的函数还是因为调用具有?义性? (a) f(2.56, 42) (b) f(42) (c) f(42, 0) (d) f(2.56, 3.14)
答: (a)void f(int,int)与void f(double, double = 3.14)为可行函数。没有最佳匹配,调用不合法,因为 调用具有?义性。 (b)void f(int)与void f(double, double = 3.14)为可行函数。前者是最佳匹配。 (c)void f(int,int)与void f(double, double = 3.14)为可行函数。前者为最佳匹配。 (d)void f(int,int)与void f(double, double = 3.14)为可行函数。后者为最佳匹配。
编写函数的声明,令其接受两个int形参并且返回类型也是int;然后声明一个vector对象,令其元素是指向该函数的指针。
Int f(int,int);
Using pF=declatype(f)*;
Vector<pF>vec;
下?面哪些句?子是合法的?如果有不合法的句?子,请说明为什么? (a) const int buf; (b) int cnt = 0; (c) const int sz = cnt; (d) ++cnt; ++sz;
答: (a)不合法,因为const对象?一旦创建必须被初始化; (b)合法。 (c)合法; (d)不合法,sz是常量,其值不能改变。
下?面的哪些初始化是合法的?请说明原因。 (a) int i = -1, &r = 0; (b) int *const p2 = &i2; (c) const int i = -1, &r = 0; (d) const int *const p3 = &i2; (e) const int *p1 = &i2; (f) const int &const r2; (g) const int i2 = i, &r = i;
答: (a)不合法,r是引?用,必须在声明语句中定义它所被绑定的对象; (b)只要前?面已经定义i2为int型变量,则该句合法,p2是?一个常量指针,它指向i2. (c)合法。 (d)只要i2在该句前已被声明为int类型,则该句合法。 (e)若i2是int类型,则该句合法。 (f)不合法,r2是对?一个int类型常量的常量引?用,它必须被初始化。 (g)若i已被声明为int类型,则此句合法,否则不合法。
假设已有上?个练习中定义的那些变量,则下?面的哪些语句是合法 的?请说明原因。 (a) i = ic; (b) p1 = p3; (c) p1 = ? (d) p3 = ? (e) p2 = p1; (f) ic = *p3;
答: (a)合法,前提是ic已被正确定义了(上例中ic被声明为int常量,但未被初始化,语句非法。) (b)不合法:p3是指向常量int的常量指针,?而p1是普通int类型指针。 (c)不合法,p1是普通int型指针,?而ic是int型常量。 (d)不合法,p3是常量指针,它应该在声明时被初始化,此后不能再赋值。 (e)不合法,p2是常量指针,不能通过拷?贝的?方法对其赋值。 (f)不合法,ic是int类型常量,只能在声明语句中初始化,此后不能通过拷贝完成赋值。
对于下?面的这些语句,请说明对象被声明成了顶层const还是底层 const? const int v2 = 0; int v1 = v2; int *p1 = &v1, &r1 = v1; const int *p2 = &v2, *const p3 = &i, &r2 = v2;
答: v2是顶层const(因为它自己是常量); v1不是const; p1指向的v1不是const,它自己也不是const,所以既不是顶层const也不是底层const; r1是v1的引用,而v1不是const,因此r1也不是const; p2指向const int,而它本?身不是const,所以它是底层const; p3自己是常量指针,指向常量int数据,因此p3既是顶层const,也是底层const(前提是 i已被定义为int常量); r2是int型常量v2的引用,因此它是底层const.
下面的代码是否合法?如果非法,请设法将其修改正确。 int null = 0, *p = null;
答: 不合法,p是指针,需指向?个int型变量的地址。可改为: int null = 0, *p = &null;
如果想定义?个含有10个元素的vector对象,所有元素的值都是42, 请列举出三种不同的实现?方法。哪种?方法更好呢?为什么?
答: 第?种方法:vector<int> vec1(10,42); 第?种方法:vector<int> vec2{42,42,42,42,42,42,42,42,42,42} 第三种方法:使?用如下程序段: vector<int> vec3; for(int i=0; i <=9; ++i) vec3.push_back(42); 第一种?方法最好,因为它比较简洁:)
?分搜索程序中,为什么用的是mid = beg + (end - beg) / 2,?非mid = (beg + end) /2;?
答:因为迭代器没有加法运算。
下列数组中元素的值是什么?
string sa[10]; int ia[10]; int main() { string sa2[10]; int ia2[10]; }
答: sa中有10个空字符串; ia中有10个0; sa2与ia2由于在函数内部,没被初始化时,是未定义的。
相比于vector来说,数组有哪些缺点,请列举一些。
答: 数组不够灵活,它们的维度是固定的,因此要使?用数组时事先要仔细设计其维度,特别 是维度不能?小于所需。 也是由于维度固定,数组不能通过push_back类函数?自由填加元素。
指出下面代码中的索引错误。 constexpr size_t array_size = 10; int ia[array_size]; for (size_t ix = 1; ix <= array_size; ++ix) ia[ix] = ix;
答: 这组语句对一个10维数组进?行赋值,它从ia[1]即第二个元素开始赋起,这没有问题。问题在于它的最后一个赋值一句是对ia[10]进?行赋值,?而这个元素是不存在的。
根据4.12节中的标表,在下述表达式的合理位置添加括号,使得添加 括号后运算对象的组合顺序与添加括号前?一致。
(a) *vec.begin() (b) *vec.begin() + 1
答: (a)*(vec.begin()); (b)(*(vec.begin()))+1;
C++语言没有明确规定大多数二元运算符的求值顺序,给编译器优化 留下了余地。这种策略实际上是在代码?生成效率和程序潜在缺陷之间进?行了权衡, 你认为这可以接受吗?请说出你的理由。
答: 这是可以接受的。当C++中采?用这种策略时,编译器可根据需要来即时抉 择求值顺序,从?而实现尽可能?高的执?行效率,程序员若避免写作次序影响 求值结果的代码,可规避程序的潜在执?行缺陷。 与C++不同,JAVA中采取确定执?行次序的策略,此时牺牲了可能的?高效, 但获得了程序结构的清晰与明确。 两者所追求的??目标不同,因此所采取的策略也不同。
解释在下面的if语句中条件部分的判断过程。
const char *cp = "Hello World"; if (cp && *cp)
答:先计算cp的bool值,由于cp是?非空指针,因此它所对应的bool值为 true,因此再计算*cp的bool值,其亦?非0,对应bool值为true,因此条件部 分运算结果为true.
尽管下面的语句合法,但它们实际执行的行为可能和预期并不?一样, 为什么?应该如何修改? (a) if (p = getPtr() != 0) (b) if (i = 1024)
答:(a) 赋值运算符优先级较低,因此此句等价于if( p = ( getPtr() != 0)), 作者预 期做的条件判断应是判断p= getPtr()与0是否相同,因此可将此句改为: if ((p = getPtr()) != 0) (b)=是赋值运算符?而不是相等运算符,因此此句应改为if (i == 1024)
假设ptr的类型是指向int的指针、vec的类型是vector<int>、ival的类 型是int,说明下?面的表达式是何含义?如果有表达式不正确,为什么?应该如何 修改? (a) ptr != 0 && *ptr++ (b) ival++ && ival (c) vec[ival++] <= vec[ival]
答: (a)该式非法。 该式等价于(ptr != 0) && (*(ptr++))该式当ptr不是空指针 且ptr所指元素?非0时值为true,否则为false,运算之后将ptr向前移动?一个位置,而由于ptr是指向int类型的指针?无法进?行?自增运算,因此该式?非法。可做如下修改 : ptr != 0 && (*ptr)++ (b)该式将产?生未定义结果,其运算过程中明确的是先计算&&左侧的表达式值, 当其为真时计算右侧的值。此处假设ival为-1,则其所对应的bool值为true,此时 ival先执?行左侧的?自增计算还是先执?行右侧的bool值计算是不确定的,?而不同的 运算顺序将影响最后结果的得出。不?鼓励使?用类似的表达式。(可参考 C++2011标准?文档(References??目录下The C++ Standard – ANSI ISO-IEC 14882-2011.pdf 中的1.9节)可做如下修改:ival && (ival + 1); (c)该式将产?生未定义结果,原因同(b),可改为vec[ival] <= vec[ival +1];
假设iter的类型是vector<string>::iterator,说明下?面的表达式是否合 法。如果合法,表达式的含义是什么?如果不合法,错在何处? (a) *iter++; (b) (*iter)++; (c) *iter.empty() (d) iter->empty(); (e) ++*iter; (f) iter++->empty();
答: (a)合法,后置递增运算符比*优先级?高,因此该表达式等价于*(iter++),?首先计算 iter所指元素值,然后将iter向前移动?一个位置,使其指向下?一个元素; (b)不合法,*iter是string类型,无法进行++运算。 (c)不合法,因为.的优先级?高于解引?用运算符,因此先计算iter.empty(),?而迭代 器类型没有名为empty的成员函数。 (d)合法,等价于(*iter).empty(),由于*iter是string类型,因此该表达式正确。 (e)不合法,*iter为string类型,不适合使?用++运算。 (f)合法,先进行(*iter).empty运算,再将iter向后移动一个位置。
在本节关于测验成绩的例子中,如果使用unsigned int作为quiz1的类型会发生什么情况?
答:若所用系统中int使?用16位存储,则?无法容纳全班同学的成绩数据,不能满足表达需要。
下列表达式的结果是什么?
unsigned long ul1 = 3, ul2 = 7; (a) ul1 & ul2 (b) ul1 | ul2 (c) ul1 && ul2 (d) ul1 || ul2
答:(a)3 (b)7 (c)true (d)true
推断下面代码的输出结果并说明理由。实际运行这段程序,结果和你 想象的?样吗?如果不?样,为什么? int x[10]; int *p = x; cout << sizeof(x)/sizeof(*x) << endl; cout << sizeof(p)/sizeof(*p) << endl;
答:此处sizeof(x)应为数组x所占空间的大小,sizeof(*x)为其?首元素所占空间的大小,因此两者相除,返回数组中元素个数,即第?句应输出10. sizeof(p)为整形指针所占空间的大小(int的地址以long型进行存储,在本人所用系统中该值为 64),*p指向数组x的?首个元素,sizeof(*p)为整形数值所占空间?大?小,为32位,因此第二句输出为2.
解释下面这个循环的含义。
constexpr int size = 5; int ia[size] = {1,2,3,4,5}; for (int *ptr = ia, ix = 0; ix != size && ptr != ia+size; ++ix, ++ptr) { /* . . . */ }
答:该循环的含义为:自ptr指向数组首部、下标为0的元素起,只要下标尚在合理范围内(即小于数组size时)且指针还指在数组有效元素时,执行循环体中的内容,每次循环体执?行结束时, 将下标加1,指针后移一个元素,继续判断上述循环条件是否为true...
假设有如下的定义,
char cval; int ival; unsigned int ui; ?oat fval; double dval; 请回答在下面的表达式中发?生了隐式类型转换吗?如果有,指出来。 (a) cval = ‘a‘ + 3; (b) fval = ui - ival * 1.0; (c) dval = ui * fval; (d) cval = ival + fval + dval;
答:(a)’a’为字符型字?面值,需将其转为int型,与3相加后,所得结束为int型,再 将其转为char类型。 (b)ival先转为double类型与1.0相乘,所得结果为double型,将ui转为double型 参与运算,最后所得结果为double类型,将其转为?oat型。 (c)ui转为?oat类型,与fval相乘,所得?oat类型转为double. (d)ival转为?oat类型与fval相加,将所得结果由?oat型转为double型与dval相加, 所得结果转为char类型。
用命名的强制类型转换改写下列旧式的转换语句。
int i; double d; const string *ps; char *pc; void *pv; (a) pv = (void*)ps; (b) i = int(*pc); (c) pv = &d; (d) pc = (char*) pv;
答: (a)pv =static_cast<void *> (const_cast<string *>(ps)); (b)i = static_cast<int>(*pc); (c)pv = static_cast<void *>(&d); (d)pc = reinterpret_cast<char *>(pv);
什么是空语句?什么时候会用到空语句?
答:空语句即是只有?一个分号的语句。 当程序段落中语法上需要?一个语句而语义上(逻辑上)并不需要时可使用空语句。
说明?nd_char函数中的三个形参为什么是现在的类型,特别说明为什 么s是常量引?用而occurs是普通引用?为什么s和occures是引用类型而c不是? 如果令s是普通引用发生什么情况?如果令occurs是常量引用会发生什么情况?
答:使用引用类型可以避免字符串拷备,因此将s设为引用类型。将s设为常量类型,是由于在该 函数作用域内并不需要对s进行改变,设为常量可避免不必要的对s潜在写操作。 c是字符类型,所占存储空间较少,因此不必将其设为引用类型。 occurs设为引用类型的原因时,希望可以通过它来返回不在return语句内的信息。而它在在函数 作用域内可能会改变,因此需将其设为普通引用。 若s是普通引用则?方面该函数?无法使用常量字符串实参来进行调用,另?方面也带来了在函数体内可能被改变的风险。 如果将occurs设为常量引用,则?无法用它返回字符c出现的次数。
在类的定义中对于访问说明符出现的位置和次数有限定吗?如果有 是什么?什么样的成员应该定义在public说明符之后,什么样的成员应该定义 在private说明之后?
答:对访问说明符的位置与次数没有限制。 可以被类外访问到的成员定义在public后。 只能被类内访问的成员定义在private后。
使用class和struct时有区别吗?如果有,是什么?
答:有区别,默认访问权限不同,struct中成员的默认访问权限是 public,class中成员的默认访问权限是private。
封装是何含义?它有什么用处?
答:在类的定义中,封闭即指其中private的部分隐藏了实现细节。 通过封闭可将功能的使?用与实现相分离,使得系统可以更好地应?用需要的变化
在你的Person类中,你将那些成员声明成public的?哪些声明成 private的?解释你这样做的原因。
答:将构造函数, getName(), getAddress()声明为public的。将name与 address声明为private的。 前三种成员函数需被类外调?用,因此需声明为public. 后两个数据成员只准许类内访问,实现封闭,因此需声明为private.
友元在什么时候用?请分别列举出使?用友元的利弊。
答:类外需要访问private的成员时需将之设置为本类的友元。 其好处是实现了一定的灵活性,满?足了特定的访问需要。 坏处是突破了类的封闭性。增加了维护难度。
什么是类的静态成员?他有何优点?静态成员与普通成员有何区 别? 答:直接与类本?身关联?而不是与每个对象关联的成员是类的静态成员。 使?用静态成员,可以避免各个对象的公共元素被重复定义,当该元素变化 时,也只需在?一个位置进?行修改。适当地使?用静态成员,可以提?高程序开 发的效率和可维护性。 静态成员存在于任何对象之外。普通成员存在于每个对象中。 针对静态成员不可以使?用this指针来进行调用,针对普通成员却可以。
C++考点问答题