使用 getaddrinfo() 指向导致段错误的结构的指针

Pointer to pointer to struct causing segfault using getaddrinfo()

我正在使用 getaddrinfo() 函数,该函数需要 struct addrinfo ** 来填充结果链接列表,但是当我尝试以下代码时出现段错误...

int main() {
    struct addrinfo **results;
    getaddrinfo("localhost", "http", NULL, results); // segfault here
    return 0;
}

我正在将 struct addrinfo **results 传递给需要该类型的 getaddinfo(),如何导致段错误?

如果我稍微更改我的代码...

int main() {
    struct addrinfo *results;
    getaddrinfo("localhost", "http", NULL, &results); // works        
    return 0;
}

我的代码工作正常。有什么区别?

getaddrinfo 函数将为传递的参数指向的指针赋值。在第一种情况下,您直接传递未初始化的局部变量 results 的值,因此它并没有真正指向任何地方并且取消引用它会导致未定义的行为(表现为崩溃)。在第二种情况下,您将 指针 传递给 results 局部变量,如果函数成功,它将指向第一个 addrinfo 结构。

results最终会指向一个struct addrinfos的链表,你可以遍历这个链表,得到所有与你用第三个参数传入的匹配的地址。函数将使指针指向链表,这就是为什么需要指针的地址。当您传递 struct addrinfo* 变量的地址时,它可以指向列表。取消引用传递的变量就可以了,因为取消引用的值是变量 results 的值。 (这解释了为什么 struct addrinfo *results;&results 有效)。

为什么会出现错误?

指向链表。在来自 here

getaddrinfo 的来源中
2201    int
2202    getaddrinfo (const char *name, const char *service,
2203                 const struct addrinfo *hints, struct addrinfo **pai)
2204    {
...
...
2535      if (p)
2536        {
2537          *pai = p; // in your case this (pai) was uninitialized
2538          return 0;
2539        }
2540    
2541      return last_i ? -last_i : EAI_NONAME;
2542    }

在您的情况下,您提供了一个未初始化的值。取消引用它是未定义的行为。在您的情况下,它导致了分段错误。

进一步澄清这也行得通

int main(void) {
    struct addrinfo *results;
    struct addrinfo **results_addr =  &results;
    getaddrinfo("localhost", "http", NULL, results_addr); // works        
    return 0;
}

但是上面的例子只是为了说明目的,问题不是传递的双指针而是初始化。 只需传递 &result 即可,这样更清晰易读。