2022-09-16_命名空间
1. 命名空间的概念
下面关于C++命名空间描述错误的是( )【不定项选择】
A.命名空间定义了一个新的作用域。
B.std是C++标准库的命名空间。
C.在C++程序中,命名空间必须写成using namespace std;
D.我们可以自己定义命名空间。
【答案解析】C
==A.命名空间主要解决名字冲突,其作用就是定义一个新的作用域==
B.std是标准命名空间
C.还有std::xx 和using std::xx来使用标准库中的用法,所以不是必须写using namespace std
D.可以通过namespace space_name{};定义自己新的命名空间
2. 引用的概念
关于引用以下说法错误的是( )。(阿里巴巴2015笔试题)
A.引用必须初始化,指针不必
B.引用初始化以后不能被改变,指针可以改变所指的对象
C.不存在指向空值的引用,但是存在指向空值的指针
D.一个引用可以看作是某个变量的一个“别名”
E.引用传值,指针传地址
F.函数参数可以声明为引用或指针类型
答案解析
A.引用必须初始化,必须在定义引用时明确引用的是哪个变量或者对象,否则语法错误,指针不初 始化时值为随机指向
B.引用一旦定义时初始化指定,就不能再修改,指针可以改变指向
C.引用必须出示化,不能出现空引用,指针可以赋值为空
D.简单粗暴的引用理解可以理解为被引用变量或对象的"别名"
==E.引用表面好像是传值,其本质也是传地址,只是这个工作有编译器来做,所以错误==
(在博客:C++入门中提到,对于引用的底层也是通过指针实现的)
F.函数调用为了提高效率,常使用引用或指针作为函数参数传递变量或对象
2022-09-21_类的定义
3. class和struct的区别
在C++中的结构体是否可以有成员函数?( )
A.不可以,结构类型不支持成员函数
B.可以有
C.不可以,只有类允许有成员函数
【答案解析】B
C语言结构体不支持成员函数,但C++结构体支持,==其实class与struct本质没有区别,唯一区别在于默认时class的访问属性为私有,struct为公有==
4. this指针
this指针可以为空嘛?
【答案解析】可以,单纯的对this赋空是不可以的,不过可以强转直接赋空,不过一般不进行这样的操作
5. 构造/析构顺序
设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?( )
C c; int main() { A a; B b; static D d; return 0; }
A.D B A C
B.B A D C
C.C D B A
D.A B D C
【答案解析】B
1、类的析构函数调用一般按照构造函数调用的相反顺序进行调用,但是要注意static对象的存在,因为static改变了对象的生存作用域,需要等待程序结束时才会析构释放对象
2、全局对象先于局部对象进行构造
3、局部对象按照出现的顺序进行构造,无论是否为static
4、所以构造的顺序为 c a b d
5、析构的顺序按照构造的相反顺序析构,只需注意static改变对象的生存作用域之后,会放在局部对象之后进行析构
6、因此析构顺序为B A D C
6. 拷贝构造函数特点
拷贝构造函数的特点是( )
A.该函数名同类名,也是一种构造函数,该函数返回自身引用
B.该函数只有一个参数,是对某个对象的引用
C.每个类都必须有一个拷贝初始化构造函数,如果类中没有说明拷贝构造函数,则编译器系统会自动生成一个缺省拷贝构造函数,作为该类的保护成员
D.拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象
【答案解析】D
A.拷贝构造函数也是一构造函数,因此不能有返回值
B.该函数参数是自身类型的对象的引用
==C.自动生成的缺省拷贝构造函数,作为该类的公有成员,否则无法进行默认的拷贝构造==
为啥自动生成的一定是缺省拷贝构造函数呢?因为拷贝构造函数是一定要带参数的
D.用对象初始化对象这是拷贝构造函数的使命,故正确
2022-10-09_构造函数和析构函数
7. 前置++/后置++(运算符重载)
已知表达式++a中的"++"是作为成员函数重载的运算符,则与++a等效的运算符函数调用形式为( )
A.a.operator++()
B.a.operator++(0)
C.a.operator++(int)
D.operator++(a,0)
【答案解析】A
A.正确
==B.operator++()传递了整形参数(对于前置++是不能传递参数的),故为后置++,错误==
C.调用函数传递类型,导致语法错误
D.参数过多,语法错误
2022-10-10_构造函数初始化列表
8. 初始化列表的初始化对象
有一个类A,其数据成员如下: 则构造函数中,成员变量一定要通过初始化列表来初始化的是:( )
class A { ... private: int a; public: const int b; float* &c; static const char* d; static double* e; };
A.a b c
B.b c
C.b c d e
D.b c d
E.b F.c
【答案解析】B
A.a是不同数据成员,可以通过构造函数进行赋值
B.正确,常量以及引用只能通过初始化列表初始化
C.d,e是静态成员,只能在类外初始化
D.d是静态成员,只能在类外初始化
E.b常量只能通过初始化列表初始化,但不是最佳答案
F.c引用只能通过初始化列表初始化,但不是最佳答案
2022-10-12_构造函数初始化列表
9. 友元函数性质
下面有关友元函数与成员函数的区别,描述错误的是?( )
A.友元函数不是类的成员函数,和普通全局函数的调用没有区别
B.友元函数和类的成员函数都可以访问类的私有成员变量或者是成员函数
C.类的成员函数是属于类的,调用的时候是通过指针this调用的
D.友元函数是有关键字friend修饰,调用的时候也是通过指针this调用的
【答案解析】 D
A.==友元函数不是类的成员函数==,就相当于你的朋友再亲密也不是你的家人
==既然不是类成员函数,那和普通成员函数调用一样,不需要通过对象调用==
B.友元的目的就是为了访问类的私有数据,成员函数可以直接访问类的私有数据
C.类的成员函数属于类,调用时其内部数据会通过this指针来调用
==D.友元函数不具备this指针,更谈不上通过this调用,故错误==
10. 日期累加
2022-10-13_数据内存分布
11. 内存管理分配堆栈
下面有关c++内存分配堆栈说法错误的是( )
A.对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制
B.对于栈来讲,生长方向是向下的,也就是向着内存地址减小的方向;对于堆来讲,它的生长方向是向上的,是向着内存地址增加的方向增长
C.对于堆来讲,频繁的 new/delete 势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题
D.一般来讲在 32 位系统下,堆内存可以达到4G的空间,但是对于栈来讲,一般都是有一定的空间大小的
【答案解析】D
==A.栈区主要存在局部变量和函数参数,其空间的管理由编译器自动完成,无需手动控制,堆区是自己申请的空间,在不需 要时需要手动释放==
B.栈区先定义的变量放到栈底,地址高,后定义的变量放到栈顶,地址低,因此是向下生长的,堆区则相反
C.频繁的申请空间和释放空间,容易造成内存碎片,甚至内存泄漏,栈区由于是自动管理,不存在此问题
D.32位系统下,==最大的访问内存空间为4G,所以不可能把所有的内存空间当做堆内存使用==,故错误
12. malloc和new的区别
下面有关malloc和new,说法错误的是? ( )
A.new 是创建一个对象(先分配空间,再调构造函数初始化), malloc分配的是一块内存
B.new 初始化对象,调用对象的构造函数,对应的delete调用相应的析构函数,malloc仅仅分配内存,free仅仅回收内存
C.new和malloc都是保留字,不需要头文件支持
D.new和malloc都可用于申请动态内存,new是一个操作符,malloc是是一个函数
【答案解析】C
A.new会申请空间,同时调用构造函数初始化对象,malloc只做一件事就是申请空间
B.new/delete与malloc/free最大区别就在于是否会调用构造函数与析构函数
==C.需要头文件malloc.h,只是平时这个头文件已经被其他头文件所包含了,用的时候很少单独引入,故错误==
==malloc是需要引用头文件的通常是==#include <stdlib.h>
D.new是操作符,malloc是函数
13. delete内置类型
使用 char* p = new char[100]申请一段内存,然后使用delete p释放,有什么问题?( )
A.会有内存泄露
B.不会有内存泄露,但不建议用
C.编译就会报错,必须使用delete [] p
D.编译没问题,运行会直接崩溃
【答案解析】B
==对于内置类型,此时delete就相当于free,因此不会造成内存泄漏==
编译不会报错,建议针对数组释放使用delete[],如果是自定义类型,不使用方括号就会运行时错误
2022-10-17_ 模板
14. 采用模板的原因
下面有关C++中为什么用模板类的原因,描述错误的是? ( )
A.可用来创建动态增长和减小的数据结构
B.它是类型无关的,因此具有很高的可复用性
C.它运行时检查数据类型,保证了类型安全
D.它是平台无关的,可移植性
【答案解析】C
==A.模板可以具有非类型参数,用于指定大小,可以根据指定的大小创建动态结构==
B.模板最重要的一点就是类型无关,提高了代码复用性
==C.模板运行时不检查数据类型,也不保证类型安全,相当于类型的宏替换,故错误==
D.只要支持模板语法,模板的代码就是可移植的
15. 模板概念
下列关于模板的说法正确的是( )
A.模板的实参在任何时候都可以省略
B.类模板与模板类所指的是同一概念
C.类模板的参数必须是虚拟类型的
D.类模板中的成员函数全是模板函数
【答案解析】D
A.不一定,参数类型不同时有时需要显示指定类型参数
==B.类模板是一个类家族,模板类是通过类模板实例化的具体类==
C.C++中类模板的声明格式为template<模板形参表声明><类声明>,并且类模板的成员函数都是模板函数
==D.正确,定义时都必须通过完整的模板语法进行定义==
16. 模板声明的正确形式
下列的模板声明中,其中几个是正确的( )
1) template
2) template
3) template
4) template
5) template
6) template
7) template
8)
【答案解析】 4 6 7
1.模板语法错误
2.没有关键字class或typename指定类型,
3.T2缺少class或typename
4,6,7为正确声明
5.T2缺少class或typename
8.缺少template
2022-10-26_string的特性及使用
17. c_str的作用
关于代码输出正确的结果是()(vs2013环境下编译运行)
int main(int argc, char* argvl) { string a = "hello world"; string b = a; if (a.c_str() == b.c_str()) { cout << "true" << endl; } else cout << "false" << endl; string c = b; c = ""; if (a.c_str() == b.c_str()) { cout << "true" << endl; } else cout << "false" << endl; a = ""; if (a.c_str() == b.c_str()) { cout << "true" << endl; } else cout << "false" << endl; return 0; }
【答案解析】A
a 和 b的值虽然相同,==但是a.c_str()==b.c_str()
比较的是存储字符串位置的地址,a和b是两个不同的对象,内部数据存储的位置也不相同== 因此不相等,后面c="",a=""与b对象都没有任何的影响,所以都不相等18. reserve缩小
下面程序的输出结果正确的是( )
int main() { string str("Hello Bit."); str.reserve(111); str.resize(5); str.reserve(50); cout << str.size() << ":" << str.capacity() << endl; return 0; }
【答案解析】C
str.reserve(111); //调整容量为 111
str.resize(5); //调整元素个数为 5
==str.reserve(50); //调整容量为 50,由于调整的容量小于已有空间容量,故容量不会减小==
所以size = 5 capacity = 111
==如果reserve 的值小于vector原先的容量, 不会更改的==
19. 数据越界的判断
【答案解析】
/*
*思路:
* 1. 要考虑正负数
* 2. 要考虑数据是否溢出
*/
class Solution {
public:
int StrToInt(string str)
{
int len = str.size();
int flag = 1;
if (len == 0)
return 0;
const char* cstr = str.c_str();
if (cstr == NULL)
return 0;
int i = 0;
if (cstr[i] == '+')
{
i++;
flag = 1;//如果str[i]为'+',str[i]顺序后移,并令标志flag为1,表示为正数
}
else if (cstr[i] == '-')
{
i++;
flag = -1;//如果str[i]为'-',str[i]顺序后移,并令标志flag为-1,表示为负数
}
long long num = 0;
while (cstr[i] != '\0')
{
if (cstr[i] >= '0' && cstr[i] <= '9')
{
//每遍历一个在0-9间的字符,就将其输入到num中
num = num * 10 + (cstr[i] - '0');//下一次输入到num中时要加上上一次*10的结果,即上一次的数左移一位(十进制下)
//如果数据溢出,则返回0
if ((flag > 0 && num > 0x7fffffff) || (flag < 0 && num>0x80000000))
return 0;
i++;
}
else
{
return 0;
}
}
if (flag < 0)
num = num * -1;
return (int)num;
}
};