STL 添加链接描述
排序
#include <iostream>
#include <algorithm>//STL库函数
using namespace std;
void sort(int a[],int length)
{
int i, j, max;
for(i=0;i<length-1; i++)
{
for(j=0;j<length-i-1; j++)
{
if(a[j]>a[j+1])
{
max = a[j];
a[j] = a[j+1];
a[j+1] = max;
}
}
}
}
数组倒排
char str[]="hello,world";
int len=strlen(str);
char t;
for(int i=0; i<len/2; i++)
{
t=str[i];
str[i]=str[len-i-1];
str[len-i-1]=t;
}
qDebug()<<str;
int main()
{
char *src = "hello,world";
int len = strlen(src);
char *dest = (char *)malloc(len + 1); //要为\0分配一个空间
char *d = dest;
char *s = &src[len - 1]; //指向最后一个字符
while ( len-- != 0 )
*d++ = *s--;
*d = 0; //尾部要加\0
printf("%s\n", dest);
free(dest);// 使用完,应当释放空间,以免造成内存汇泄露
return 0;
}
int main()
{
char str[] = "hello,world";
int len = strlen(str);
char t;
for (int i = 0; i < len; i++)
{
t = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = t;
}
printf("%s", str);
return 0;
}
一.标志位和序号
seq序号 :发送方随机生成的
ack确认序号:ack=seq+1 标志位ACK=1时确认序号有效
SYN标志位:发起一个新连接
ACK标志位:确认序号有效
FIN标志位:断开连接
TCP IP 三次握手
第一次握手客户跟服务器说要创建链接,服务器开始监听。客户端变成 SYN_SENT
第二次,服务器同意客户端的链接,然后要再和客户端确认一遍是不是真要链接。服务器 SYN_RCVN
第三次客户端说真要链接,这才链接 进入ESTABLISHED 模式
为什么三次握手中客户端还要发送一次确认呢?可以二次握手吗?
主要为了防止已失效的连接请求报文段突然又传送到了B,因而产生错误。如A发出连接请求,但因连接请求报文丢失而未收到确认,于是A再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,A工发出了两个连接请求报文段,其中第一个丢失,第二个到达了B,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达B,此时B误认为A又发出一次新的连接请求,于是就向A发出确认报文段,同意建立连接,不采用三次握手,只要B发出确认,就建立新的连接了,此时A不理睬B的确认且不发送数据,则B一致等待A发送数据,浪费资源。
四次挥手
3.2.5为什么客户端最后还要等待2MSL?
解析:MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。
第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
3.2.6为什么建立连接是三次握手,关闭连接确是四次挥手呢?
解析:建立连接的时候,服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次
写String类
class String
{
public:
explicit String(const char *str=NULL)
{
if(str ==NULL)
{
m_size= strlen(str);
m_data=new char [1];
strcpy(m_data,'\0');
}else
{
m_size= strlen(str);
m_data=new char [m_size+1];
strcpy(m_data,str);
}
}
String(const String &other)
{
m_size= strlen(other.m_data);
m_data=new char [m_size+1];
strcpy(m_data,other.m_data);
}
String &operator =(const String &other)
{
if(this== &other)
{
return *this;
}
delete m_data;
m_size=other.m_size;
m_data=new char[m_size+1];
strcpy(m_data,other.m_data);
return *this;
}
size_t getSize() const{
return m_size;
}
private :
size_t m_size;
char *m_data;
};
编写Strcpy
char *my_strcpy(char *strDest, const char *strSrc) {
assert(strDest != nullptr && strSrc != nullptr);
char *p = strDest;
while (*strSrc != '\0') {
*p++ = *strSrc++;
}
return strDest;
}
strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
答:为了实现链式表达式。例如 int length = strlen( strcpy( strDest, “hello world”) );
基类为什么要虚析构函数?
防止内存泄漏 当父类指针指向子类对象时 delete 父类指针 只自动调用了 父类的析构函数 派生类中申请的空间则得不到释放导致内存泄漏。
指针和引用的区别
指针指针是一个新的变量 指向一片内存空间 而引用只是变量别名
指针可以初始化为空值。而引用必须初始化
指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
new和malloc的区别。
new 是操作符 malloc 是系统函数
new 返回指定类型指针 malloc返回void*指针,需要强制类型转换
new 会调用构造函数 malloc 不会
new会自动计算需分配的空间,malloc不行;
new可以被重载,malloc不能。
什么是多态
静态多态(早绑定)、动态多态(晚绑定)。静态多态是通过函数重载实现的;动态多态是通过虚函数实现的。
多态作用
作用:
1)隐藏实现细节,使得代码模块化。
2)类的继承与派生的时候,接口重用。
实现多态的条件
1)要有继承
2)要有虚函数重写
3)要有父类指针(父类引用)指向子类对象
浅拷贝 深拷贝
浅拷贝 只是增加一个指针 指向原来的内存 若多个对象指向一块空间时候 释放一个对象会导致其他对象的空间也被释放 再次使用这个对象会报错。
而深拷贝是增加了一个指针,并新开辟了一块空间让指针指向这块新开辟的空间。深拷贝和浅拷贝的不同之处,仅仅在于修改了下拷贝构造函数,以及赋值运算符的重载。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
什么情况下会调用拷贝构造函数
用类的一个对象去初始化另一个对象时
CExample A(100);
CExample B = A; //这句和下句都会调用拷贝构造函数。
CExample B(A);
当函数的形参是类的对象时(也就是值传递时),如果是引用传递则不会调用
//全局函数,传入的是对象
void g_Fun(CExample C)
{
cout<<"test"<<endl;
}
int main()
{
CExample test(1);
//传入对象
g_Fun(test);
当函数的返回值是类的对象(返回值为引用不会调用拷贝构造函数)
//全局函数
CExample g_Fun()
{
CExample temp(0);
return temp;
}
int main()
{
g_Fun();
}
构造函数为什么不能被定义为虚函数
1.虚函数的作用在于通过子类的指针或引用来调用父类的那个成员函数。而构造函数是在创建对象时自己主动调用的,不可能通过子类的指针或者引用去调用。
2.虚函数相应一个指向vtable虚函数表的指针,但这个指向vtable的指针事实上是存储在对象的内存空间的,假设构造函数是虚的,就须通过vtable来调用,但对象还没有实例化,也就是内存空间还没有,无法找到vtable
const与#define的区别
const 有安全类型检查 define 没有安全类型检查
1.编译器处理方式
define – 在预处理阶段进行替换
const – 在编译时确定其值
2.类型检查
define – 无类型,不进行类型安全检查,可能会产生意想不到的错误
const – 有数据类型,编译时会进行类型检查
3.内存空间
define – 不分配内存,给出的是立即数,有多少次使用就进行多少次替换,在内存中会有多个拷贝,消耗内存大
const – 在静态存储区中分配空间,在程序运行过程中内存中只有一个拷贝
Static 作用
添加链接描述
1)在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
(2)static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。
(3)static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。
(4)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。
(5)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。
派生类中构造函数,析构函数调用顺序?
构造函数:“先基后派”;析构函数:“先派后基”。
指针常量与常量指针
常量指针
const char *str;
*str不能修改
可以修改 str=&str1;
#include <stdio.h>
// 常量指针(被指向的对象是常量)
int main() {
int i = 10;
int i2 = 11;
const int *p = &i;
printf("%d\n", *p);//10
i = 9; //OK,仍然可以通过原来的声明修改值,
//Error,*p是const int的,不可修改,即常量指针不可修改其指向地址
//*p = 11; //error: assignment of read-only location ‘*p’
p = &i2;//OK,指针还可以指向别处,因为指针只是个变量,可以随意指向;
printf("%d\n", *p);//11
return 0;
}
指针常量
char *str const;
指向内容可以改变 地址不可变
str不可修改
定义:
本质是一个常量,而用指针修饰它。指针常量的值是指针,这个值因为是常量,所以不能被赋值。
关键点:
它是个常量!
指针所保存的地址可以改变,然而指针所指向的值却不可以改变;
指针本身是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化;
//指针常量(指针本身是常量)
#include <stdio.h>
int main() {
int i = 10;
int *const p = &i;
printf("%d\n", *p);//10
//Error,因为p是const 指针,因此不能改变p指向的内容
//p++;//error: increment of read-only variable ‘p’
(*p)++; //OK,指针是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化
printf("%d\n", *p);//11
i = 9;//OK,仍然可以通过原来的声明修改值,
return 0;
}
面试题目 :
介绍 项目
之前在在学校的时候就去培训班参加培训 主要学习C C++ STM32开发和 Qt
参加工作就一直在这家公司工作 产品主要是 手持喷印设备 我主要负责软件的研发工作 主要负责 交互界面 和 业务逻辑实现的工作 入职一开始是修改bug 后面开始自己做项目 过程中业务逻辑的部分是通过开源库 zint freetype 根据用户界面的一些配置生成对应信息的 二维码 一维码字体 用户设置一些参数 和 编辑的喷印模板文件保存在本地 用的Qt的 xml 存储参数配置 读出文件后 导入Qt的 容器 qmap Qlist qvector 和 QVariant 在程序中 调用 。
期间也有做写上位机程序对下位机STM32板子一些功能经行测试 然后上报上位机程序
void * ( * (*fp1)(int))[10];
float (( fp2)(int,int,int))(int);
int (* ( * fp3)())10;
分别表示什么意思?
【标准答案】
1.void * ( * (fp1)(int))[10]; fp1是一个指针,指向一个函数,这个函数的参数为int型,函数的返回值是一个指针,这个指针指向一个数组,这个数组有10个元素,每个元素是一个void型指针。
2.float (( fp2)(int,int,int))(int); fp2是一个指针,指向一个函数,这个函数的参数为3个int型,函数的返回值是一个指针,这个指针指向一个函数,这个函数的参数为int型,函数的返回值是float型。
3.int (* ( * fp3)())10; fp3是一个指针,指向一个函数,这个函数的参数为空,函数的返回值是一个指针,这个指针指向一个数组,这个数组有10个元素,每个元素是一个指针,指向一个函数,这个函数的参数为空,函数的返回值是int型。