打印inet_ntoa函数中的分段错误

时间:2015-09-11 07:35:50

标签: c sockets host gethostbyname

考虑以下计划:

#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]="\0";

   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()函数打印时出现分段错误。有人可以澄清一下吗?

2 个答案:

答案 0 :(得分:1)

注意:我不熟悉相关功能,但我的答案基于this explanationthis 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),则代码可能似乎 ,但实际上仍然坚持使用此类代码是个坏主意。

答案 1 :(得分:0)

我明白了,双重解除引用就是问题所在,因为M.M告诉你,你的代码中有两个不同的变量,名为pLocalHostAddress&#34;。 以下计划正在运作:

#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]="\0";

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