这一系列文章会从网络各位同学的面试笔记和常考点进行汇总,主要是针对面试的C++后台开发岗位,涵盖了大部分C++相关的可能会被问道的技术点。笔记大都是比较基础的C++知识点的总结。
gdb调试命令
step和next的区别:
内存查看:
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))
|
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 ; }
|