【问题标题】:Returning a null pointer from a C function, comparison seg faults从 C 函数返回空指针,比较段错误
【发布时间】:2016-05-17 12:12:03
【问题描述】:

我正在使用 C 开发文件系统模拟器。 我的 Node 结构如下所示:

typedef struct node
{
  char name[64];
  char type;
  struct node* child;
  struct node* sibling;
  struct node* parent;
}Node;

我的递归函数 findNode() 如果在树中找不到具有特定名称的节点,则返回 NULL。

Node* findNode(char* name, Node* start)
{
  printf("inside findNode, looking for %s, starting at %s\n", name, start->name);
  Node* current = start;
  if(strcmp(name, current->name) == 0)
  {
    printf("inside findNoe, node found.\n");
    return current;
  }
  if(current->sibling->name != 0)
  {
    return findNode(name, current->sibling);
  }
  if(current->child->name != 0)
  {
    return findNode(name, current->child);
  }
  printf("inside findNode, node not found.\n");
  return 0;
}

调用 findNode() 并将其与 0 进行比较后,我的程序出现了段错误。

if(findNode(bname,current) != 0) //seg fault here
  {
    printf("Error: node with basename already exists under directory name.\n"); 
    return;
  }

我知道程序在找不到节点时到达 findNode() 的末尾,因为它会打印“找不到节点”消息。

我的印象是,当返回类型是指针时,可以返回 0。我尝试过使用 NULL,并在比较之前将结果保存到 Node* 变量中。都没有用。

谁能解释这里发生了什么?我真的很感激。提前致谢。

编辑: 代码现在如下所示。开头有一个新的检查来查看 current 是否为 NULL,并且我已经停止尝试访问 childsibling 名称。

Node* findNode(char* name, Node* start)
{
  Node* current = start;
  if(current == NULL)
  {
    printf("inside findNode, NULL passed in\n");
    return NULL;
  }
  printf("inside findNode, looking for %s, starting at %s\n", name, current->name);
  if(strcmp(name, current->name) == 0)
  {
    printf("inside findNode, node found.\n");
    return current;
  }
  if(current->sibling != NULL && current->sibling != root)
  {
    return findNode(name, current->sibling);
  }
  if(current->child != NULL && current->sibling != root)
  {
    return findNode(name, current->child);
  }
  printf("inside findNode, node not found.\n");
  return NULL;
}

第一个测试:“/”和我的根节点,名称为“/”。 第二个测试:“hello”和我的根节点,名称为“/”。应该找不到“你好”。

inside findNode, looking for /, starting at /
inside findNode, node found.
inside findNode, looking for hello, starting at /
inside findNode, node not found.
Segmentation fault

【问题讨论】:

  • 当您尝试访问 NULL 指针时会发生段错误。例如,如果a 是一个空指针并且您试图访问a->name(这是a 的一个属性),那么就会发生段错误。你的问题和这个类似吗?如果是这样,我可以提供详细的描述。
  • return 0;,为什么不return NULL;?从技术上讲,空指针通常定义为(void *) 0;,它使您的代码更易于阅读
  • S_kar,我不这么认为。我唯一一次尝试访问结构的属性是在findNode() 内,而startcurrent 不是NULL,因为findNode() 会结束。我不想比较属性,我想比较指针以确定findNode() 是否找到任何东西。
  • 比较本身不太可能出现段错误。您以某种方式误解了数据。为什么不直接在调试器中运行程序?它会准确地告诉你哪一行代码导致了段错误。可能在findNode 的递归调用之一中。例如,您在取消引用之前不检查 current 是否为 NULL。
  • 埃利亚斯,我都试过了。 0 正是我的教授使用的,所以我想我会保持一致。它们的意思不是一样的吗?

标签: c pointers null segmentation-fault return


【解决方案1】:

我刚刚编写了一个程序来测试您的代码。请注意,在 main 函数中,我刚刚初始化了一个 NULL 指针。

#include <iostream>

using namespace std;

typedef struct node
{
    char name[64];
    char type;
    struct node* child;
    struct node* sibling;
    struct node* parent;
}Node;

Node* findNode(char* name, Node* start)
{
    printf("inside findNode, looking for %s, starting at %s\n", name, start->name);
    Node* current = start;
    if (strcmp(name, current->name) == 0)
    {
        printf("inside findNoe, node found.\n");
        return current;
    }
    if (current->sibling->name != 0)
    {
        return findNode(name, current->sibling);
    }
    if (current->child->name != 0)
    {
        return findNode(name, current->child);
    }
    printf("inside findNode, node not found.\n");
    return 0;
}

int main()
{
    Node *n = NULL;
    char bname[] = "somename";
    Node *current = n;
    if (findNode(bname, current) != 0) //seg fault here
    {
        printf("Error: node with basename already exists under directory name.\n");
    }
}

我得到的输出是(Used Visual Studio 2015)

inside findNode, looking for somename, starting at (null)

正如kaylum 指出的那样,这条线printf("inside findNode, looking for %s, starting at %s\n", name, start-&gt;name); 会导致分段错误。原因是你试图访问一个为空的指针。

首先你需要检查你正在访问的指针是否为NULL。那么你必须访问它的属性或值。

我希望这是有道理的。

【讨论】:

  • 但 Megain 说“它会打印“找不到节点”消息。”
【解决方案2】:

虽然目前信息不足,但我认为是 100%。但可以肯定的是,从函数返回 NULL(或 0)指针在 C 中是完全合法的。

你进入 findNode,它会一直工作,直到在兄弟节点中找不到节点,它会打印“node not found”。

if (current->sibling->name != 0)
{
    return findNode(name, current->sibling);
}

然后,进行可能崩溃的测试,因为 current->child 未指向有效节点。

if (current->child->name != 0)

您可能需要保护对兄弟节点和节点的访问,测试类似:

if (current->sibling && current->sibling->name) {
    return findNode(name, current->sibling);
}
if (current->child && current->child->name) {
    return findNode(name, current->child);
}

如果某些指针指向内存堆栈中的位置,而不是动态分配的内存,则一个问题可能是覆盖错误。一切似乎都很好,直到堆栈展开后进行更多调用,此时函数参数会丢弃自动变量。

【讨论】:

    猜你喜欢
    • 2010-12-25
    • 1970-01-01
    • 2022-11-07
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多