You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中指针、结构体与memset的使用疑问

关于C语言指针、结构体与memset的问题解答

一、memset在自定义函数中仅置零首个成员的原因

大概率是你在函数里用错了sizeof的计算对象。比如你写的是:

void fun(struct car* ptr) {
    memset(ptr, 0, sizeof(ptr)); // 错误:sizeof(ptr)取的是指针的大小,不是结构体的大小
}

ptr是指针变量,32位系统下占4字节,64位系统下占8字节。如果你的struct car第一个成员name是指针类型(刚好占4/8字节),那memset只会把这部分内存置零,后面的speed、price自然不会被修改。

正确写法应该指定结构体的内存大小:

void fun(struct car* ptr) {
    memset(ptr, 0, sizeof(struct car)); // 正确:直接指定结构体类型的大小
}
// 更安全的写法(避免写错结构体名):
void fun(struct car* ptr) {
    memset(ptr, 0, sizeof(*ptr)); // 取指针指向对象的大小
}

你在main函数里能成功置零所有成员,是因为你直接用了sizeof(struct car)或者sizeof(结构体变量),覆盖了整个结构体的内存空间。

二、C语言的传值机制

C语言里所有函数参数都是传值,也就是说函数拿到的是实参的一份独立副本:

  • 如果传的是struct car* p,函数里的参数ptr是另一个指针,它和p指向同一块内存,但ptr本身是独立变量。所以在函数里修改ptr本身(比如ptr = NULL),main里的p不会变化;但修改ptr指向的内容(比如ptr->speed = 0),会影响main里的结构体,因为它们指向同一块内存。
  • 如果传的是结构体本身(不是指针),函数会拷贝整个结构体,修改副本不会影响原结构体。

三、void*指针的使用问题

void*是通用指针类型,C标准允许任何对象类型的指针转换为void*,也允许void*转换回原指针类型(写代码时加上强制转换会更清晰)。

比如struct car* p; void* s = &p;,这里&p的类型是struct car**(指向指针的指针),它可以赋值给void*,符合通用指针的规则。但这种写法的合理性要看场景:

  • 写通用工具函数(比如内存分配、拷贝函数)时,用void*可以处理任意类型的指针,这是合理的。
  • 但在明确类型的业务代码里,不建议这么写——void*丢失了类型信息,后续使用时如果转换错误,会导致难以排查的bug。比如把struct car**存在void*里,之后误转换成struct car*去用,直接就会出错。

四、手动逐个赋值结构体成员是否为良好实践

分场景判断:

  • 如果结构体成员少,或者只需要初始化部分成员:手动赋值是很好的实践,比如car.name = NULL; car.speed = 0; car.price = 0;,代码清晰可读性高,还能避免memset的潜在问题(比如结构体包含非POD类型、位域,或者有需要特殊初始化的成员时,memset置零可能不符合预期)。
  • 如果结构体很大,或者需要全置零:用memset或者结构体初始化器更高效。比如struct car c = {0};(C标准规定,未明确初始化的成员会自动置零),这种写法比memset更安全简洁。
  • C99及以后支持指定初始化器,比如struct car c = {.name = NULL, .speed = 120, .price = 150000};,可以精准初始化指定成员,剩下的自动置零,兼顾清晰和效率。

内容的提问来源于stack exchange,提问作者Tryint0learn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 20:55:21