查找主机名和IP地址时出现分段错误

6
我有以下代码来获取主机名和IP地址,
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h> /* This is the header file needed for gethostbyname() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>


int main(int argc, char *argv[])
{
struct hostent *he;

if (argc!=2){
printf("Usage: %s <hostname>\n",argv[0]);
exit(-1);
}

if ((he=gethostbyname(argv[1]))==NULL){
printf("gethostbyname() error\n");
exit(-1);
}

printf("Hostname : %s\n",he->h_name); /* prints the hostname */
printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr))); /* prints IP address */
}

但是在编译过程中我收到了一个警告:

$cc host.c -o host
host.c: In function ‘main’:
host.c:24: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’

当我运行代码时,出现了分段错误:

./host 192.168.1.4
Hostname : 192.168.1.4
Segmentation fault

代码中有什么错误?

4
你正在对一个无辜的结构体进行可怕的操作。 - SLaks
顺便说一下,在新代码中通常不应使用gethostbyname,主要是因为它不兼容IPv6。您应该使用getaddrinfo替代:http://beej.us/guide/bgnet/output/html/multipage/getaddrinfoman.html - Tyler McHenry
@nsayer 它正在运行 $ ./host www.stackoverflow.com 主机名:stackoverflow.com IP地址:69.59.196.211 - Biranchi
5个回答

8

我有一个类似的代码(如果不是完全相同),在我们学校实验室的一台机器上编译没有问题,但是当我在家里的电脑上编译时,出现了相同的错误(我没有编辑代码)。我阅读了inet的手册,并发现我缺少一个头文件,即#include <arpa/inet.h>。在我的C程序中添加了这个头文件后,它就可以编译和运行了。


6
关于printf格式不匹配的警告是一条重要的警告。在这种情况下,是因为编译器认为函数inet_ntoa返回一个int类型,但你在格式字符串中指定了一个字符串。
函数inet_ntoa的错误返回类型是旧C规则的结果,该规则规定如果你尝试使用一个没有先前声明的函数,则编译器必须假定该函数返回一个int类型并且需要一个未知(但固定)数量的参数。假设返回类型和函数的实际返回类型不匹配会导致未定义行为,在你的情况下表现为崩溃。
解决方法是包含正确的头文件inet_ntoa

1

破解此代码:

printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr)));

转换为:

struct in_addr* address = (in_addr*) he->h_addr;
char* ip_address = inet_ntoa(*address);
printf("IP address: %s\n", ip_address);

这也使得调试和定位问题更加容易。


0
实际上,我只是在我家的FreeBSD机器上编译了那段代码,而且它可以运行。

我在Mac OS上尝试了没有使用#include <arpa/inet.h>的代码,结果它会发出警告并且产生Segmentation Fault。 - Biranchi

0

在尝试对其进行解引用并将其传递给inet_ntoa之前,您可以尝试转储he->h_addr的值。如果它是NULL,那么会导致段错误。

通过strace运行它怎么样?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接