1、空类占多大内存空间?
1个字节
2、explicit作用:
关闭函数类型的自动类型转换功能(防止隐式类型转换的发生)
3、深拷贝与浅拷贝问题:
浅拷贝:简单的赋值拷贝操作;
深拷贝:在堆区重新申请空间,惊醒拷贝操作;
浅拷贝常见的问题:堆区数据重复释放问题;
4. 线程池工作原理
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
线程池的作用:
主要作用:避免创建过多的线程时引发的内存溢出问题。因为创建线程还是比较耗内存的,通常来说创建一个线程会默认分配1M的内存。
线程池的主要优势:
降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
线程池的实现原理:
-
线程池的组成主要分为3个部分,这三部分配合工作就可以得到一个完整的线程池:
任务队列,存储需要处理的任务,由工作的线程来处理这些任务
- 通过线程池提供的API函数,将一个待处理的任务添加到任务队列,或者从任务队列中删除
- 已处理的任务会被从任务队列中删除
- 线程池的使用者,也就是调用线程池函数往任务队列中添加任务的线程就是生产者线程
工作的线程(任务队列任务的消费者) ,N个
- 线程池中维护了一定数量的工作线程, 他们的作用是是不停的读任务队列, 从里边取出任务并处理
- 工作的线程相当于是任务队列的消费者角色,
- 如果任务队列为空, 工作的线程将会被阻塞 (使用条件变量/信号量阻塞)
- 如果阻塞之后有了新的任务, 由生产者将阻塞解除, 工作线程开始工作
管理者线程(不处理任务队列中的任务),1个
- 它的任务是周期性的对任务队列中的任务数量以及处于忙状态的工作线程个数进行检测
- 当任务过多的时候, 可以适当的创建一些新的工作线程
- 当任务过少的时候, 可以适当的销毁一些工作的线程
- 它的任务是周期性的对任务队列中的任务数量以及处于忙状态的工作线程个数进行检测
5. 字符串的输入
5.1 C标准输入:
gets(): 可读取一整行输入,遇到换行符自动丢弃;gets()
不检查数组空间是否够用,会有缓冲区溢出的情况,造成内存不安全;与puts()结合使用,(不推荐);
fgets(): 从指定输入流读取一行,输入可以是stdin
,也可以是文件流,使用时需要显式指定所有空格、Tab等空白字符均被读取,不忽略。会自动在字符串末尾加上\0
结束符;函数读到n-1
个字符(包括换行符\n
)就会停止,并在末尾加上\0
结束符。剩余字符将残留在缓冲区。fgets(str, sizeof(str), stdin)(推荐),与fputs()结合使用;
gets_s(): 与fgets()类似,但不会读取换行符,而是将其丢弃。从标准输入中读取数据,无需第三个参数;
scanf(): 读取字符串时,遇到空格就停止读入(空白符可以是空格(space)、制表符(tab)和新行符 (newline))。只可以读取一个单词;scanf("%10s", name);表示只读取十个字符,遇空格就停止;
fgetc():
getchar(): getchar()
实际上也由fgetc()
宏定义而来,只是默认输入流为stdin
。
5.2 C标准输出:
printf(): 按照特定格式将stdout
缓冲区的内容打印到终端。
puts(): 传入字符串地址,在输出末尾会自动添加换行符;
putchar(): 该函数打印它的参数。putchar(ch);等价于printf("%c",ch);
5.3 C++标准输入
wcin:用来处理宽字符类型wchar_t的输入;
cin: 与scnaf类似,在读取字符串时,遇到第一个空格符便停止读取,下一次读取会从上一次结束处继续读取;
- cin.fail()==false; //未检测到文件结尾
- cin.eof()==false; //未检测到结尾
getline():getline(istream is,string str,结束符);同样,此处结束符为可选参数(默认依然为enter)。然而,getline()与前面的诸多存在的差别在于,它string库函数下,而非前面的istream流,所有调用前要在前面加入#include<string>。与之对应这一方法读入时第二个参数为string类型,而不再是char*,要注意区别。另外,该方法也不是遇到空白字符(tab, space, enter(当结束符不是默认enter时))就结束输入的,且会丢弃最后一个换行符。一次读取一行,不可指定读取长度;一般用于string对象的输入;
cin.getline():面向行的输入,可以读取空格,用于读取整行,直至遇到换行符停止读取;读取换行符后自动将其丢弃,并在末尾添加一个'\0';如:cin.getline(name,20); 若参数为20,则至多读取19个字符数,最后一个用于存储 '\0';可以指定读取长度;
cin.getline(字符数组名,接收长度,结束符)
cin.get(): 可以读取字符串中的空格和换行符'\n',并将其保存在输入队列中,下一次读取从保存在队列中的换行符开始,可用cin.get()来处理换行符;如cin.get(name,Arsize).get();这样在读取字符数组name后,自动处理末尾处换行符,下次读取将不会从换行符读取
cin.get(字符数组名,接收长度,结束符) int ch; ch=cin.get()与cin.get(char ch)等价
组合使用情况:
5.4 C++标准输出
cout.put(ch):输出字符ch;等价于printf("%c",ch);而cout<<'ch';只是输出字符ch对应的ASCLL码
wcout:用来处理宽字符类型wchar_t的输出;
如:wchar_t ch=L'p';//定义一个宽字符串常量
wcout<<L"tall"<<endl;//输出一个宽字符串
6. sprintf()函数
sprintf(): 用来将数据写入字符串而非打印到显示器上;sprintf(formal,"%s,%lqs:%6.2f\n",last,first,prize);可用puts(formal);进行输出
7. 五大存储类别
- 自动变量:块作用域内,相当于局部变量
- 寄存器变量:
- 块作用域静态变量
- 外部链接的静态变量(全局变量),其它文件若要使用,添加extern引用即可,如extern int a;
- 内部链接的静态变量(只可以在本文件中使用的静态全局变量)
8. 函数按照存储类别分:
外部函数、静态函数(static double beta(int,int)、内联函数
9. malloc 与 calloc异同,new的使用(C++)
同:都是在堆区中手动开辟一块内存,都需要free进行手动释放
异:
- int *p1=(int *)malloc(sizeof(int));
- int *p2=(int *)calloc(10,sizeof(int));
使用calloc可以指定每次开辟多少块同样大小的存储单元,可将所有位都设置为0;
【注意】:之所以使用sizeof(int)而不是直接使用4是为了提交程序的可移植性;
new运算符可以根据类型来自动确定所需要多少字节的内存;
int *pn=new int;
*pn=5; //此时pn被声明为指向int的指针,并在堆内存中开辟一块内存空间;
......
delete pn; //使用delete释放pn指向的内存空间,但指针本身不会被删除;
//在堆内存中开辟一块动态数组
int *p=new int[10];
p[0]=0.2; //可以像使用普通数组那样,将指针直接当作数组名使用
p[1]=0.5;
......
delete [] p; //将使用完的数组释放掉
//创建动态结构
struct inflatable{
char name[20];
float volume;
double price;
};
int main()
{
inflatable *ps=new inflatable;
cin.get(ps->name,20);
cin>>ps->volume;
cin>>(*ps).price;
cout<<(*ps).name<<endl;
cout<<ps->volume<<endl;
cout<<ps->price<<endl;
delete ps;
return 0;
}
【注意】使用new []为数字非陪内存,应使用delete []来释放,内存释放不当会导致内存泄漏问题的发生,正确使用new和delete可以有效避免内存泄漏问题;
10. 模板类vector、array
//模板vector
vector<typaname> arr(n_elem);
vector<int> vi; //创建一个包含0个int型数据的vector对象
vector<double> vd(n); //创建一个包含n个double型数据的数组
vd[0]=1.0/3.0;
.....
//模板array
array<typename,n_elem> arr; //n_elem不可为变量
array<int,5> ai; //创建一个包含5个int类型数据的array对象
array<double,4> as={1.2,2.1,3.1,4.1};
11. 指针常量与常量指针
const int *p=&a; //常量指针,指针指向的地址可以改变,指向的值不可以改变;
int *const p=&a; //指针常量,指针指向的地址不可以改变,指向的值可以改变
const int *const p=&a; //指针指向的地址和值均不可改变;
12. C/C++文件操作
步骤:打开,写入、读取、关闭
12.1 C语言通过一个文件指针打开绝对地址中的文件
#include <stdio.h>
int main()
{
FILE *fp=fopen("c:\\......\\word.txt","r");
if(fp==NULL)
{
printf("文件打开失败!");
exit(0);
}
.....
.....
fclose(fp);
return 0;
}
12.2 C++通过文件输出输入流对象打开文件并进行相应读写操作;
#include <iostream>
#include <fstream>
int main()
{
//文件的写入
ofstream outfile; //创建一个文件输入流对象
outfile.open("carinfo.txt");
if(!outfile.is_open()) //检查文件是否打开成功
{
cout<<"could not open the file!"<<endl;
exit(EXIT_FAILURE);
}
.....
outfile.close();
//文件的读取
ifstream infile;
infile.open("carinfo.txt");
if(!infile.is_open())
{
cout<<"could not open the file!"<<endl;
exit(EXIT_FAILURE);
}
.....
infile.close();
return 0;
}
13. 移位运算符的用法
number<<n //number乘以2的n次幂
number>>n //number为非负,用number除以2的n次幂
14. cstring与string头文件的区别
<string>是C++标准库头文件,使用stirng类型必须首先包含string头文件,用于字符串操作,string类型可以进行+、 =、 +=、 >等运算。还有如int len=str.size()等函数,std::string 类实际上是 STL 模板类 std::basic_string 的具体化。
<cstring>是C标准库头文件<string.h>对应的C++标准库版本,包含了C风格字符串(即’\0’结尾字符数组),以及相关的一些类型和函数,例如strcmp、strcat、strchr、strstr、strlen等函数。<cstring>和<string.h>的最大区别在于,其中声明的名称都是位于std命名空间中的,而后者是全局命名空间。包含cstring之后,就可以在程序中使用C语言风格的strcpy之类的函数
15. 将数值作为地址来使用,需要通过强制类型转换将数字值转换为适当的地址类型
int *pt;
pt=(int *)0XB8000000; //合法,因为以十六进制表示的int型数值被转换为int *;成为了一个地址
pt=0XB8000000; //非法,因为此时0XB8000000是一个以十六进制表示的int型数值,而pt是一个地址
16. 枚举常量
enum{red,orange,yellow,green,blue,violet,indigo}; //仅使用枚举常量
int main()
{
int code;
cin>>code;
while(code>=red&&code<=indigo)
{
switch(code)
{
case red:cout<<"this is red!";break;
case yellow:cout<<"this is yellow!";break;
.....
.....
default:
cout<<"input error!";
}
cin>>code;
}
return 0;
}
17. cin.clear()
cin.clear()用来处理错误操作,可以消除错误标记,使输入继续进行,重置cin以接受新的输入;
//若输入一个字符,程序发现不是数字后将拒绝继续输入,所输入字符将保留在输入队列中;
//若不清除,下次读取依然从该位置读取;
while(!(cin>>golf[i])) //cin读取错误返回false,!(cin>>golf[i])则为true;
{
cin.clear(); //重置cin以接受新的输入;
while(cin.get()!='\n')
continue; //删除错误输入,将队列中不匹配的输入清除
cout<<"please enter a number:";
}
18. 函数重载
重载条件:函数名相同,但函数的特征标(即函数的参数列表)必须不同 ;
注意:部分看起来彼此不同的特征标,是不可以共存的;
如double cube(double x);与double cube(double &x);看上去不同,但含义相同;
19 类的继承
类继承中私有成员是否被继承问题
父类中所有的非静态成员属性都会被子类继承下去;父类中的私有成员属性是被编译器隐藏了,所以子类对象访问不到,但却是是被继承下去了;
继承中构造与析构的顺序 (面试题)
先构造父类,再构造子类,析构顺序与构造顺序恰好相反