1、编译器常量和运行期常量有什么不同
编译期常量和运行期常量是两种不同的常量类型,它们在常量的定义和使用时具有不同的特点。
-
编译期常量(Compile-time Constant):
- 编译期常量是在编译阶段就能确定其值的常量。编译器在编译代码时可以直接将编译期常量的值替换到使用它的地方,而无需在运行时进行计算或查询。
constexpr
关键字用于声明编译期常量。在 C++11 标准引入constexpr
后,可以使用constexpr
关键字来定义能在编译期求值的常量表达式,例如整数常量、浮点数常量、字符常量等。编译期常量可以在编译时就进行计算,提供了更高效、更安全的常量定义方式。
-
运行期常量(Run-time Constant):
- 运行期常量是在程序运行时才能确定其值的常量。在运行时,运行期常量的值可能由用户输入、读取文件、网络请求等动态获取。
const
关键字用于声明运行期常量。使用const
关键字可以将变量声明为不可修改的常量,即其值在初始化后不能再修改。这种常量在运行时仍然保持不变,但其值无法在编译期间确定。
总结起来,编译期常量是在编译阶段就能确定值的常量,可以使用 constexpr
关键字进行定义;而运行期常量是在程序运行时才能确定值的常量,可以使用 const
关键字进行定义。编译器可以在编译时优化编译期常量的使用,而运行期常量的值需要在程序运行时才能确定。
2、当涉及到内存泄漏检查时,Valgrind和mtrace是两个常用的工具。
-
Valgrind:
Valgrind是一个功能强大的开源工具集,包含多个工具,其中最常用的是Memcheck。Memcheck是Valgrind的内存错误检测工具,可以检测内存泄漏、使用未初始化的内存、访问已释放内存等常见内存错误。使用Valgrind的Memcheck工具,你可以通过以下步骤进行内存泄漏检查:
- 在终端中运行Valgrind的命令,并指定要运行的可执行文件。例如:
valgrind --leak-check=full ./your_program
- Valgrind会运行你的程序,并在程序退出时提供内存泄漏的报告。报告会显示内存泄漏的详细信息,包括泄漏的内存块的大小、位置和堆栈跟踪信息。
Valgrind还提供其他工具,如Cachegrind(用于缓存分析)、Callgrind(用于函数调用分析)等,可用于性能分析和调试。
- 在终端中运行Valgrind的命令,并指定要运行的可执行文件。例如:
-
mtrace:
mtrace是一个简单的内存跟踪工具,用于检测C/C++程序中的内存泄漏。它是GNU C库的一部分,可以通过在程序中调用特定的函数来启用和禁用内存跟踪。使用mtrace进行内存泄漏检查的步骤如下:
- 在程序中包含
mcheck.h
头文件。 - 在程序中调用
mtrace()
函数来启用内存跟踪。 - 运行程序,执行各种操作。
- 在程序退出之前,调用
muntrace()
函数来禁用内存跟踪。 - 运行程序后,mtrace会生成一个内存跟踪报告,其中包含泄漏的内存块的详细信息,如地址、大小和堆栈跟踪。
mtrace的使用相对简单,但它的功能相对有限,适用于简单的内存泄漏检查。对于复杂的程序或大型项目,Valgrind的Memcheck工具通常更为强大和全面。
- 在程序中包含
总结:Valgrind的Memcheck工具提供了全面的内存错误检测和内存泄漏检查功能,适用于各种复杂的程序。而mtrace是一个简单的内存跟踪工具,适用于简单的内存泄漏检查。根据具体的需求和情况,你可以选择适合的工具来进行内存泄漏检查。
3、系统资源泄漏(Resource Leak)是指程序在使用系统分配的资源(如内存、文件句柄、网络连接等)后没有适当地释放这些资源,导致系统资源的浪费和耗尽。
当程序分配资源时,如通过动态内存分配、打开文件、建立网络连接等操作,系统会为其分配相应的资源。这些资源在程序使用完毕后应该被显式地释放,以便系统可以重新利用这些资源。
如果程序没有正确释放这些资源,就会发生资源泄漏。资源泄漏可能会导致以下问题:
-
系统资源浪费:未释放的资源会一直占用系统的内存、文件句柄或网络连接等资源,导致系统资源的浪费。随着时间的推移,资源泄漏会累积,最终导致系统资源不足。
-
系统性能降低:资源泄漏会导致系统的可用资源减少,从而降低系统的性能。例如,内存泄漏会导致系统内存不足,进而影响程序的运行速度和响应性能。
-
系统运行不稳定:资源泄漏可能会导致系统崩溃、死锁或其他异常行为。例如,文件句柄泄漏可能会导致打开文件数超过系统限制,最终导致文件操作失败或系统崩溃。
为避免资源泄漏,程序应该遵循以下几点:
-
在分配资源后,始终记得在不再使用时显式地释放资源,如使用对应的函数进行释放,如
free()
释放内存、close()
关闭文件等。 -
使用合适的作用域和生命周期管理资源。确保在资源不再需要时及时释放,避免资源的长时间占用。
-
使用异常处理机制来捕获可能发生的异常,并确保在异常发生时进行资源的释放。这样可以避免因异常而导致资源无法释放的情况。
-
使用智能指针、RAII(资源获取即初始化)等技术来自动管理资源的生命周期,以减少手动释放资源的疏忽和错误。
通过正确管理和释放系统资源,可以避免资源泄漏问题,提高系统的稳定性和性能。
4、下面的程序运行结果为程序崩溃,因为p无法传递程序运行后的地址。str一直都是null。
5、下面的程序输出乱码,因为p返回的是指向栈内存的地址,函数运行完后原来的地址所放置的内容被抹除。
6、在使用 free()
函数释放内存后,指针仍然保留原来的值,但是这个值不再是有效的内存地址。通过 free()
函数释放内存只是告诉操作系统可以回收该内存块,并且该内存块可以重新分配给其他程序使用,但是指针本身仍然保留原来的值。
在调用 free()
后,为了避免悬挂指针(Dangling Pointer)的问题,通常建议立即将指针设置为 NULL
。将指针设置为 NULL
可以帮助你在后续使用时发现悬挂指针的错误。
以下是释放内存并将指针设置为 NULL
的示例:
int* ptr = (int*)malloc(sizeof(int));
// 使用指针进行操作
free(ptr);
ptr = NULL; // 将指针设置为 NULL
// 现在 ptr 不再指向有效的内存地址,可以避免悬挂指针问题
需要注意的是,在将指针设置为 NULL
之后,你应该避免继续使用指针,以免出现未定义的行为。在后续使用指针之前,应该先重新分配内存并将指针指向有效的内存地址。
7、有副作用编程和无副作用编程的本质区别在于函数执行的结果是否仅依赖于输入参数,是否对外部环境产生可观察的影响。
无副作用编程(Pure Function)的特点是:
- 函数的执行结果仅依赖于输入参数,对于相同的输入参数,始终返回相同的结果。
- 函数在执行过程中不修改任何外部状态,包括全局变量、文件、网络连接等。
- 函数没有观察到的行为,即不会产生任何可观察的副作用,如输出到屏幕、写入文件、修改全局状态等。
有副作用编程(Impure Function)的特点是:
- 函数的执行结果可能依赖于除了输入参数之外的其他因素,如全局变量、文件状态、网络状态等。
- 函数在执行过程中可能修改外部状态,包括全局变量、文件、网络连接等。
- 函数可能产生可观察的副作用,如输出到屏幕、写入文件、修改全局状态等。
本质上,有副作用编程是一种更灵活但也更复杂的编程方式,它允许函数与外部环境进行交互和修改状态。有副作用的函数可以更直接地操作外部资源,但也增加了代码的复杂性和不确定性,因为它们引入了对外部状态的依赖和可能的竞态条件。
相比之下,无副作用编程更加可靠和可预测,因为函数的行为仅取决于输入参数,不会受到外部环境的影响。无副作用的函数更容易进行测试、并发执行和代码优化。
在实际编程中,根据需求和设计目标,可以选择使用有副作用编程或无副作用编程,或者在不同的场景中灵活地结合使用它们。