以下代码中的分段故障11。如何避免溢出?

时间:2017-10-07 08:24:13

标签: c

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地址来预定义主机名的大小,以避免seg错误?有没有更好的方法,我不需要硬编码大小?

3 个答案:

答案 0 :(得分:2)

修复编译器错误和警告后,您将获得:

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);
}

答案 1 :(得分:2)

  

有没有更好的方法,我不必硬编码大小?

习惯使用GCC编译所有警告和调试信息:gcc -Wall -Wextra -g。改进代码以完全不发出警告。

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

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

 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
};

你最好有一个全球static variable(而不是automatic一个坐在call stack上,因为你没有想要在每次致电getClientHostName时填写。

然后你的查询程序(低效,因为在线性时间内)将是:

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

答案 2 :(得分:1)

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

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