也许,现在是我为我大学前三年买单的时候了,虽有不甘,但是认了。我现在,只有一个选择,继续看书、刷题。趁着秋招才刚刚开始,我需要坚持不懈。每次笔试过后,我会在这里记录一些我的错题。
部分编程题记录--点击打开链接
1、字符串相加
string str{ "123" }; str += 49;//此时49表示的ASCII码,str="1231" str += 4;//str="123\x4"
1、字符串复制
char a[2][10]; char b[] = "sucee", c[] = "fail"; //a[0] = b;//等式左边必须是可以被修改的左值!!! //a[1] = c; strcpy_s(a[0], b); strcpy_s(a[1], c); printf("%s\n", a[0]); printf("%s\n", a[1]);
1、
#include <iostream> using namespace std; typedef void(*Fprint)(); void fun() { cout << "fun()" << endl; } //传递函数指针(引用传递)的两种方式 void doSomething(Fprint &p)//void(*&p)() { cout << "start" <<endl; p(); } int main() { Fprint f = fun; doSomething(f); system("pause"); return 0; }
2、删除字符串s中的字符c:
#include <iostream> #include <string> using namespace std; void fun(string &str) { string::size_type len = str.length(), count = 0,i = 0; while(i+count<len) { if (str[i + count] == 'c') { for (string::size_type j = i+count+ 1;j < len&&str[j] != 'c';++j,++i) { str[i] = str[j]; } ++count; } else { ++i; } } str[i] = '\0'; } int main() { string s{ "1111111111111111c333333c444444c555555555" }; cout << s << endl;//1111111111111111c333333c444444c555555555 fun(s); cout << s << endl;//1111111111111111333333444444555555555 55 printf_s("%s\n",s.c_str());//1111111111111111333333444444555555555 system("pause"); return 0; }
3、两分钟写快排,未能快速写出,需要加强。
写出项目核心代码。
4、TCP为什么是三次握手,不是两次。
三次的原因阐述:保证post、get机制完好。信道不可靠, 数据传输要可靠。参考点击打开链接,点击打开链接。有两次的举例。
5、TCP主要用于哪方面,为什么有了TCP(传输控制协议)还要有UDP(用户数据报协议)。
TCP:可靠的数据流传输方法。比如传输信令,数据量较小的场合等。
UDP:无排序的,不可靠的传输服务。适用于对传输速率要求较高、通信量比较大,而对于可靠和安全的要求较低的场合。多媒体通信。--RPC、RTP。
6、SQL:有一张表,下面是定义
create table sg (id char(9),/*以逗号结尾*/ course char(9) , score smallint, primary key(id,course) );A、求取总分前十名
select id,sum(score) as total from sg group by id order by total desc limit 3;B、求取单科第一名
select id,A.course,A.score from sg as A, (select course,max(score) as highest_score from sg group by course )as B where A.course=B.course and A.score=B.highest_score;
1、算法五大特征:有限性、确定性、输入、输出、可行性。最基本的是有限性、确定性和可行性。(没有中间处理!)
2、snmp报文:首部、数据、版本。(并不含有安全类型啥的)
3、volatile用法:表示可变的,用来在进程间传递参数,特殊功能寄存器。
A中断服务程序中修改的供其它程序检测的变量需要加volatile;
B多任务环境下各任务间共享的标志应该加volatile;
C存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义。
4、菱形继承:定义:两个子类继承同一个父类,而又有子类同时继承这两个子类。
5、分支限界法与回溯法的相同点和不同点
相同点:二者都是一种在问题的解空间树T上搜索问题解的算法。
不同点:
A在一般情况下,分支限界法与回溯法的求解目标不同。回溯法的求解目标是找出T中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。
B回溯法与分支-限界法对解空间的搜索方式不同,回溯法通常采用尝试优先搜索,而分支限界法则通常采用广度优先搜索。
C对节点存储的常用数据结构以及节点存储特性也各不相同,除由搜索方式决定的不同的存储结构外,分支限界法通常需要存储一些额外的信息以利于进一步地展开搜索。
参考自点击打开链接
6、计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。当然这是一种牺牲空间换取时间的做法,而且当O(k)>O(n*log(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是O(n*log(n)), 如归并排序,堆排序)。
7、基于比较的排序:一般的排序都是基于比较的。非基于比较的有计数排序、桶排序、基数排序。
1、二叉树对称序列:即中序遍历序列。
2、DNS协议运行在UDP协议之上,使用端口号53。在传输层TCP提供端到端可靠的服务,在UDP端提供尽力交付的服务。其控制端口作用于UDP端口53。
3、学会的一种编程风格:
/*风格: * if(nullptr= =node) * break; */
我们可以防止出现node=nullptr的问题。
4、
#include <iostream> using namespace std; int main(void) { const int n = 10; const int m =2; int a[n]; for (int i = 0;i < n;++i) { a[i] = (0 == i % 2) ? (i + 2) : (i + 0); } int(*b)[n / m] = (int (*)[n / m])a;//将a数组划分为m部分 for (int j = 0;j < m;++j) { for (int i = 0;i < n / m;++i) { cout << b[j][i]; } } cout << endl << "\t\t\t\t@zem" << endl; system("pause"); return 0; }
5、就绪队列有10个线程,cpu执行一个大概花费200ms,切换线程约花费10ms,求出系统开销约占0.045。
6、x64平台:
#include <iostream> using namespace std; class St { public: int a;//8 short *p;//8 char b[32];//32 };//48 int main(void) { St st[10]; char *pointer = st[2].b + 32; char *head = (char *)st; cout << pointer - head << endl;//48*3=144 cout << endl << "\t\t\t\t@zem" << endl; system("pause"); return 0; }
x86运行:
7、
#include <iostream> using namespace std; int main(void) { char *p[] = { "Twww","Cwww","Rwww" }; char **pp[] = { p + 2,p + 1,p }; char ***ppp = pp; cout << **++ppp << endl; cout << *++*++ppp << endl;//此时的ppp已经指向pp[1]了,然后++取出p,再++取出Cwww。 cout << endl << "\t\t\t\t@zem" << endl; system("pause"); return 0; }
1、关键字容器与文本:判断给定文本是否包含关键字。
很详细的讲解:点击打开链接。构建关键字的树,状态机,可以合并多个关键字于一棵树,然后扫描关键字。
2、对于给定内存分配、释放。阐述相关数据结构、申请固定大小内存块getBlock(int sz=100)和释放free(char *p)的实现。
3、UNIX进程间通信:
A.管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信; 有名管道克服了管道没有名字的限制,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
B.信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身。
C.消息队列:消息队列是消息的链接表,包括Posix消息队列systemV消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
D.共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
E.信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
F.套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。
4、生产者和消费者问题。
5、UDP实现TCP需要添加哪些功能。
重传策略、重复检测、流控、连接建立、连接结束、故障恢复。(个人认为应该添加所有传输层保证可靠传输的功能,UDP使用的底层协议传送报文--数据报传送机制)
6、如何实现流量控制。
TCP采用滑动窗口机制(提供了可靠传输服务)解决了端到端的流量控制,但并未解决整个网络的拥塞控制。
7、流量控制和拥塞控制的区别。
拥塞控制:慢启动算法,逐步扩大发送窗口,以防止网络拥塞;
流量控制:放置数据发送过多,导致接收机高负荷,过少,导致利用率过低,于是两边进行窗口大小通信告知。
8、数据库索引是怎么实现的。对B+树的了解。为什么不用别的算法。
常见索引:顺序文件上的索引、B+树索引、散列索引、位图索引等
顺序文件上的索引是针对按指定属性值升序或降序存储的关系,在该属性上建立一个顺序索引文件,索引文件由属性值和相应的元组指针组成;(估计是查找用二分)
B+树索引是将索引属性组织成B+树形式,B+树的叶节点为属性值和相应的元组指针;
散列索引是建立若干个桶,将索引属性按照其散列函数值映射到相应桶中,桶中存放索引属性值和相应的元组指针;(查找速度快)
位图索引是用位向量记录索引属性中可能出现的值,每个位向量对应一个可能的值。
位图索引参考-点击打开链接,点击打开链接
后三种的简介-点击打开链接
B系列树:BST、B-树、B+树、B*树点击打开链接
B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于
走右结点;
B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键
字范围的子结点;
所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点
中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率
从1/2提高到2/3;
9、map的实现机制。
红黑树。
10、红黑树和平衡二叉树的区别。
红黑树和AVL树的区别在于它使用颜色来标识结点的高度,它所追求的是局部平衡而不是AVL树中的非常严格的平衡。都是自动调整平衡的。
点击打开链接
1、
#include <iostream> using namespace std; class A { public: A():a(2){} int getA() { return a; } void fun() const { cout << "a" << endl; } void fun() { cout << "b" << endl; } private: int a = 1; }; int main() { //test unsigned==unsigned int unsigned i = 0; cout << i << endl; //test printf() //printf("11" + "22");//编译不通过 //test fun() A obja; obja.fun();//b,优先匹配普通函数 const A objb; objb.fun();//a,只能调用常量函数 //test a cout << obja.getA() << endl; //如果有初始化列表则初始化为该值,如果没有则初始化为类类初始值 system("pause"); return 0; }
class A { private: int _a; public: int getA() { return _a; } void fun() { cout << "fun()" << endl; getM();//成员函数可以调用静态成员函数 } static int m; static int getM() { //cout << getA() << endl;//错误 //fun();//错误 //只能访问静态成员 return m; } };
2、 set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与有字数的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。构造set集合的主要目的是为了快速检索。
3、面试问了很多编译器行为问题,应该冷静分析,根据平时写的代码进行判断,而不是畏惧。
1、单列模式:参考的别人的C++代码
#include <iostream> using namespace std; class Singelton { private: Singelton() {} static Singelton* singel; public: static Singelton* GetInstance() { if (singel == NULL) { singel = new Singelton(); } return singel; } }; Singelton* Singelton::singel = NULL;//注意静态变量类外初始化 //客户端: int main() { Singelton* s1 = Singelton::GetInstance(); Singelton* s2 = Singelton::GetInstance(); if (s1 == s2) cout << "ok" << endl; else cout << "no" << endl; system("pause"); return 0; }
Container(容器) 各种基本数据结构
Adapter(适配器) 可改变containers、Iterators或Function object接口的一种组件
Algorithm(算法) 各种基本算法如sort、search…等
Iterator(迭代器) 连接containers和algorithms
Function object(函数对象)
Allocator(分配器)
参考自:点击打开链接
3、
#include <iostream> #include <vector> using namespace std; int main() { vector<int> ia; ia.reserve(5);//仅仅预留空间,尽在要求容量大于本有容量时候起作用 cout << ia.size() << "\t" << ia.capacity() << endl; ia.resize(2);//相当于含有2个元素,但是此时,并不修改容量 cout << ia.size() << "\t" << ia.capacity() << endl; system("pause"); return 0; }
4、vector和list区别
vector:随机访问、数量变化小、对象简单(否则扩容开销比较大);
list:插入删除、数量变化大、对象较为复杂。
5、vector从8K扩容到了128K,如果前8K常用,后面的不常用,此时vector是怎么做的(面试官的意思是系统操作,并非人为)。
这里,我确实不知道,还在寻找答案。对于人为干预:点击打开链接
容量变大后,是变不回来的,我们在这里可以使用shrink_to_fit(),但是系统可以选择忽视。
#include <iostream> #include <vector> #include <string> using namespace std; int main() { vector <string> v; for (int i = 0; i<1000000; i++) v.push_back("abcdefghijklmn"); v.clear(); cout << "Vector 的 容量为" << v.capacity() << endl; vector<string> (v).swap(v);//这种写法还真是第一次见 cout << "Vector 的 容量为" << v.capacity() << endl; // 此时容量为0 system("pause"); return 0; }
7、static_cast和dynamic_cast区别作用:
static_cast:一般只要不包含底层const都可以转换,可以找回存在的void *指针。
dynamic_cast:运行时类型识别。将基类的指针或引用安全的转换为派生类的指针或引用。dynamic_cast<type*>(e):type是类,通常有虚函数。什么情况下转换成功:type与e同类、type是e的子类、type是e的公有基类。
8、C11特性举例:auto自动类型判断。点击打开链接
9、函数指针和lambda区别:传统的函数指针是一个指针, lambda是一个对象。
10、哈希表冲突处理:
开放定址法:线性探测再散列(容易产生二次聚集,即处理同义词冲突又导致非同义词冲突。几次出现冲突。但是他一定可以找到不冲突的地址)、二次探测再散列(k^2,k正负跳跃,属于跳跃式探测)、伪随机数探测再散列(确定一个伪随机数序列);
再哈希法:同时构造多个不同的哈希函数,不易聚集,但是开销变大。
链地址法:将同义词构成单链表,适合经常要插入删除情况。(同义词指哈希函数计算结果一样的词);
建立公共溢出区:哈希表分为基本表和溢出表。
11、如何消抖:硬件消抖和软件消抖(检测后延时再检测)。
1、IPV6里面没有广播,只有:单播、多播(组播)、任播(群集:选择最近一台)。
2、不能重载的运算符如:
:: .*(类成员指针) . ?:(三目条件)
重载运算符定义更佳准则:
A 赋值(=)、下标([])、调用(())、成员访问箭头(->)运算符必须是成员;
B 复合赋值运算符一般来说是成员;
C 改变对象状态的运算符或与给定类型密切相关的运算符,如递增递减解引用运算符等常为成员;
D 具有对称性的运算符可能转换任意一端的运算符,例如算数、相等性、关系和位运算等常为普通非成员函数。
3、编程题难。还需要好好锻炼。
4、
#include <iostream> using namespace std; template<class T> void fun() { cout << "templat fun()" << endl; } void fun() { cout << "fun()" << endl; } int main() { fun<int>();//实例化函数模板及调用 fun(); system("pause"); return 0; }
1、C和C++的区别:
C是面向过程的,C++面向对象。C++三个主要特点:封装、继承、多态。
2、多态:
重载多态,强制多态,包含多态,参数多态。
普通函数和类的成员函数的重载属于重载多态,还有运算符重载。
强制多态包括类型强制转换等。
包含多态主要通过虚函数来实现。(动态多态,其余为静态多态)
参数多态:函数模板、类模板。
3、删除vector<int>中值为3的元素:
思路一:直接用一个新的vector装入不是3的元素;
思路二:排序,找到首尾迭代全3的序列,删除(erase)。
在面试的时候应该多与面试官沟通,得到更多的信息,选择合适的思路。
1、RAII:这个问题在Effective C++有详细介绍,暂不写。
2、虚函数底层实现机制。
1、
#include <iostream> using namespace std; int main() { int a = -1; unsigned b = 0; int c = (a + b > 0 ? 1 : -1); cout << c << endl;//1 system("pause"); return 0; }2、对于http状态:
1**表示确定、2**表示、3**重定向、4**请求错误、5**服务器错误。
5、面试有一定难度。
1、mysql_fetch_object() 和 mysql_fetch_array() 类似,只有一点区别 - 返回一个对象而不是数组。间接地也意味着只能通过字段名来访问数组,而不是偏移量(数字是合法的属性名)。速度上,本函数和 mysql_fetch_array() 一样,也几乎和 mysql_fetch_row() 一样快(差别很不明显)。(竟然连这都考--PHP)
2、RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。非对称密码算法。你只要想:既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。
1、不能建立索引的数据类型是哪一个:int、date、blob、varchar。目测是blob(二进制大对象)。
2、git命令,合并远程分支于本地。点击打开链接
git pull:从远程获取最新版本并merge到本地。
3、请求式分页存储管理---页面置换算法:最佳页面淘汰(理论上的)、先进先出淘汰、最近最不常用淘汰、最近最久未用淘汰。
5、kill普通用户是可以操作的,但是ldconfig管理动态链接的,还真没有用过,排除到这里了,估计要root权限。
1、BSR-逆向位扫描指令(从高位开始),BSF - 正向位扫描(从低位开始)
1234H 的二进制为 0001 0010 0011 0100
BSF找值为1的最低bit,
找到0001 0010 0011 0(1)00,是(从0数)第2位,cx值2
BSR找值为1的最高bit
找到000(1) 0010 0011 0100, 是(从0数)第12位,cx值12
2、关于左值和右值:左值是类型、右值是取其值。概念要清楚,会区分。
#include <iostream> using namespace std; void print(char(*p)[5]) { for (int i = 0;i < 5;++i) { for (int j = 0;j < 5;++j) {//等效写法 cout << p[i][j] << "\t"<<*((p[i])+j)<<"\t"<<*(*(p+i)+j)<<endl; } } } int main() { char s[5][5] = { "1234","6789","asdf","ghjk","zxcb" }; print(s); system("pause"); return 0; }
#include <iostream> using namespace std; int main() { int a[2][3] = { 1,2,3,4,5,6 }; cout << a[0] << "\t" << *(a + 1) << "\t" << *a[1] + 1 << endl; //010FF9B8(地址,表示指向第一个数组的指针) 010FF9C4 5 system("pause"); return 0; }
#include <iostream> using namespace std; class A { public: A(int _a):a(_a){} int getA() { return a; } private: int a; }; class B :private A { public: B(int _a,int _b):A(_a),b(_b){} int getA() { //write code here return A::getA(); //a不可访问,因为在private中,虽然是私有继承,但是public部分成为了自己的private部分,可以访问。 } private: int b; }; int main() { B b(1, 2); cout << b.getA() << endl;//1 system("pause"); return 0; }
#pragma pack(1)//1、2、4、8显然最高要小于电脑位数/8 #include <iostream> using namespace std; struct A { int a; float b; short c; char d; }; int main() { cout << sizeof(A) << endl;//11 cout << endl; system("pause"); return 0; }
#include <iostream> using namespace std; class A { public: void fun() { cout << "fun()" << endl; } void getM() { cout << m << endl; } private: int m; }; int main() { A *pa = 0;//与nullptr等效 pa->fun();//fun() pa->getM();//中断 system("pause"); return 0; }
#include <iostream> #include <string> using namespace std; int tran(string str) { int i = 0, len=str.length(); int y = 0; if (len != 8) return 0; while (i < 4) { y = 10 * y + str[i++] - '0'; } int m = 0; while (i < 6) { m =10 * m + str[i++] - '0'; } int d = 0; while (i < 8) { d = 10 * d + str[i++] - '0'; } if (m == 1) m = 13; if (m == 2) m = 14; return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7+1; } int main() { string str; while (cin >> str) { switch (tran(str)) { case 0:break; case 1:cout << "星期一";break; case 2:cout << "星期二";break; case 3:cout << "星期三";break; case 4:cout << "星期四";break; case 5:cout << "星期五";break; case 6:cout << "星期六";break; case 7:cout << "星期七";break; default:break; } } cout << endl; system("pause"); return 0; }
class Solution { public: int trailingZeroes(int n) { while(n%5) { --n; } if(n<25) { return n/5; } return n/5+trailingZeroes(n/5); } };
#include <iostream> using namespace std; class A { public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } }; int main() { cout << "C" << endl; A *p1 = (A*)malloc(sizeof(A)); free(p1); cout << "CPP" << endl; A *p2 = new A; delete p2; system("pause"); return 0; }
#include <iostream> using namespace std; #define DIV(x) x/x int fun(volatile int *ptr)//可能返回不同的值,直接从原始地址取出 { return (*ptr)*(*ptr); } int main() { int a = 4; int b = DIV(a) / DIV(a);//0 int $123 = 0123;//八进制 cout << $123 << endl; // int _int&int = 0;//错误标识符 cout << fun(&a) << endl; system("pause"); return 0; }