【问题标题】:segmentation fault in printing inet_ntoa function打印 inet_ntoa 函数中的分段错误
【发布时间】:2015-09-11 07:35:49
【问题描述】:

考虑以下程序:

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

【问题讨论】:

  • **(struct in_addr **)&amp;pLocalHostAddress) - 到底是什么
  • 我已经删除了 c++ :)
  • 数组自然衰减为指针(指向第一个元素),您无需将数组强制转换为指针。
  • 顺便说一句,您的代码中有两个不同的变量,都名为pLocalHostAddress。他们有不同的地址,所以你不应该期望通过别名地址得到相同的结果
  • 正如@M.M 所说,到底是什么。您是否看过 inet_ntoa 的手册页?

标签: c sockets host gethostbyname


【解决方案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-&gt;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 就可以了。在您的函数中,&amp;pLocalHostAddress指向包含struct in_addr 的缓冲区的地址。因此,您取消引用两次以获取结构。

但在main 中,&amp;pLocalHostAddress 是包含struct in_addr缓冲区 的地址。所以你应该只取消引用一次。相反,您的代码会尝试将 Internet 地址解释为指针的字节,当您取消引用该指针时会导致分段错误。

如果您将 main 中的代码更改为 inet_ntoa(*(struct in_addr *)&amp;pLocalHostAddress),您的代码可能似乎可以工作,但实际上坚持使用此类代码是个坏主意。

【讨论】:

  • 感谢您的回答,它会起作用,但我要问的是“函数内部的 printf 工作正常的原因是什么,但是当我尝试在主函数中打印它时会出现分段错误。”
  • 你是对的,我不应该在 main 中有两次尊重,这是错误的,谢谢你的详细回答。
【解决方案2】:

我明白了,双重取消引用是问题所在,正如 M.M 所说的“你的代码中有两个不同的变量,都名为 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]="\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));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-03
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 2015-12-28
    相关资源
    最近更新 更多