找工作告一段路,总结一下这段时间遇到的一些印象中的笔试和面试题目。
公司一
-
写一个循环,步数10步,依次输出1,3,5,7,9,2,4,6,8,10
for (int i = 0; i <= 20; i++) { if((i % 2) && (i < 10)) cout << i; if (!(i % 2) && (i > 10)) cout << (i-10); }
-
写一个函数来逆转字符串,注意性能
void reverse(char *str) { char temp; for(int i = 0; i < strlen(str) / 2; i++) { temp = str[i]; str[i] = str[strlen(str) - i - 1]; str[strlen(str) - i - 1] = temp; } }
-
写一个函数不使用变量,不使用系统函数,来输出字符串长度
不使用变量,就是使用递归函数,当时忽略了这个知识点,没有写出来。
int new_str(char *str) { if (str == NULL) return 0; if (*str == '\0') return 0; return 1 + new_str(str + 1); }
-
写一个函数,输入为整形的形参,其字节代表彩虹的颜色,来解析出来有哪些颜色
void show_rainbow(int rainbow) { string color[7] = ["red","orange","yellow","blue","cyan","green","purple"]; int j; std::cout << "This rainbow have the below color:" << std::endl; for (int i = 0; i < 7; i++) { j = 1 << i; if(rainbow & j) std::cout << color[j] << " "; } std::cout << std::endl; }
-
输入一个10M的文件,来判断之后的输入的10M的函数是不是有损坏(想法)
想法:
(1) CRC16的校验
(2) 直接保存之前文件的哈希值
(3) 计算所有自己的累加和、累加减、累加乘、累加除
由于平时工作中不是经常使用文件读写,关于文件处理的一个简单的模板记录如下:
```
文件处理的相关程序:
#include <iostream>
#include <fstream>
int main()
{
using namespace std;
ofstream outFile; // 输出的文件字节流
outFile.open("out.txt");
ifstream inFile; // 输入的文件字节流
inFile.open("in.txt");
outFile.close();
inFile.close();
}
```
公司二:
C++多态
虚函数就是允许子类重新定义的成员函数。而子类重新定义父类虚函数的做法,称为“覆盖”(override),或者是“重写”。
覆盖是指子类重新定义父类的虚函数的做法。 重载是指允许多个同名的函数,而这些函数的参数列表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)
重载不属于“面向对象编程”
C和javascript之间的区别
javascript是解释型脚本语言,而c是面向过程的、高级的、编译型语言。
js定义变量使用var,而C要确定类型,如int, long, float, double, char.
公司三:
- C++的三大特性(或面向对象设计的三大原则):多态、继承、封装
- 简述函数重载、函数覆盖、隐藏的特性
参考:https://www.cnblogs.com/beaglebone/p/5727287.html
- 函数重载只会发生在同一个类中,函数名相同,只能通过参数类型,参数个数或者有无const来区分。不能通过返回值类型区分,而且virtual也是可有可无的,即虚函数和普通函数在同一类中也可以构成函数重载。
- 基类和派生类中只能是隐藏或者覆盖。
- 隐藏是指派生类中有函数与基类中函数同名,但是没有构成虚函数覆盖,就是隐藏。
- 隐藏的表现:若基类中函数func()被派生类中函数func()隐藏,那么无法通过派生类对象访问基类中的func() 函数,派生类对象只能访问到派生类中的func()函数。不过基类中的func()确实继承到了派生类中。
- 虚函数也只是在基类和派生类中发挥多态的作用,而在同一类中虚函数也可以重载。
虚函数实现多态的条件:
a 基类中将这些成员声明为virtual。
b 基类和派生类中的这些函数必须同名且参数类型,参数个数,返回值类型必须相同。
c 将派生类的对象赋给基类指针或者引用,实现多态。
缺少任何一条,只会是基类和派生类之间的隐藏,而不是覆盖
- 查找单链表中倒数第k个数的数值
该题目来自《剑指offer》,参考链接如下: https://www.cnblogs.com/edisonchou/p/4769164.html
思路:假设整个链表有n个结点,那么倒数第k个结点就是从头结点开始的第n-k+1个结点。如果我们能够得到链表中结点的个数n,那我们只要从头结点开始往后走n-k+1步就可以了。
为了能够只遍历一次就能找到倒数第k个节点,可以定义两个指针:
(1)第一个指针从链表的头指针开始遍历向前走k-1,第二个指针保持不动;
(2)从第k步开始,第二个指针也开始从链表的头指针开始遍历;
(3)由于两个指针的距离保持在k-1,当第一个(走在前面的)指针到达链表的尾结点时,第二个指针(走在后面的)指针正好是倒数第k个结点。
因此,这里n-(k-1),就是n-k+1
对应代码如下:
public static Node FindKthToTail(Node head, uint k)
{
if(head == null || k == 0)
{
return null;
}
Node ahead = head;
Node behind = null;
for (int i = 0; i < k - 1; i++)
{
if(ahead.Next != null)
{
ahead = ahead.Next;
}
else
{
return null;
}
}
behind = head;
while (ahead.Next != null)
{
ahead = ahead.Next;
behind = behind.Next;
}
return behind;
}
- 运算符重载能否访问私有成员
是可以访问的。本质上运算符的重载也是成员函数
- 集成测试又称为什么测试?组装方法?
组装测试(也叫集成测试,联合测试)是单元测试的逻辑扩展。它的最简单的形式是:两个已经测试过的单元组合成一个组件,并且测试它们之间的接口。从这一层意义上讲,组件是指多个单元的组装聚合。
自底向上的组装(Bottom-Up Integration)方式是最常使用的方法。其他组装方法都或多或少地继承、吸收了这种组装方式的思想。自底向上组装方式从程序模块结构中最底层的模块开始组装和测试。
- 进程和线程
- 进程fork,其中一个进程输出1001,1002。其他可能的进程?
https://www.cnblogs.com/msxh/p/4889529.html
- 信号量的初始化
信号量是一个计数器,通常在内核中实现,用于多个进程对共享数据对象的同步访问。使用信号量的头文件是#include <sys/sem.h> 信号量的使用规则: 若信号量为正,则进程可使用该资源。 若信号量为0,则进程阻塞等待,并将进程插入等待队列,直到该信号量的值大于0从等待队列中执行进程请求。 加锁操作:如果信号量大于0,则信号量-1;如果信号量为0,则挂起该进程,并将这个进程插入等待队列。 解锁操作:如果等待队列中有进程则唤醒该进程,让它恢复运行;否则,信号量+1。
操作系统原理中有作业,进程,线程,管程
现在常用的进程间通信的方式有信号,信号量,消息队列,共享内存。
函数指针
void (*func) (void)
defin语句中#和##的区别
#是将参数字符串话,##是将两个参数连为一个整体
循环include
必须前向声明
如何判断栈的增长方式
数组是不可以的。因为数组是增加的。
方法1,通过比较被调用过程中的入口参数所在地址和局部变量所在地址之间的大小来判断。如果入口参数所在地址大于局部变量所在地址,则栈是从低地址增加的。
方法2: 直接阅读汇编指令来判断。
方法三: 显示栈钉寄存器的内容。
强制转换和static_cast的区别
在两个类进行转换时,C风格的强制转换,编译不会报错,但是会留下隐患。 而static_cast会进行类型检测,直接报错。
extern C
主要作用是能够实现C代码调用其他的C需要代码。由于C支持重载,因此编译器编译函数的过程会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名。而C需要不支持函数重载,因此编译C语言代码的函数不会带上函数的参数类型,一般只包含函数名。
如果不使用extern C,则会在连接阶段报错。因为找不到对应的编译好的函数。