打印 inet_ntoa 函数中的分段错误
segmentation fault in printing inet_ntoa function
考虑以下程序:
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
void printhost(char* pLocalHostAddress )
{
struct hostent * pHost;
struct in_addr **pptr;
char hostName[128]="[=11=]";
gethostname(hostName, sizeof(hostName));
printf("%s",hostName);
if( NULL != (pHost = gethostbyname(hostName)) )
{
memcpy( pLocalHostAddress, *pHost->h_addr_list, 4);
printf("ip address: %s\n",inet_ntoa(**(struct in_addr **)&pLocalHostAddress));
}
}
void main()
{
char pLocalHostAddress[50];
printhost((char *)pLocalHostAddress);
printf("ip address: %s\n",inet_ntoa(**(struct in_addr **)&pLocalHostAddress));
}
奇怪的是,当我尝试在 printhost()
函数中打印时,它正确地打印了主机 IP 地址,但是当我尝试从 main()
函数中打印时却出现分段错误。有人可以澄清一下吗?
注意:我不熟悉所讨论的功能,但我的回答基于 this explanation and this documentation。
将函数替换为:
struct in_addr *printhost(void)
{
// ...
if( NULL != (pHost = gethostbyname(hostName)) )
{
struct in_addr *tmp = (struct in_addr *)*pHost->h_addr_list;
printf("ip address: %s\n",inet_ntoa(*tmp));
return tmp;
}
return NULL;
}
并这样称呼它:
struct in_addr *p = printhost();
if ( p )
printf("ip address: %s\n",inet_ntoa(*p));
您的代码以多种方式导致未定义的行为。当未定义的行为被触发时,任何事情都可能发生,包括相同的代码似乎在一个地方工作而在另一个地方不工作。分析得太深入是徒劳的,还不如把代码搞定。
memcpy( pLocalHostAddress, *pHost->h_addr_list, 4);
将 struct in_addr
的前 4 个字节复制到 main
中 50 字节缓冲区的开头。我假设 sizeof(struct in_addr)
在你的系统上实际上是 4 个字节 as suggested by this page 否则你的代码会更糟。一般来说,您应该使用 sizeof
表达式来计算要复制多少。
然后将 struct in_addr
传递给 inet_ntoa
就可以了。在您的函数中,&pLocalHostAddress
是 指向 包含 struct in_addr
缓冲区的指针的地址。所以你取消引用两次以获得结构。
但在 main
中,&pLocalHostAddress
是 包含 struct in_addr
的缓冲区 的地址。所以你应该只取消引用一次。相反,您的代码会尝试将 Internet 地址解释为指针的字节,从而在您取消引用该指针时导致分段错误。
如果您将 main
中的代码更改为 inet_ntoa(*(struct in_addr *)&pLocalHostAddress)
,您的代码可能 看起来可以工作 ,但是实际上坚持使用是个坏主意这样的代码。
我明白了,正如 M.M 告诉 "you have two different variables in your code both named pLocalHostAddress" 的那样,双重取消引用是问题所在。
以下程序正在运行:
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
void printhost(char* pLocalHostAddress )
{
struct hostent * pHost;
struct in_addr **pptr;
char hostName[128]="[=10=]";
gethostname(hostName, sizeof(hostName));
printf("%s",hostName);
if( NULL != (pHost = gethostbyname(hostName)) )
{
memcpy( pLocalHostAddress, *pHost->h_addr_list, 4);
printf("ip address: %s\n",inet_ntoa(*(struct in_addr *)pLocalHostAddress));
}
}
void main()
{
char pLocalHostAddress[50];
printhost(pLocalHostAddress);
printf("ip address: %s\n",inet_ntoa(*(struct in_addr *)pLocalHostAddress));
}
考虑以下程序:
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
void printhost(char* pLocalHostAddress )
{
struct hostent * pHost;
struct in_addr **pptr;
char hostName[128]="[=11=]";
gethostname(hostName, sizeof(hostName));
printf("%s",hostName);
if( NULL != (pHost = gethostbyname(hostName)) )
{
memcpy( pLocalHostAddress, *pHost->h_addr_list, 4);
printf("ip address: %s\n",inet_ntoa(**(struct in_addr **)&pLocalHostAddress));
}
}
void main()
{
char pLocalHostAddress[50];
printhost((char *)pLocalHostAddress);
printf("ip address: %s\n",inet_ntoa(**(struct in_addr **)&pLocalHostAddress));
}
奇怪的是,当我尝试在 printhost()
函数中打印时,它正确地打印了主机 IP 地址,但是当我尝试从 main()
函数中打印时却出现分段错误。有人可以澄清一下吗?
注意:我不熟悉所讨论的功能,但我的回答基于 this explanation and this documentation。
将函数替换为:
struct in_addr *printhost(void)
{
// ...
if( NULL != (pHost = gethostbyname(hostName)) )
{
struct in_addr *tmp = (struct in_addr *)*pHost->h_addr_list;
printf("ip address: %s\n",inet_ntoa(*tmp));
return tmp;
}
return NULL;
}
并这样称呼它:
struct in_addr *p = printhost();
if ( p )
printf("ip address: %s\n",inet_ntoa(*p));
您的代码以多种方式导致未定义的行为。当未定义的行为被触发时,任何事情都可能发生,包括相同的代码似乎在一个地方工作而在另一个地方不工作。分析得太深入是徒劳的,还不如把代码搞定。
memcpy( pLocalHostAddress, *pHost->h_addr_list, 4);
将 struct in_addr
的前 4 个字节复制到 main
中 50 字节缓冲区的开头。我假设 sizeof(struct in_addr)
在你的系统上实际上是 4 个字节 as suggested by this page 否则你的代码会更糟。一般来说,您应该使用 sizeof
表达式来计算要复制多少。
然后将 struct in_addr
传递给 inet_ntoa
就可以了。在您的函数中,&pLocalHostAddress
是 指向 包含 struct in_addr
缓冲区的指针的地址。所以你取消引用两次以获得结构。
但在 main
中,&pLocalHostAddress
是 包含 struct in_addr
的缓冲区 的地址。所以你应该只取消引用一次。相反,您的代码会尝试将 Internet 地址解释为指针的字节,从而在您取消引用该指针时导致分段错误。
如果您将 main
中的代码更改为 inet_ntoa(*(struct in_addr *)&pLocalHostAddress)
,您的代码可能 看起来可以工作 ,但是实际上坚持使用是个坏主意这样的代码。
我明白了,正如 M.M 告诉 "you have two different variables in your code both named pLocalHostAddress" 的那样,双重取消引用是问题所在。 以下程序正在运行:
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
void printhost(char* pLocalHostAddress )
{
struct hostent * pHost;
struct in_addr **pptr;
char hostName[128]="[=10=]";
gethostname(hostName, sizeof(hostName));
printf("%s",hostName);
if( NULL != (pHost = gethostbyname(hostName)) )
{
memcpy( pLocalHostAddress, *pHost->h_addr_list, 4);
printf("ip address: %s\n",inet_ntoa(*(struct in_addr *)pLocalHostAddress));
}
}
void main()
{
char pLocalHostAddress[50];
printhost(pLocalHostAddress);
printf("ip address: %s\n",inet_ntoa(*(struct in_addr *)pLocalHostAddress));
}