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

C语言中struct sockaddr_in*指针使用触发段错误的原因

两种写法运行结果差异的根本原因

核心问题是崩溃版本传入函数的是未初始化的野指针,没有指向合法可访问的struct sockaddr_in结构体内存。


崩溃代码的问题

触发段错误的代码逻辑如下:

int main(){
  struct sockaddr_in* s;
  f(s);
}

这里的s只是一个指针类型的变量,本身仅占用栈上很小的空间(32位系统通常为4字节,64位系统通常为8字节),作用是存储一块内存的地址。但代码中从来没有给s赋过合法的地址值,它存储的是栈空间残留的随机垃圾值,也就是常说的野指针。
当把这个野指针传入f函数后,函数内部执行in->sin_addr.s_addr = htonl(INADDR_ANY)这类赋值操作时,本质是向那个随机垃圾地址对应的内存位置写入数据。这块内存要么不属于当前进程的合法地址空间,要么是受系统保护的只读区域,会直接触发操作系统的内存保护机制,抛出段错误终止进程。


正常运行代码的逻辑

可正常运行的两种写法本质完全一致,都是给函数传入了指向合法结构体实例的有效指针:

  • 第一种写法中struct sockaddr_in s;直接在栈上分配了一整块大小匹配struct sockaddr_in的内存,s就是真实存在的结构体实例,通过&s取到的是这块合法内存的起始地址,传入函数后,所有对in->xxx的赋值操作都是在读写当前进程有权限访问的栈内存,不会触发访问错误。
  • 第二种写法中的指针p最终被赋值为&s,也就是让p存储了栈上合法结构体实例的地址,此时p不再是野指针,传入函数后自然可以正常工作。

补充说明

不要混淆“定义结构体指针”和“创建结构体实例”两个概念:指针本身只是存储内存地址的容器,必须让它指向一块真实存在、可读写、大小足够容纳目标结构体的内存后,才能通过指针访问结构体成员。除了栈上定义结构体取地址的方式,也可以通过堆内存分配实现同样的效果,示例如下:

int main(){
  struct sockaddr_in* s = malloc(sizeof(struct sockaddr_in));
  if (s == NULL) {
    // 处理内存分配失败的逻辑
    return 1;
  }
  f(s);
  // 堆内存用完后需要手动释放
  free(s);
  return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:54:27