【问题标题】:Segmentation fault 11 in following code. How to avoid overflow?以下代码中的分段错误 11。如何避免溢出?
【发布时间】:2017-10-07 08:24:13
【问题描述】:
void main(int argc, char* argv[]) {

    char* hostname = (char*)malloc(sizeof(char)*1024);
    hostname = getClientHostName("122.205.26.34");
    printf("%s\n", hostname);
    free(hostname);
}

char* getClientHostName(char* client_ip) {

    char hostnames[5][2];
    hostnames[0][0] = "122.205.26.34";
    hostnames[0][1] = "aaaaa";
    hostnames[1][0] = "120.205.36.30";
    hostnames[1][1] = "bbbbb";
    hostnames[2][0] = "120.205.16.36";
    hostnames[2][1] = "ccccc";
    hostnames[3][0] = "149.205.36.46";
    hostnames[3][1] = "dddddd";
    hostnames[4][0] = "169.205.36.33";
    hostnames[4][1] = "eeeeee";
    for(int i = 0; i<5; i++) {
        if(!strcmp(hostnames[i][0], client_ip))
            return (char*)hostnames[i][1];
    }
    return NULL;
}

C 初学者。

我不确定是否有更好的方法来实现我正在尝试实现的内容。代码是不言自明的。有什么方法可以预定义主机名的大小,使用一些一般大小的 IP 地址,以避免段错误?有没有更好的方法让我不必对大小进行硬编码?

【问题讨论】:

  • 你的代码不应该编译干净。用gcc -Wall -Wextra -gGCC编译它

标签: c


【解决方案1】:

修复编译器错误和警告后:

const char* getClientHostName(const char* client_ip) {

    const char * hostnames[5][2];
    hostnames[0][0] = "122.205.26.34";
    hostnames[0][1] = "aaaaa";
    hostnames[1][0] = "120.205.36.30";
    hostnames[1][1] = "bbbbb";
    hostnames[2][0] = "120.205.16.36";
    hostnames[2][1] = "ccccc";
    hostnames[3][0] = "149.205.36.46";
    hostnames[3][1] = "dddddd";
    hostnames[4][0] = "169.205.36.33";
    hostnames[4][1] = "eeeeee";
    for(int i = 0; i<5; i++) {
        if(!strcmp(hostnames[i][0], client_ip))
            return hostnames[i][1];
    }
    return NULL;
}

int main(int argc, char* argv[]) {
    const char * hostname = getClientHostName("128.205.36.34");
    printf("%s\n", hostname);
}

【讨论】:

    【解决方案2】:

    有没有更好的方法让我不必对大小进行硬编码?

    养成使用所有警告和调试信息进行编译的习惯:gcc -Wall -Wextra -gGCC。改进代码以完全没有警告。

    如果您想获得真正的 IP 地址,这是特定于操作系统的(因为标准 C11 不知道 IP 地址;请阅读 n1570 进行检查)。在 Linux 上,您将使用名称服务例程,例如 getaddrinfo(3)getnameinfo(3) 或已过时的 gethostbyname(3)

    如果这只是一个与 TCP/IP 套接字没有实际关系的练习(请参阅tcp(7)ip(7)socket(7)),您可以将表存储在一些 global 数组中:

     struct myipentry_st {
       const char* myip_hostname;
       const char* myip_address;
     };
    

    然后定义一个包含它们的global 数组,约定通过一些{NULL, NULL} 条目来终止它:

    const struct myipentry_st mytable[] = {
        {"aaaaa", "122.205.26.34"},
        {"bbbb", "120.205.36.30"},
        /// etc
        {NULL, NULL} // end marker
    };
    

    你最好有一个 globalstatic variable(而不是 automatic 一个坐在 call stack 上),因为你不想在每次调用你的 @ 时都填写它987654349@.

    那么您的查找例程(效率低,因为在线性时间内)将是:

    const char* getClientHostName(char* client_ip) {
       for (const struct myipentry_st* ent = mytable;
            ent->myip_hostname != NULL;
            ent++)
       // the if below is the only statement of the body of `for` loop
         if (!strcmp(ent->myip_address, client_ip))
             return ent->myip_hostname;
       // this happens after the `for` when nothing was found
       return NULL;
    }
    

    您甚至可以将该表声明为heap allocated 指针:

    const struct myipentry_st**mytable;
    

    然后使用calloc 分配它并从某个文本文件中读取它的数据。

    阅读您正在使用的每个standard 或外部函数的文档。不要忘记检查失败(例如calloc,如here)。通过适当地调用free 来避免memory leaks。使用调试器gdbvalgrind。当心undefined behavior

    在现实世界中,您可能会有数千个条目,并且您会执行多次查找(可能是数百万次,例如,对于 Web 服务器或客户端中的每个 HTTP 请求一次)。然后选择更好的data structurehash tablered-black tree 可能)。阅读一些Introduction to Algorithms

    【讨论】:

    • 感谢您的意见。但问题是,我绝对可以实施更好的方法,而且我可以做到。但不是在 C 中。这是我第一次在 C 中编码。第一次。就像,第一次。我有一周的时间来完成这项任务。所以我没有足够的时间来学习 C。我对 Java 和某种程度上的 Python 更熟悉,但 C 非常不同。所以现在我只是想让它以某种方式工作。
    【解决方案3】:

    * 添加到类型定义char * hostnames[5][2]。这必须是指针数组,而不是简单的chars。另一个必要的更改是strcpy,而不是strcpy( hostname, getClientHostName("122.205.26.34") ); 中的=

    PS:总是尝试编译时出现 0 个编译器警告,而不仅仅是 0 个错误!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      • 2012-05-16
      • 2010-11-14
      • 2022-06-16
      相关资源
      最近更新 更多