1. new 和 malloc的区别:
new是 C++ 中的操作符,而malloc是 C 语言中的函数。
new在分配内存的同时会调用对象的构造函数进行初始化,而malloc只是简单地分配一块指定大小的内存空间。
new返回的是对象类型的指针,而malloc返回的是void*类型的指针,需要进行显式的类型转换。
new抛出异常(如 std::bad_alloc)来处理内存分配失败的情况,而malloc在内存分配失败时返回空指针(NULL)。
2. malloc的底层实现:
malloc函数的底层实现会根据具体的操作系统和编译器而有所不同。通常,它会使用操作系统提供的堆管理机制来分配所需的内存空间。一般情况下,malloc调用了系统调用(如 brk或 sbrk)来扩展进程的堆空间,然后将分配到的内存块返回给调用者。
3. 指针与引用的相同和区别;如何相互转换?
相同点:
指针和引用都可以用于访问变量或对象。
指针和引用都可以作为函数参数传递,允许对传入的变量进行修改。
区别:
指针可以为空(NULL),但引用必须始终引用一个已存在的对象。
指针可以被重新赋值指向其他对象,而引用一旦绑定到一个对象后就无法改变其引用目标。
引用在声明时必须进行初始化,并且不能有空引用。
指针转换为引用:可以使用解引用操作符 *将指针转换为引用,例如 int& ref = *ptr;。
引用转换为指针:可以使用取地址操作符 &将引用转换为指针,例如 int* ptr = &ref;。
4. C 语言检索内存情况,内存分配的方式:
在 C 语言中,可以使用 malloc 和 free 函数进行动态内存分配和释放。此外,还可以使用栈上分配的局部变量(自动变量)和全局变量(静态变量)来进行内存分配。可以通过调试工具或编写代码来检查内存的使用情况和泄漏问题。
5. extern "C"的作用:
extern "C"是 C++ 中的语言特性,用于指定以 C 语言的方式进行函数名重载和链接。当 C++ 代码与 C 代码进行混合编译时,可以使用 extern "C" 来告诉编译器将某段代码按照 C 语言的规则进行处理,避免了 C++ 的名称修饰和函数重载导致的链接错误。
6. memcpy()函数需注意,strcat strncat strcmp strcpy哪些函数会导致内存溢出
确保源地址和目标地址的有效性,避免越界访问。
考虑内存重叠情况,确保拷贝的正确性。
strcat如果目标字符串的空间不足以容纳源字符串,可能导致缓冲区溢出。
strncat如果指定的拼接长度超过目标字符串的剩余空间,可能导致缓冲区溢出。
strcmp如果比较的字符串没有以空字符结尾,可能导致访问非法内存。
strcpy如果源字符串没有以空字符结尾,可能导致访问非法内存。
7. char和int之间的转换
在 C 语言中,可以使用字符型变量和整型变量之间的隐式类型转换。将一个字符赋值给整型变量时,会将字符的 ASCII 值作为整数赋给该变量。将一个整型值赋值给字符型变量时,会将整数的低位字节(如果符合字符范围)作为字符赋给该变量。
显式转换可以通过强制类型转换实现。例如,将字符型转换为整型:int num = (int)ch;,将整型转换为字符型:char ch = (char)num;
8. static的用法(定义和用途)static静态变量,只初始化一次
static关键字在 C 语言中有多种用法和含义:
- 定义静态变量:在函数内部使用 static关键字定义的变量称为静态局部变量,它会在程序运行期间保持其值不变,并且只初始化一次。
- 局部函数:在函数定义前加上 static关键字将函数声明为仅在当前文件可见的静态函数,不能被其他文件访问。
- 静态全局变量:在函数外部或模块内部使用 static关键字定义的全局变量,它的作用域限定在当前文件中,其他文件无法访问。
- 静态函数:在函数定义前加上 static关键字将函数声明为仅在当前文件可见的静态函数,不能被其他文件访问。
9. const的用法(定义和用途)
const 关键字在 C 语言中用于声明常量。它可以用来修饰变量、函数参数和函数返回值。
修饰变量:使用 const 关键字修饰的变量被称为常量,其值在初始化后不能被修改。
修饰函数参数:使用 const 关键字修饰函数参数表示该参数在函数体内不会被修改,提高代码的可读性和安全性。
修饰函数返回值:使用 const 关键字修饰函数返回值表示该返回值是只读的,不允许对其进行修改。
10. const常量和#define的区别(编译阶段、安全性、内存占用等)
编译阶段:const 常量在编译时进行类型检查,具有更强的类型安全性,而 #define 宏定义是简单的文本替换,在预处理阶段进行,没有类型检查。
安全性:const 常量具有作用域和命名空间,不会导致命名冲突,而宏定义没有作用域概念,可能引发命名冲突和意外的替换。
内存占用:const 常量在内存中分配了存储空间,每个变量只有一份内存;而宏定义仅仅是文本替换,没有内存占用。
调试信息:const 常量在调试过程中可以提供符号信息,而宏定义不存在符号信息
11. volatile作用和用法
volatile 关键字用于告诉编译器一个变量可能会被意外修改,从而禁止对该变量进行优化。主要用途包括:
用于多线程或并发编程中,标记共享变量,保证每次访问都是对内存的实际读写,避免编译器对变量的优化。
用于与硬件相关的地址或寄存器,因为这些值可能会被硬件或其他程序修改,需要确保每次读取都是实时的。
用于信号处理函数中,防止编译器将对变量的读写操作优化掉,保证正确处理信号。
12. 有常量指针 指针常量 常量引用 没有 引用常量
常量指针:指针指向的地址不可修改,但指针本身可以修改,例如 int* const ptr;。
指针常量:指针本身不可修改,指向的地址可以修改,例如 const int* ptr; 或 int const* ptr;。
常量引用:指向的对象不可修改,例如 const int& ref;。引用本身不可修改。
13. 变量的作用域(全局变量和局部变量)
全局变量:声明在函数外部、代码块外部的变量为全局变量,其作用域从声明处开始到文件末尾,可以被整个程序访问。
局部变量:声明在函数内部或代码块内部的变量为局部变量,其作用域仅限于所在的函数或代码块内部,在外部不可访问。
- 全局变量与局部变量同名时,局部变量会覆盖全局变量的值。
- 静态局部变量:在函数内部使用 `static` 关键字修饰的局部变量称为静态局部变量,其生命周期跨越多次函数调用,但作用域仍限于所在的函数内部。
14. sizeof 与strlen (字符串,数组)
- sizeof 是 C 语言的运算符,用于获取数据类型或变量占用的内存大小(以字节为单位)。
- strlen是 C 语言的库函数,用于计算字符串的长度(不包括结尾的空字符 '\0'),返回值为无符号整型。
15. 经典的sizeof(struct)和内存对齐(一字节对齐)
- sizeof(struct) 用于计算结构体的大小,包括结构体中所有成员的大小之和,可能会受到内存对齐的影响。
- 内存对齐是为了提高访问效率和处理器的要求,结构体中的成员在内存中按照特定规则对齐,通常以成员大小或者指定的对齐值为基准进行对齐。
一字节对齐指的是结构体中的每个成员都从结构体的起始地址开始,不考虑对齐规则,占用实际大小
16. const * char 与 const char *
const * char 是指向字符常量的指针,表示指针指向的字符内容不能通过指针修改。
const char *是指向字符的指针,表示指针指向的字符可以通过其他途径修改,但通过该指针本身不可修改。
17. inline函数
inline是 C 语言的关键字,用于声明内联函数。内联函数是一种编译器优化手段,将函数的代码直接插入调用处,避免了函数调用的开销,提高执行效率。使用 `inline` 关键字声明的函数,编译器会尽可能地将其作为内联函数来处理。
18. 内存四区,什么变量分别存储在什么区域,堆上还是栈上
内存四区是指程序运行时的内存划分,包括代码区、全局数据区(静态数据区)、栈区和堆区。不同类型的变量存储在不同的区域。
代码区:
存储程序的可执行代码。
包括函数的机器指令和常量数据。
通常是只读的,不允许修改。
全局数据区(静态数据区):
- 存储全局变量和静态变量。
- 在程序启动时分配,在程序结束时释放。
- 全局变量具有静态生命周期,存在于整个程序运行期间。
栈区:
- 存储局部变量和函数调用所需的上下文信息。
- 通过栈指针进行动态管理,具有自动分配和释放的特性。
- 局部变量具有自动生命周期,随着函数的进入和退出而分配和释放。
堆区:
- 用于动态内存分配。
- 通过函数如malloc()、calloc()和 realloc()进行申请,通过free()进行释放。
- 存储在堆区的变量需要手动管理其生命周期。
总结:
- 全局变量和静态变量存储在全局数据区。
- 局部变量存储在栈区。
- 动态分配的变量(如通过 malloc()分配的内存)存储在堆区。