C语言中strcpy为什么不安全?如何解决?
主要原因是缺乏对输入长度的边界检查,容易导致缓冲区溢出漏洞。
解决:可以使用strncpy函数替代,或者在程序最顶端加入代码段
#define _CRT_SECURE_NO_WARNINGS
缓冲区溢出
缓冲区通常指的是用于存储数据的连续内存块。在输入输出操作中,缓冲区被用来临时存储数据,以便进行读取或写入操作。
缓冲区溢出(Buffer Overflow)是指当往一个缓冲区写入超过其容量的数据时,导致数据溢出到其他内存区域,造成程序运行时的问题。这种情况通常发生在写入数据时缓冲区的大小不足以容纳所写入的数据量。
缓冲区溢出可能会导致以下问题:
- 覆盖数据:超出缓冲区边界的数据可能会覆盖其他数据,导致数据的丢失或损坏。
- 程序崩溃:缓冲区溢出可能引发程序崩溃或异常终止,因为溢出的数据可能会影响程序的控制流和运行状态。
- 安全漏洞:恶意攻击者可以利用缓冲区溢出漏洞执行恶意代码,例如注入恶意指令或覆盖函数返回地址。
C++容器不是线程安全的,怎么解决?
解决非线程安全容器(如map vector)的方法:同步
- 互斥锁实现互斥,即一个共享资源,同时最多只能有一个线程访问;
- 互斥锁 & 条件变量,实现多线程同步;
- 互斥锁 & 信号量,实现多线程同步;
- 读写锁,互斥锁的升级版本。读的部分,多线程可以并行访问;写的部分,同时最多只能有一个线程访问。
- 可以通过固定vector的大小,避免动态扩容(无push_back)来做到 lock-free
互斥不一定同步,同步包含互斥
什么是线程安全容器
线程安全容器是可以支持在多个线程并发访问的STL容器。在多线程程序中使用线程安全容器可以保证数据操作的正确性和安全性。C++ STL库提供了一些线程安全容器(适配器),包括std::stack
和std::queue
,它们都是基于顺序容器实现的。这些容器提供了多个线程的并发访问功能。
为什么需要线程安全容器
在并发环境中,多个线程可能同时访问同一资源。对于非线程安全的容器,在多线程的情况下容易出现数据竞争、死锁等问题。线程安全容器可以避免这种问题的发生,保证程序的正确性。
读写锁和互斥锁有什么区别?
读写锁读的时候会加锁吗?
简述读写锁实现时的二次加锁检测,了解源码
delete没加[]会报错吗?
delete 释放new分配的单个对象指针指向的内存
delete[] 释放new分配的对象数组指针指向的内存
(1). 针对简单类型 使用new分配后的不管是数组还是非数组形式内存空间用两种方式均可 如:
int *a = new int[10];
delete a;
delete [] a;
此种情况中的释放效果相同,原因在于:分配简单类型内存时,内存大小已经确定,系统可以记忆并且进行管理,在析构时,系统并不会调用析构函数,它直接通过指针可以获取实际分配的内存空间,哪怕是一个数组内存空间(在分配过程中 系统会记录分配内存的大小等信息,此信息保存在结构体_CrtMemBlockHeader中,具体情况可参看VC安装目录下CRT\SRC\DBGDEL.cpp
(2). 针对类Class,两种方式体现出具体差异
当你通过下列方式分配一个类对象数组:
class A{
private:
char *m_cBuffer;
int m_nLen;
public:
A(){ m_cBuffer = new char[m_nLen]; }
~A() { delete [] m_cBuffer; }
};
A *a = new A[10];
delete a; //仅释放了a指针指向的全部内存空间
//但是只调用了a[0]对象的析构函数 剩下的从a[1]到a[9]这9个用户
//自行分配的m_cBuffer对应内存空间将不能释放 从而造成内存泄漏
delete [] a;
//调用使用类对象的析构函数释放用户自己分配内存空间并且
//释放了a指针指向的全部内存空间
所以总结下就是,如果ptr代表一个用new申请的内存返回的内存空间地址,即所谓的指针,那么:
delete ptr 代表用来释放内存,且只用来释放ptr指向的内存。
delete[] rg 用来释放rg指向的内存,!!还逐一调用数组中每个对象的destructor!!
对于像int/char/long/int*/struct等等简单数据类型,由于对象没有destructor,所以用delete 和delete [] 是一样的!但是如果是C++对象数组就不同了!
vector和list的区别
vector 拥有一块连续的内存,因此支持随机访问,如果需要高效率的访问,而不在乎插入和删除的效率,使用vector
list拥有一段不连续的内存空间,如果需要高效率的插入和删除,而不关心访问效率,使用list
C++程序生成可执行程序的流程
预编译-编译-汇编-链接
C++遇到库不存在时可以编译吗?
虚函数表实现思路
对于虚函数表来说,在编译的过程中编译器就为含有虚函数的类创建了虚函数表,并且编译器会在构造函数中插入一段代码,这段代码用来给虚函数指针赋值。因此虚函数表是在编译的过程中创建。
对于虚函数表指针来说,由于虚函数表指针是基于对象的,所以对象在实例化的时候,虚函数表指针就会创建,所以是在运行时创建。由于在实例化对象的时候会调用到构造函数,所以就会执行虚函数表指针的赋值代码,从而将虚函数表的地址赋值给虚函数表指针。