1

函数 getManager 创建一个 Manager 结构并从 ManagerP 类型返回一个指向它的指针(这个函数工作正常)。定义是这样的:

typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;  
typedef struct Manager *ManagerP;

//My little code (that does the problem) is this (it's inside main):  

int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000); //this works ok.
foundId = manToFind->ID; //Error : "dereferencing pointer to incomplete type"

你能帮我找出问题吗?我不明白这个错误是什么意思。

谢谢。


编辑:

谢谢,但我刚刚注意到一个问题。这些行在“Manager.c”中。

typedef struct Manager
{
    int ID;
    char name[MAX_NAME_LENGTH];
    int numberOfStudentsInSchool;
    double paycheck;
    double attract;
} Manager;
typedef struct Manager *ManagerP;

在我的主文件中,我确实包含了具有更多定义的“Manager.h”。我刚刚检查过,当我将两个 typedefs 代码(上面写的)移动到主文件时,一切正常。但是我需要将这些 typedefs 放在“Manager.c”中(然后我仍然收到“取消引用指向不完整类型的指针”错误。那么问题是什么?

编辑#2:好的,我正在发布三个文件。当我编译那些我得到错误:“GenSalary.c:9:21: 错误:取消引用指向不完整类型的指针”

这些是文件:

// * Manager.h * :

#ifndef MANAGER_H
#define MANAGER_H
#define MAX_NAME_LENGTH 30

typedef struct Manager *ManagerP;

ManagerP getManager(int ID, const char name[], double paycheck, 
                    double attract, int numberOfStudentsInSchool);

#endif

// * Manager.c * :

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "Manager.h"
#define MAX_PRINT_LENGTH 1000

typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;  

ManagerP getManager(int ID, char const name[], double paycheck,
                    double attract, int numberOfStudentsInSchool)
{
    ManagerP retVal = (ManagerP) malloc(sizeof(struct Manager));
    if (retVal == NULL)
    {
        fprintf(stderr, "ERROR: Out of memory in Manager\n");   
        exit(1);
    }
    retVal->ID = ID;
    strcpy(retVal->name, name);
    retVal->paycheck = paycheck;
    retVal->attract = attract;
    retVal->numberOfStudentsInSchool = numberOfStudentsInSchool;
    return retVal;
}

// * GenSalary.c * :

#include <stdio.h>
#include <stdlib.h>
#include "Manager.h"

int main()
{
    int foundId;
    ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000); //this works ok.
    foundId = manToFind->ID; //Error : "dereferencing pointer to incomplete type"
    return 0;
}

我使用 gcc -Wall GenSalary.c Manager.c -o GenSalary 编译它,我得到: GenSalary.c:9:21: 错误:取消引用指向不完整类型的指针

注意:我不能更改管理器文件(它们属于锻炼)我只能更改主要文件。

感谢您的帮助!

4

5 回答 5

2

如所写,getManager看起来它打算返回的指针是不透明的。如果是这种情况,通常会为调用者应该能够做的任何事情提供函数。例如:

经理.h

...
typedef struct Manager *ManagerP;

ManagerP getManager(int ID, const char name[], double paycheck, 
                    double attract, int numberOfStudentsInSchool);
int getManagerID(ManagerP);

经理.c

...
int getManagerID(ManagerP m) { return m->ID; }

gensalary.c

...
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
foundId = getManagerID(manToFind);

另一种方法是将结构的定义移动到标题中,一切都可以看到它(目前它在标题中前向声明,但只有manager.c知道里面有什么)。

于 2013-08-06T18:11:04.083 回答
1

下面的代码适用于gcc -Wall -pedantic -o test test.c. 但是,我不确定使用typedefs 隐藏指针类型对可读性有什么真正的优势。错误必须来自代码上下文中的某个地方。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Manager
{
    int ID;
    char name[42];
    int numberOfStudentsInSchool;
    double paycheck;
    double attract;
} Manager;
typedef struct Manager *ManagerP;

