【问题标题】:Returning pointer to pointer of structs返回指向结构指针的指针
【发布时间】:2017-03-24 16:46:00
【问题描述】:

我正在开发一个具有多个结构的数据库。我已经定义了一个从 csv 文件加载数据并将每一行存储为结构的函数。我使用双指针存储它们,因此一个指针指向每个结构变量的多个指针。该函数确实正确返回双指针,但是我收到警告:从不兼容的指针类型返回。

我的代码如下:

struct part** loadParts(char* fileName, int m)
{
    typedef struct part
    {
        int id;
        int cost;
    } Part;
    FILE* fptr = fopen(fileName, "r");
    //creat pointer to array of pointers to part structs
    Part** parts;
    parts = malloc((nParts) * sizeof(Part *));
    //length of one line
    char line[1000];

    //while new items can be added
    int i;
    i=0;
    while (fgets(line, sizeof(line), fptr)!= NULL)
    {
            parts[i] = malloc(sizeof(Part));
            //get id
            int id = atoi(strtok(line, ";"));
            parts[i]->id = id;
            // get cost
            int id = atoi(strtok(line, ";"));
            parts[i]->cost = cost;
    i++;
    }
    fclose(fptr);
    return parts;
}

有人知道为什么会出现此警告吗?非常感谢!

【问题讨论】:

  • 你能告诉你代码中的哪个语句收到了警告吗?
  • 谢谢,我在复制代码时出错了! :)
  • 您确定struct part 与您的函数中的Part 相同吗?如果我是你,我会有一个这种类型的全局定义,并在函数内部去掉第二个定义。
  • @Drent,我会完全删除这个定义,因为全局命名空间中已经有一个。
  • @SMFSW 警告是为了突出代码中需要修复的问题,而不是用一个考虑不周的问题来解决问题!

标签: c pointers struct


【解决方案1】:

你有大纲:

struct part** loadParts(char* fileName, int m)
{
    typedef struct part
    {
        int id;
        int cost;
    } Part;
    …
    Part** parts;
    …
    parts = …
    …
    return parts;
}

编译时没有警告是不可能的。根据定义,函数签名中使用的struct part 与函数内部定义的struct part 完全无关。因此,您将在函数中返回指向一种类型的指针,该函数期望返回指向不同类型的指针,即使这些类型可能都拼写为struct part。甚至没有办法让您的代码摆脱困境。

正如 cmets 中所指出的,结构定义必须出现在函数之外,在函数定义之前(并且可能在任何声明之前 - 通常在使用结构的任何地方使用的头文件中)。

因此,修复代码的一种方法是:

typedef struct part
{
    int id;
    int cost;
} Part;

struct part **loadParts(char *fileName, int m)
{
    …
    Part **parts;
    …
    parts = …
    …
    return parts;
}

在这种情况下,您可以让函数返回 Part **

但是,该函数现在应该定义为static,除非您有一个包含结构定义的标头。如果您没有标头,则无法(可靠地)访问其他源文件中的结构类型。 (可以通过将代码写出两次来完成,但写两次代码应该是可恶的——在您完成输入或复制粘贴第二份副本之前,它会成为维护责任。)

您可能正在处理不透明类型;此文件之外的代码不需要了解结构细节。这是合法的;它甚至可以(非常)有益。不过,您只需要一种不同的写作方式:

标题:

typedef struct part Part;
extern struct part **loadParts(char *fileName, int m);

如果您决定不公开名称 Part,则可以改用此标头:

struct part;
extern struct part **loadParts(char *fileName, int m);

第一行说“有一个类型struct part,但稍后会提供详细信息,如果你需要的话”。第二个声明函数返回一个指向struct part 值的指针。 extern 是可选的;我用它——很多人不用。在此代码中,第一行是可选的。但是,如果您将 extern int num_parts(struct part **list); 作为函数,则需要将其显示在 loadParts() 声明之后,或者您需要 struct part; 行来确保原型中的类型不是新的。

来源:

struct part 
{
    int id;
    int cost;
};

struct part **loadParts(char *fileName, int m)
{
    …
    Part **parts;
    …
    parts = …
    …
    return parts;
}

您需要担心标头中的标头保护以确保幂等性。 (在此示例中,不存在自包含问题,但您还应确保您的标题是自包含的——SO 上有多个问题,如果您搜索这些术语,它们将解释这些术语)。

【讨论】:

  • 非常感谢您的详尽解释!我已经实施了您建议的方法来修复我的代码,并且确实有效。我确实有一个标题,所以我不需要将函数设为静态。我将研究您的答案的幂等性部分,因为我不熟悉这个(还)。周末愉快!
猜你喜欢
  • 1970-01-01
  • 2014-12-30
  • 1970-01-01
  • 1970-01-01
  • 2014-09-09
  • 2010-12-01
  • 1970-01-01
相关资源
最近更新 更多