string.h库函数中的坑

本文详细解释了C语言中sizeof运算符与strlen函数的工作原理。sizeof并非真正的函数调用,而是编译期间处理的类型信息;strlen则返回字符串长度,但其结果为无符号整型,这一点常被忽视。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sizeof

1.它并不是一个函数,它并不传参数本身,只传参数的类型,比如说写一个小段代码

int a=10;

int size;

size = sizeof(a);

实际在编译过程时

size =sizeof(a);已经变成size =sizeof( int );传递的是参数类型,忽略参数本身,如果这样写: size = sizeof(a++);  a++是不会被执行的


strlen

char arr1[] = "abc";

	char arr2[] = "abcdef";
	if (strlen(arr1) - strlen(arr2) > 0)//
	{
		printf("arr1>arr2\n");
	}
	else
	{
		printf("arr1<=arr2\n");
	}

按照一般的思维应该输出 arr1<=arr2    实际上会输出 arr1>arr2,那是因为strlen的返回类型为无符号整型,无符号类型减去一个无符号类型依然是无符号类型.

strlen声明的原型:size_t strlen ( const char * str );



<think>首先,用户的问题是:“我想了解memset和bzero的详细用法及常见错误点 请问memset 和 bzero 函数的详细用法以及使用过程中可能遇到的点”。用户要求了解memset和bzero函数的详细用法以及常见错误点。 根据系统级指令,我需要: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 参考提供的引用: - 引用[1]: 提到bzero和memset,以及UNIX网络编程作者推荐bzero因为它更容易记忆。 - 引用[2]: 讨论bzero和memset的区别。 - 引用[3]: 详细比较了bzero和memset,包括作者推荐bzero的原因(避免参数错误)和性能考虑。 - 引用[4]: 提问为什么在socket地址结构清0时使用bzero而不是memset。 - 引用[5]: 介绍memset和bzero的用法,并提到memset可能导致虚函数表指针被置NULL的问题。 用户的问题集中在用法和常见错误点上,所以我需要基于这些引用构建回答。 回答结构: 1. **介绍函数**:简要解释memset和bzero是什么。 2. **详细用法**:给出函数原型、参数解释和示例。 3. **常见错误点**:列出使用中可能遇到的问题。 4. **比较和推荐**:基于引用,讨论两者的区别和适用场景。 5. **生成相关问题**:在末尾添加相关问题。 确保使用中文。 **步骤分解:** - **memset函数**: - 原型:`void *memset(void *s, int c, size_t n);` - 功能:将指针s指向的内存区域的前n个字节设置为值c。 - 常见错误:参数顺序错误(c和n互换),可能导致未定义行为;在C++中使用时可能破坏虚函数表。 - **bzero函数**: - 原型:`void bzero(void *s, size_t n);`(根据引用,bzero有两个参数) - 功能:将指针s指向的内存区域的前n个字节设置为0。 - 常见错误:bzero不是ANSI C标准函数,可能在某些环境中不可用。 从引用中: - bzero更易记忆,因为只有两个参数,减少了参数错误的风险(如memset中c和n互换)。 - memset是ANSI C标准函数,bzero是POSIX遗留函数。 - 在C++中,memset可能破坏对象,如果对象包含虚函数。 常见错误点: 1. **参数错误**:对于memset,第二个参数是int,第三个是size_t;如果互换,可能导致错误(如引用[3]所述)。 2. **标准兼容性**:bzero在POSIX中已标记为遗留,不推荐使用;memset是标准C函数。 3. **性能问题**:引用提到性能比较未详细说明,但可能因实现而异。 4. **C++特定问题**:memset可能破坏虚函数表指针(引用[5])。 回答结构: - 开头介绍。 - 分节解释memset和bzero的用法。 - 列出常见错误点。 - 比较两者。 - 给出建议。 - 生成相关问题。 使用引用标识: - 在相关段落末尾添加[^1], [^2]等,基于提供的引用。 生成相关问题: - 例如:1. 如何避免memset的参数错误?2. bzero在现代编程中是否还推荐使用?3. 在C++中如何安全地初始化内存? 最终回答应清晰、逐步。</think>### memset 和 bzero 函数的详细用法及常见错误点 在C/C++编程中,`memset` 和 `bzero` 是用于内存初始化的常用函数,尤其在网络编程或数据结构操作中频繁使用。它们都能将指定内存区域设置为特定值,但在用法、标准兼容性和潜在风险上存在差异。下面我将逐步解释它们的详细用法、常见错误点,并基于真实场景提供建议。内容参考了相关文档和常见实践[^1][^2][^3]。 #### 1. **memset 函数的详细用法** - **函数原型**: `void *memset(void *s, int c, size_t n);` 其中: - `s`:指向要初始化的内存块的指针。 - `c`:要设置的值(以 `int` 形式传入,但实际使用时会被转换为 `unsigned char`)。 - `n`:要设置的字节数(类型为 `size_t`)。 - **功能**:将内存区域 `s` 的前 `n` 个字节设置为值 `c`。常用于清零、填充固定值或初始化数组。 - **示例代码**: ```c #include <string.h> int main() { char buffer[100]; // 将buffer全部设置为0 memset(buffer, 0, sizeof(buffer)); // 将buffer前10个字节设置为'A'(ASCII值65) memset(buffer, 'A', 10); return 0; } ``` - **常见用途**: - 清零内存:如 `memset(ptr, 0, size)`。 - 填充特定值:例如初始化缓冲区为特定字符。 #### 2. **bzero 函数的详细用法** - **函数原型**: `void bzero(void *s, size_t n);` 其中: - `s`:指向要初始化的内存块的指针。 - `n`:要清零的字节数(类型为 `size_t`)。 - **功能**:专门将内存区域 `s` 的前 `n` 个字节设置为0。它是 `memset` 的简化版,仅用于清零操作。 - **示例代码**: ```c #include <strings.h> // 注意:bzero 需要此头文件 int main() { char buffer[100]; // 将buffer全部清零 bzero(buffer, sizeof(buffer)); return 0; } ``` - **常见用途**: - 快速清零:在网络编程中常用于初始化 socket 地址结构(如 `struct sockaddr_in`)[^4]。 #### 3. **常见错误点及点** 使用 `memset` 和 `bzero` 时,易犯以下错误,可能导致程序崩溃、未定义行为或性能问题: - **参数顺序错误(针对 memset)**: - 问题:`memset` 的第二个参数是值 `c`,第三个是字节数 `n`。如果互换(如 `memset(ptr, size, 0)`),编译器可能不报错(因为 `c` 和 `n` 都是整数类型),但行为错误(例如,试图设置无效内存区域)。引用[^3]提到,在《UNIX网络编程》中,作者曾因此错误多次出错。 - 避免方法:始终按 `memset(ptr, value, size)` 顺序调用;使用常量或宏减少错误。 - **标准兼容性问题(针对 bzero)**: - 问题:`bzero` 不是 ANSI C 标准函数,而是 POSIX 遗留函数(在 POSIX.1-2001 中被标记为过时)。在非 POSIX 系统(如 Windows)或严格遵循 C99/C11 标准的项目中,`bzero` 可能不可用或导致编译错误[^1][^3]。 - 避免方法:在跨平台代码中,优先使用 `memset` 代替 `bzero`;或使用宏定义兼容层。 - **C++ 对象初始化风险(针对 memset)**: - 问题:在 C++ 中,如果对象包含虚函数表(vtable)指针,`memset` 会覆盖该指针(因为它直接操作内存)。例如,调用 `memset(&obj, 0, sizeof(obj))` 后,调用虚函数可能崩溃。引用[^5]指出,这会导致程序运行时错误。 - 避免方法:在 C++ 中,避免对类对象使用 `memset`;改用构造函数或 `std::fill`。 - **性能与误用**: - 问题:`memset` 和 `bzero` 的性能差异通常不大,但错误使用(如频繁调用小内存块)可能引发缓存问题。引用[^3]提到,网上有性能争议,但未明确实验数据。 - 避免方法:对大型内存块使用这些函数;避免在热点代码中过度调用。 - **类型安全缺失**: - 问题:两个函数都直接操作字节,不检查类型。例如,`memset` 用于非 POD(Plain Old Data)类型(如 C++ 的带资源类)可能导致资源泄漏。 - 避免方法:仅用于基本数据类型或结构体(确保无虚函数);使用类型安全的替代方案(如 C++ 的 `std::memset` 或智能初始化)。 #### 4. **比较与建议** - **关键区别**: - **参数数量**:`bzero` 只有两个参数(更易记忆),而 `memset` 有三个(易出错)[^3]。 - **功能范围**:`bzero` 仅用于清零;`memset` 更灵活(可设任意值)。 - **标准支持**:`memset` 是 ANSI C/C++ 标准函数,可移植性好;`bzero` 是 POSIX 特定函数,逐渐被弃用[^1][^2]。 - **推荐实践**: - **优先使用 memset**:在通用代码中,`memset` 更安全(标准兼容),尤其当需要非零值时。 - **特定场景用 bzero**:在 POSIX 环境(如 Linux 网络编程)中,`bzero` 可简化清零操作[^4]。但需添加头文件 `#include <strings.h>`。 - **替代方案**:在 C++ 中,使用 RAII 模式或标准库函数(如 `std::fill`)避免内存错误。 #### 5. **总结** `memset` 和 `bzero` 都是高效的内存初始化工具,但错误使用可能导致严重问题。`memset` 灵活但参数易错,`bzero` 简单但兼容性差。建议在清零操作中,如果平台支持,`bzero` 可提高代码可读性;否则优先使用 `memset` 并仔细检查参数[^3][^5]。在实际开发中,结合代码审查和测试可减少风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值