大厂C++面试题要点
1、malloc和new的区别
(1)操作对象不同:malloc/free是C++/C语言的标准库函数,new/delete是C++的运算符。对于非内部数据类的对象而言,光用malloc/free无法满足动态对象的要求。
(2)返回类型安全性:new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。(int *)malloc(sizeof(int))
类型安全很大程度上可以等价于内存安全,类型安全的代码不会试图方法自己没被授权的内存区域。关于C++的类型安全性可说的又有很多了。
(3)内存分配失败时的返回值:new内存分配失败时,会抛出bac_alloc异常,比如反馈客户请求处理内存分配不足;malloc分配内存失败时返回NULL。
(4)是否需要指定内存大小:使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。
例子:(int *)malloc(sizeof(int)),new int;
(5)是否调用构造函数以构造对象,并为其传入初值;编译器运行相应的构造函数以构造对象,并为其传入初值。使用delete操作符来释放对象内存时会经历两个步骤:调用对象的析构函数;编译器调用operator delete(或operator造/析构函数:使用new操作符来分配对象内存时会经历三个步骤:调用operator new 函数(对于数组是operator new[])分配一块足够大的原始的未命名的内存空间以便存储特定类型的对象;编译器运行相应的构 delete[])函数释放内存空间。
(6)对数组的处理:C++提供了new[]与delete[]来专门处理数组类型: A*ptr=new A[10];//分配10个A对象,使用new[]分配的内存必须使用delete[]进行释放:delete [] ptr;new对数组的支持体现在它会分别调用构造函数函数初始化每一个数组元素,释放对象时为每个对象调用析构函数。注意delete[]要与new[]配套使用,不然会找出数组对象部分释放的现象,造成内存泄漏。至于malloc,它并不知道你在这块内存上要放的数组还是啥别的东西,反正它就给你一块原始的内存,在给你个内存的地址就完事。所以如果要动态分配一个数组的内存,还需要我们手动自定数组的大小:int*ptr=(int*)malloc(sizeof(int));//分配一个10个int元素的数组。
(7)New/malloc是否可以互相调用:operator new /operator delete的实现可以基于malloc,而malloc的实现不可以去调用new。
(8)opeartor new /operator delete可以被重载(前提是自定义版本必须位于全局作用域或者类作用域中),而malloc/free并不允许重载。
(9)malloc能直观的重新分配内存:使用malloc分配的内存后,如果在使用过程中发现内存不足,可以使用realloc函数进行内存重新分配实现内存的扩充。realloc先判断当前的指针所指内存是否有足够的连续空间,如果有,原地扩大可分配的内存地址,并且返回原来的地址指针;如果空间不够,先 按照新指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来的内存区 域。new没有这样直观的配套设施来扩充内存。
2、线程和进程的区别
主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,是共享地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
3、僵尸进程
一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
危害:如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。
处理方法:当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
4、重载与多态的区别
(1)重载是同名参数不同,通过参数来确定调用那个函数;但是多态是同名同参数,通过函数的实际类型决定调用那个函数;
(2)重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;
多态而言,只有等到方法调用的那一刻,编译器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。
---------------------
作者:lyf-高坪村长
原文:https://blog.csdn.net/qq_38282803/article/details/81462713
1. 26进制的字符串相加
两个大整数相加,每一位是一个小写字母,二十六进制,a表示0,z表示25,求结果。 输入: 2个26进制数; 输出: 2个26进制的和。 实例: 输入: z bc 输出: cb
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int main()
{
char str1[205], str2[205];
int num1[205], num2[205], num[205];
int i;
while (cin >> str1 >> str2)
{
memset(num1, 0, sizeof(num1));
memset(num2, 0, sizeof(num2));
memset(num, 0, sizeof(num));
int tmp = 0;
for (i = strlen(str1) - 1; i >= 0; i--)
num1[++tmp] = str1[i] - 'a';
tmp = 0;
for (i = strlen(str2) - 1; i >= 0; i--)
num2[++tmp] = str2[i] - 'a';
for (i = 1; i <= 202; i++)
num[i] = num1[i] + num2[i];
for (i = 1; i <= 202; i++)
num[i + 1] += num[i] / 26, num[i] %= 26;
int mk = 0;
for (i = 202; i >= 1; i--)
{
if (num[i]) mk = 1;
if (mk) printf("%c", num[i] + 'a');
}
if (!mk) printf("a");
puts("");
}
return 0;
}
2. 两个字符串包含问题
两个字符串input1,和字符串input2,字符串元素的值域是26个大写字母,判断input2中的所有字符是否都包含在字符串input1中。 如果包含返回:ture, 否则返回:false
输入: 两个字符串: input1和input2,其中input1的长度大于input2。要求两个输入字符串input1和input2的长度不小于5. 如:A字符串:BBDDCFFE,B字符串:LCEFB
输出:true或false
位图思想:
无论是字符串1还是字符串2,都是由【a-z】字母组成的,所以最多只有26个字母,所以只要一个整数(32位)就可以表示字符串所表示的字母,假设这个字母出现,则对应的位置1,那么就算26个字母都出现了,也只需要26位置1.
#include <iostream>
#include <sstream>
#include <map>
#include <string.h>
using namespace std;
bool is_contained(string str1, string str2)
{
int strmap = 0;
const char * pstr = str1.data();
while (*pstr != '\0')
{
strmap |= (1 << (*pstr - 'a'));
pstr++;
}
pstr = str2.data();
bool iscontained = true;
while (*pstr != '\0')
{
if ((strmap & (1 << (*pstr - 'a'))) == 0)
{
iscontained = false;
break;
}
pstr++;
}
return iscontained;
}
int main()
{
string str1, str2;
while (getline(cin, str1))
{
getline(cin, str2);
if (str1.length() >= 5 && str2.length() >= 5 && (str1.length() > str2.length()))
{
if (is_contained(str1, str2))
cout << "true" << endl;
else
cout << "false" << endl;
}
else
cout << "error: 字符串长度小于5" << endl;
}
return 0;
}
第二种方法:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
string matchStr(string str1, string str2)
{
string flag = "true";
int len1 = str1.size();
int num = 0;
vector<int> pos;
for (int i = 0; i < len1 - 1; ++i)
{
if (str1[i + 1] == str1[i])
pos.push_back(i + 1);
}
for (int i = 0; i < pos.size(); i++)
{
int tmp = pos[i] - i;
str1.erase(str1.begin() + tmp);
}
for (int i = 0; i < str2.size(); i++)
{
num = str1.find(str2[i]);
if (num < 0)
{
flag = "false";
break;
}
else
continue;
}
return flag;
}
int main()
{
string Str1, Str2;
cin >> Str1;
cin >> Str2;
string Res = matchStr(Str1, Str2);
cout << Res << endl;
return 0;
}
3. 字符串解压缩,并且排序输出
---------------------
作者:Cookie小甜饼 原文:https://blog.csdn.net/image_fzx/article/details/82431082