ManagerP getManager(int x, char *y, double z, double q, int p)
{
    ManagerP foo = malloc(sizeof(Manager));
    foo->ID = x;
    strncpy(foo->name, y, 42);
    foo->numberOfStudentsInSchool = p;
    foo->paycheck = z;
    foo->attract = q;

    return foo;
}

int main(void)
{
    int foundId;
    ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
    foundId = manToFind->ID;
    printf("Found ID: %d\n", foundId);

    return 0;
}
于 2013-08-06T11:15:05.917 回答
1

从您自己的编辑:

我刚刚检查过,当我将两个 typedefs 代码(上面写的)移动到主文件时,一切正常。但我需要将这些 typedef 放在“Manager.c”中

正如您所发现的,您需要包含这些定义才能使其正常工作。将它们放在“Manager.h”中,并在主文件和“Manager.c”中包含“Manager.h”。

编辑:从您的代码中,您还需要typedef在头文件中包含实际结构的 ,而不仅仅是指针的 typedef ,所以移动它:

typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;  

从“Manager.c”中取出,并将其放在 ManagerP 的 typedef 之前。否则,所有主文件看到的只是指针的声明,并且它没有结构实际包含的信息,因此您会得到“不完整类型”错误。

编辑2:如果您“不能更改管理器文件”,那么这是一个有点愚蠢的问题,因为您无法应用最佳答案,但如果确实如此,那么您将拥有将结构定义复制并粘贴到“GenSalary.c”(或新的用户创建的头文件,如果您也需要在其他文件中使用它),因为该文件需要它。由于很多原因,在“GenSalary.c”和“Manager.c”中分别定义结构是一个坏主意,但它是完全合法的 C 语言,并且它会起作用(这就是当你#include在标题下发生的所有事情文件,无论如何)。

于 2013-08-06T12:20:01.600 回答
1

为 ManagerP 执行 typedef 的行将编译,因为它是一个指针声明,但是由于结构管理器位于文件 Manager.c 中并且对 GenSalary.c 不可用,编译器无法知道结构管理器的样子。

所以包含文件Manager.h需要有以下几行代码。

typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;

typedef struct Manager *ManagerP;

然后,任何包含 Manager.h 的源文件都将具有 Manager typedef 以及 ManagerP typedef 的定义。当 ManagerP 被取消引用时,编译器将知道如何访问 Manager 结构的各个部分。

编辑:其他注意事项

您提到这是某种练习,所以我想指出这样做的方式,文件中的结构,唯一暴露的是指向结构的指针,是一种经常用于隐藏结构细节的机制. 这种技术的目标是提供一个指向库中的对象的指针,在这种情况下是结构,但是使用库的人不能访问任何结构成员或做任何事情,除了将指针传递给其他函数在图书馆。

因此,本练习的重点可能是不访问任何结构成员。

于 2013-08-06T13:04:55.477 回答
1

创建指向类型的指针时,编译器不需要知道该类型是什么样的,因为所有指针的大小都相同(4 或 8 或许多字节)。但是,如果您尝试取消引用该指针,编译器必须知道该类型是什么样子才能计算内存偏移量并执行其他任务。由于在您的原始 cpp 文件中Manager未定义类型,仅声明了类型,因此编译器无法确定在到达该ID字段之前需要使用什么内存偏移量。(这样的类型通常称为opaque。)因此编译器会通知您该类型不完整。

如果您尝试直接创建类型变量,也会出现同样的问题Manager,因为编译器不知道需要为该变量留出多少内存。您可以malloc指向Manager,但如果您尝试这样做sizeof(Manager),它将失败。

为了使其工作,编译器需要知道在您尝试取消引用指针时该类型是什么样的。因此,结构定义必须放在主 cpp 文件中,或者放在该 cpp 文件包含的任何头文件中。

于 2013-08-07T00:26:18.900 回答