面试-C++-01

这一系列文章会从网络各位同学的面试笔记和常考点进行汇总,主要是针对面试的C++后台开发岗位,涵盖了大部分C++相关的可能会被问道的技术点。笔记大都是比较基础的C++知识点的总结。

gdb调试命令

step和next的区别:

  • next 执行到下一句
  • step进入到函数

内存查看:

1
2
3
4
5
6
7
8
// 打印变量地址
(gdb)p &a
// 查看内存单元内变量
(gdb)x 0xbffff543
0xbffff543: 0x12345678
//单字节查看4个内存单元变量的值
(gdb) x /4xb 0xbffff543
0xbffff543: 0x78 0x56 0x34 0x12

多线程调试:

1
2
3
4
5
6
(gdb) info threads:查看GDB当前调试的程序的各个线程的相关信息
(gdb) thread threadno:切换当前线程到由threadno指定的线程
break filename:linenum thread all 在所有线程相应行设置断点,注意如果主线程不会执行到该行,并且启动all-stop模式,主线程执行n或s会切换过去
set scheduler-locking off|on\step 默认off,执行s或c其它线程也同步执行。on,只有当前相称执行。step,只有当前线程执行
show scheduler-locking 显示当前模式
thread apply all command 每个线程执行同意命令,如bt。或者thread apply 1 3 bt,即线程1,3执行bt。

查看调用堆栈:

1
2
3
(gdb)bt
(gdb)f 1 //帧简略信息
(gdb)info f 1 //帧详细信息

断点:

1
2
b test.cpp:11
b test.cpp:main

gdb attach:

1
2
3
gdb->file xxxx->attach pid->这时候进程是停止的->c 继续运行
or
$ sudo gdb attach PID

带参数调试:

1
2
(gdb)set args -l a -C abc
输入参数命令set args 后面加上程序所要用的参数,注意,不再带有程序名,直接加参数。

list命令:

1
2
list linenum  //显示程序第linenum行的周围的程序
list function  //显示程序名为function的函数的源程序

软链接、硬链接:

  • 软链接:ln –s 源文件 目标文件, 会在选定的位置上生成一个文件的镜像,不会占用磁盘空间,类似于Windows的快捷方式。
  • 硬链接:ln 源文件 目标文件,没有参数-s, 会在选定的位置上生成一个和源文件大小相同的文件,无论是软链接还是硬链接,文件都保持同步变化。

函数指针:

1
2
3
4
5
6
7
8
9
函数指针 int (*func)(int, int)

函数指针数组 int (*funcArry[10])(int, int)

const int* p; 指向const int的指针

int const* p; 同上

int* const p; const指针

互斥锁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
pthread_mutex_t m_mutex;
pthread_mutex_init(&m_mutex, NULL)等效于pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
pthread_mutex_lock(&m_mutex);
pthread_mutex_unlock(&m_mutex)
pthread_mutex_destroy(&m_mutex)
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
bool g_flag = false;
void* t1(void* arg)
{
cout << "create t1 thread success" << endl;
pthread_mutex_lock(&m_mutex);
g_flag = true;
pthread_mutex_unlock(&m_mutex);
}

void* t2(void* arg)
{
cout << "create t2 thread success" << endl;
pthread_mutex_lock(&m_mutex);
g_flag = false;
pthread_mutex_unlock(&m_mutex);
}

int main(int argc, char* argv[])
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, t1, NULL);
sleep(2);
pthread_create(&tid2, NULL, t2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
}

大小端转换:

1
2
3
4
#define BigLittleSwap32(A) ((((uint32)(A) & 0xff000000) >> 24) | \
(((uint32)(A) & 0x00ff0000) >> 8) | \
(((uint32)(A) & 0x0000ff00) << 8) | \
(((uint32)(A) & 0x000000ff) << 24))

TCP套接字:

  • 服务器端
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    listenfd = socket(AF_INET , SOCK_STREAM , 0)

    bind(listenfd , (struct sockaddr*)&servaddr , sizeof(servaddr))

    listen(listenfd , LISTENQ)

    connfd = accept(listenfd , (struct sockaddr *)&cliaddr , &clilen))

    n = read(connfd , buff , MAX_LINE)

    write(connfd , buff , n)
  • 客户端
    1
    2
    3
    4
    5
    sockfd = socket(AF_INET , SOCK_STREAM , 0)

    connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr))

    write(sockfd , sendline , strlen(sendline))

"TCP三次握手"

IP分片与重组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MTU是1500是指的以太网的MTU,可以用 netstat -i 命令查看这个值。如果IP层有数据包要传,而且数据包的长度超过了MTU,

那么IP层就要对数据包进行分片(fragmentation)操作,使每一片的长度都小于或等于MTU。

我们假设要传输一个UDP数据包,以太网的MTU为1500字节,一般IP首部为20字节,UDP首部为8字节,数据的净荷(payload)

部分预留是1500-20-8=1472字节。如果数据部分大于1472字节,就会出现分片现象,

偏移量的单位为8Byte

以ID标示是不是同一个分片,以偏移量标示在保文里的位置,每个不完整的ID报文有一个等待计时器,到时丢弃IP层不保证能够送达,

如果丢了上层自己处理参考rfc 791
IP报文长度单位口诀:
4字节单位 - 首部长度单位 1字节单位 - 总长度单位 8字节单位 - 片偏移单位

Vector && List

  • vector
    1
    2
    3
    4
    5
    6
    7
    vector和数组类似,拥有一段连续的内存空间,并且起始地址不变。

    因此能高效的进行随机存取,时间复杂度为o(1);

    但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存块的拷贝,时间复杂度为o(n)。

    另外,当数组中内存空间不够时,会重新申请一块内存空间并进行内存拷贝。
  • list.
    1
    2
    3
    4
    5
    list是由双向链表实现的,因此内存空间是不连续的。

    只能通过指针访问数据,所以list的随机存取非常没有效率,时间复杂度为o(n);

    但由于链表的特点,能高效地进行插入和删除。

Vector动态内存分配:

1
这个问题其实很简单,在调用push_back时,若当前容量已经不能够放入心得元素(capacity=size),那么vector会重新申请一块内存,把之前的内存里的元素拷贝到新的内存当中,然后把push_back的元素拷贝到新的内存中,最后要析构原有的vector并释放原有的内存。所以说这个过程的效率是极低的,为了避免频繁的分配内存,C++每次申请内存都会成倍的增长,例如之前是4,那么重新申请后就是8,以此类推。当然不一定是成倍增长,比如在我的编译器环境下实测是0.5倍增长,之前是4,重新申请后就是6

new && malloc:

  • new和malloc最大区别: new会调用类的构造函数,malloc不会;
  • delete和free同理;new/delete是运算符,malloc/free函数。所以new/delete效率应该会高点。

手动实现strcpy:

1
2
3
4
5
6
7
8
9
10
char *strcpy(char *strDest, const char *strSrc)
{
if ( strDest == NULL || strSrc == NULL)
return NULL ;
if ( strDest == strSrc)
return strDest ;
char *tempptr = strDest ;
while( (*strDest++ = *strSrc++) != ‘/0’)
return tempptr ;
}