2017-03-24 9 views
0

Ich arbeite an einer Datenbank, die mehrere Strukturen hat. Ich habe eine Funktion definiert, die Daten aus einer CSV-Datei lädt und jede Zeile als Struktur speichert. Ich speichere sie mit einem Doppelzeiger, so dass ein Zeiger auf mehrere Zeiger für jede Strukturvariable zeigt. Die Funktion gibt den doppelten Zeiger korrekt zurück, jedoch erhalte ich eine Warnung: Rückgabe vom inkompatiblen Zeigertyp.Zeiger auf Zeiger von Strukturen zurückgeben

Mein Code ist wie folgt:

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

Weiß jemand, warum diese Warnung auftritt? Vielen Dank im Voraus!

+0

können Sie sagen, auf welche Anweisung in Ihrem Code Sie die Warnung erhalten? – SMFSW

+0

Danke, ich habe beim Kopieren des Codes einen Fehler gemacht! :) – Drent

+3

Sind Sie sicher, dass der 'struct part' in Ihrer Funktion der gleiche ist wie' Part'? Wenn ich Sie wäre, hätte ich eine globale Definition dieses Typs und würde diese zweite Definition innerhalb der Funktion loswerden. – ForceBru

Antwort

0

Sie haben in groben Zügen:

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

Es gibt keine Möglichkeit, dass dies ohne Warnungen kompilieren. Die in der Funktionssignatur verwendete struct part ist per Definition völlig unabhängig von der in der Funktion definierten struct part. Sie geben daher einen Zeiger auf einen Typ in einer Funktion zurück, die erwartet, einen Zeiger auf einen anderen Typ zurückzugeben, obwohl beide Typen struct part geschrieben werden können. Es gibt nicht einmal eine Möglichkeit, Ihren Code in Schwierigkeiten zu bringen.

Wie in den Kommentaren angegeben, muss die Strukturdefinition außerhalb der Funktion vor der Funktionsdefinition (und wahrscheinlich vor jeder Deklaration - und normalerweise in einer Headerdatei, die überall dort verwendet wird, wo die Struktur verwendet wird) kommen.

Eine Möglichkeit, den Code zu beheben, daher ist:

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

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

Sie die Funktion zurückgeben Part ** in diesem Szenario haben könnten.

Die Funktion sollte jetzt jedoch als static definiert werden, es sei denn, Sie haben eine Kopfzeile, die die Strukturdefinition enthält. Wenn Sie keine Kopfzeile haben, können Sie in anderen Quelldateien nicht (zuverlässig) auf den Strukturtyp zugreifen. (Es kann getan werden, indem Sie den Code zweimal schreiben, aber zweimal Code schreiben sollte ein Gräuel sein - es wird eine Wartung Haftung, bevor Sie mit der Eingabe fertig sind, oder Copy'n'pasting, die zweite Kopie.)

Es ist möglich, dass es sich um einen undurchsichtigen Typ handelt; Der Code außerhalb dieser Datei muss nicht über die Strukturdetails wissen. Das ist legitim; es kann sogar (sehr) vorteilhaft sein. Sie brauchen nur eine andere Art und Weise des Schreibens Dinge, aber:

Rubrik:

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

Wenn Sie nicht die Part Namen entscheiden zu belichten, könnten Sie verwenden diesen Header statt:

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

Die erste Zeile sagt "es gibt eine Art struct part, aber die Details werden später geliefert, wenn Sie sie brauchen". Der zweite deklariert die Funktion, die einen Zeiger auf den Zeiger auf struct part Wert zurückgibt. Die extern ist optional; Ich benutze es - viele Leute nicht. In diesem Code ist die erste Zeile optional. Wenn Sie jedoch extern int num_parts(struct part **list); als Funktion hätten, müssten Sie dies nach der loadParts() Deklaration anzeigen, oder Sie würden die struct part; Zeile benötigen, um sicherzustellen, dass der Typ im Prototyp nicht neu ist.

Quelle:

struct part 
{ 
    int id; 
    int cost; 
}; 

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

Sie müssen sich über Kopfschutz im Header sorgen Idempotenz zu gewährleisten. (In diesem Beispiel gibt es kein Problem der Selbstständigkeit, aber Sie sollten auch sicherstellen, dass Ihre Header eigenständig sind - es gibt mehrere Fragen zu SO, die diese Begriffe bei der Suche erläutern).

+0

Vielen Dank für diese ausführliche Erklärung! Ich habe Ihren vorgeschlagenen Weg zur Korrektur meines Codes bereits implementiert und es hat tatsächlich funktioniert. Ich habe tatsächlich einen Header, also muss ich die Funktion nicht statisch machen. Ich werde in den Idempotenz-Teil Ihrer Antwort schauen, da ich (noch) nicht damit vertraut bin. Ein schönes Wochenende wünsche ich ihnen! – Drent