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

如何保存hostent结果 避免重复调用gethostbyname时被覆盖

解决gethostbyname结果被覆盖的问题

问题背景

调用两次gethostbyname时,第二次的结果会覆盖第一次的,导致两次输出相同:

struct hostent* d = gethostbyname("www.google.com");
struct hostent* b = gethostbyname("www.youtube.com");
printf("%s\n",d->h_name);
printf("%s\n",b->h_name);

输出:

youtube-ui.l.google.com
youtube-ui.l.google.com

直接拷贝hostent结构体的方式无效,因为结构体中的指针仍指向共享的静态缓冲区:

struct hostent d = *(gethostbyname("www.google.com"));
struct hostent b = *(gethostbyname("www.youtube.com"));
printf("%s\n",d.h_name); // 无输出
printf("%s\n",b.h_name); // 输出youtube-ui.l.google.com

原因分析

gethostbyname的返回值指向静态分配的内存缓冲区,所有调用共享这块区域。每次调用都会覆盖缓冲区里的内容,而hostent结构体中的h_name、h_aliases、h_addr_list都是指向该缓冲区内部的指针。直接拷贝结构体只是复制了这些指针,并没有复制指针指向的实际数据,所以第二次调用后,第一次拷贝的结构体里的指针指向的内容已经被覆盖,甚至可能变成无效地址。

解决方案:深拷贝hostent结构

需要手动实现hostent的深拷贝,把结构体本身以及它指向的所有字符串、地址列表都复制到独立的内存区域,这样每次的结果就不会互相覆盖。

实现深拷贝函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>

// 深拷贝hostent结构体
struct hostent* copy_hostent(const struct hostent* src) {
    if (src == NULL) return NULL;

    // 分配hostent结构体内存
    struct hostent* dest = malloc(sizeof(struct hostent));
    if (dest == NULL) return NULL;
    memcpy(dest, src, sizeof(struct hostent));

    // 拷贝h_name
    dest->h_name = strdup(src->h_name);
    if (dest->h_name == NULL) {
        free(dest);
        return NULL;
    }

    // 拷贝h_aliases字符串数组
    int alias_count = 0;
    while (src->h_aliases[alias_count] != NULL) alias_count++;
    dest->h_aliases = malloc((alias_count + 1) * sizeof(char*));
    if (dest->h_aliases == NULL) {
        free(dest->h_name);
        free(dest);
        return NULL;
    }
    for (int i = 0; i < alias_count; i++) {
        dest->h_aliases[i] = strdup(src->h_aliases[i]);
        if (dest->h_aliases[i] == NULL) {
            // 释放已分配的别名
            for (int j = 0; j < i; j++) free(dest->h_aliases[j]);
            free(dest->h_aliases);
            free(dest->h_name);
            free(dest);
            return NULL;
        }
    }
    dest->h_aliases[alias_count] = NULL;

    // 拷贝h_addr_list地址列表
    int addr_count = 0;
    while (src->h_addr_list[addr_count] != NULL) addr_count++;
    dest->h_addr_list = malloc((addr_count + 1) * sizeof(char*));
    if (dest->h_addr_list == NULL) {
        // 释放已分配的别名和name
        for (int i = 0; dest->h_aliases[i] != NULL; i++) free(dest->h_aliases[i]);
        free(dest->h_aliases);
        free(dest->h_name);
        free(dest);
        return NULL;
    }
    for (int i = 0; i < addr_count; i++) {
        dest->h_addr_list[i] = malloc(src->h_length);
        if (dest->h_addr_list[i] == NULL) {
            // 释放已分配的地址
            for (int j = 0; j < i; j++) free(dest->h_addr_list[j]);
            free(dest->h_addr_list);
            // 释放别名和name
            for (int i = 0; dest->h_aliases[i] != NULL; i++) free(dest->h_aliases[i]);
            free(dest->h_aliases);
            free(dest->h_name);
            free(dest);
            return NULL;
        }
        memcpy(dest->h_addr_list[i], src->h_addr_list[i], src->h_length);
    }
    dest->h_addr_list[addr_count] = NULL;

    return dest;
}

// 释放拷贝后的hostent结构体
void free_hostent(struct hostent* hp) {
    if (hp == NULL) return;

    free(hp->h_name);
    for (int i = 0; hp->h_aliases[i] != NULL; i++) free(hp->h_aliases[i]);
    free(hp->h_aliases);
    for (int i = 0; hp->h_addr_list[i] != NULL; i++) free(hp->h_addr_list[i]);
    free(hp->h_addr_list);
    free(hp);
}

使用示例

int main() {
    struct hostent* orig_d = gethostbyname("www.google.com");
    struct hostent* d = copy_hostent(orig_d);

    struct hostent* orig_b = gethostbyname("www.youtube.com");
    struct hostent* b = copy_hostent(orig_b);

    if (d != NULL) printf("%s\n", d->h_name);
    if (b != NULL) printf("%s\n", b->h_name);

    // 记得释放内存
    free_hostent(d);
    free_hostent(b);

    return 0;
}

替代方案:使用线程安全的gethostbyname_r

如果系统支持,可以使用gethostbyname_r函数,它允许你传入自己的缓冲区来保存结果,避免静态缓冲区的共享问题。示例代码:

#include <stdio.h>
#include <netdb.h>
#include <string.h>

int main() {
    struct hostent host_d, host_b;
    char buf_d[1024], buf_b[1024];
    struct hostent *orig_d, *orig_b;
    int herrno_d, herrno_b;

    gethostbyname_r("www.google.com", &host_d, buf_d, sizeof(buf_d), &orig_d, &herrno_d);
    gethostbyname_r("www.youtube.com", &host_b, buf_b, sizeof(buf_b), &orig_b, &herrno_b);

    printf("%s\n", host_d.h_name);
    printf("%s\n", host_b.h_name);

    return 0;
}

注意:gethostbyname_r的参数在不同系统可能有差异,需要参考对应平台的手册。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 21:15:36