2017-11-16 6 views
1

Ich verstehe, dass C ist (meist) aufrufen und zuweisen "nach Wert", und dass struct Zuweisung a = b erstellt eine Kopie von b.Idiom für Aliasing-Strukturen

Dies führt zu etwas Ausführlichkeit beim Iterieren durch ein Array, dessen Mitglieder struct sind, und den Zugriff auf Mitgliedsfelder (Beispiel unten). Gibt es ein Idiom für Aliasing-Strukturen in einer Schleife?

#include <stdio.h> 
#define N_FOOS 2 

struct Foo { 
    char *bar; 
    char *baz; 
}; 

int main() { 
    struct Foo foos[N_FOOS] = { 
    {"foo", "bar"}, 
    {"baz", "qux"}, 
    }; 

    for (int i = 0; i < N_FOOS; ++i) { 
    printf("foos[%d].bar = %s\n", i, foos[i].bar); 
    printf("foos[%d].baz = %s\n", i, foos[i].baz); 
    } 
} 

In einer höheren Programmiersprache würde ich einen Alias ​​innerhalb for erstellt haben foos[i] und vermeiden wiederholte Indizierung zu zeigen.

Wäre die idiomatische Methode, einen Zeiger zu erstellen, der auf foos[i] verweist?

int main() { 
    struct Foo *foo; 
    struct Foo foos[N_FOOS] = { 
    {"foo", "bar"}, 
    {"baz", "qux"}, 
    }; 

    for (int i = 0; i < N_FOOS; ++i) { 
    foo = &foos[i]; 
    printf("foos[%d].bar = %s\n", i, foos[i].bar); 
    printf("foos[%d].baz = %s\n", i, foos[i].baz); 
    printf("foo->bar = %s\n", foo->bar); 
    printf("foo->baz = %s\n", foo->baz); 
    } 
} 

Der Nachteil manuelle Aufhebung der Zuordnung zu tun hat, aber ich denke, dass nur ein unausweichlicher Teil der Sprache ist.

EDIT: fixed-Code aufgrund @ dbush Feedback

+2

Wenn Sie nicht fast alle Optimierungen ausschalten, würde jeder vernünftige Compiler den gemeinsamen Teilausdruck optimieren und würde nicht zweimal indexieren, so dass Sie in den meisten Fällen nicht so viel darüber nachdenken müssen. Der malloc ist überflüssig und das free ist eigentlich ein Fehler. – pvg

+0

Es könnte vom Compiler weg optimiert werden, aber es sind noch mehr Zeichen zu tippen (mein Ausgangspunkt). Dieser Kommentar wäre auch besser, wenn er erklärt, warum "malloc" überflüssig und "frei" ein Fehler ist. – yangmillstheory

+0

Ich bin nicht sicher, wie ich es erklären soll, weil ich nicht verstehe, warum Sie malloc benutzt haben und dann etwas anderes freigegeben haben, als das, was Sie mallociert haben. Wenn Sie Ihr Denken erklären, wäre es vielleicht einfacher, darüber zu sprechen, wo es schief gelaufen ist. – pvg

Antwort

2

Was haben Sie wird gut funktionieren. Es kann besonders nützlich sein, wenn Sie eine Struktur mehrere Schichten tief haben, um zu verkürzen, was Sie beziehen und Ihren Code klarer machen.

Das einzige Problem, das Sie haben, ist ein Speicherleck. Sie Speicher dynamisch zu foo, weisen aber dann überschreiben Sie die Adresse des zugewiesenen Speicher mit der Adresse einer anderen Variablen:

foo = &foos[i]; 

Nun ist die zugewiesenen Speicher verloren.

Da Sie den Zeiger verwenden, um auf eine vorhandene Variable zu verweisen, benötigen Sie keine dynamische Zuordnung. Befreien Sie sich von malloc und free.

+0

Ist was idiomatisch und gibt es eine bessere Möglichkeit, den Alias ​​zu erstellen? Auch in Bezug auf "frei" vermute ich, dass sein Verhalten nicht definiert gewesen wäre, wenn ich es verlassen hätte, da ich einen Zeiger übergeben habe, der nicht von "malloc" und Freunden erstellt wurde. – yangmillstheory

+1

Ich akzeptiere dies als die Antwort, obwohl @Jesin einen guten Punkt darüber macht, den Zeiger explizit auf 'NULL' zu initialisieren. – yangmillstheory

+1

@ yangmillstheorie es ist kein guter Punkt, um den Zeiger auf NULL zu initialisieren - in der Tat wäre das redundant und könnte sogar eine Compiler-Warnung für nicht verwendeten Code auslösen. Die beste Option ist, den Zeiger nicht zu deklarieren, bis Sie bereit sind, ihm den ersten Wert zu geben (innerhalb der Schleife) –

2

Ihr Programm ist nicht korrekt. Hier ist, wie es zu beheben: Entfernen Sie die malloc auf der RHS, ersetzen Sie sie durch NULL, und entfernen Sie die free Linie.

Sie ziehen nur den Zeiger, so gibt es keine Notwendigkeit, manuelle Zuordnung zu tun, und wenn Sie free der letzte Wert, das ist ein Fehler, weil Sie free ing etwas sind, die nicht malloc ed war.

+0

Die 'NULL'-Zuweisung ist technisch nicht notwendig, oder? – yangmillstheory

+1

Es ist technisch unnötig, aber es ist eine gute Praxis, Zeiger niemals uninitialisiert zu lassen. Wenn Sie versehentlich einen Null-Zeiger dereferenzieren, erhalten Sie einen sofort diagnostizierbaren Absturz, aber wenn Sie einen nicht initialisierten Zeiger dereferenzieren, können Sie einen beliebigen Teil des Speichers stummschalten und je nach Programm für Minuten oder Wochen nichts herausfinden. – Jesin

+0

Danke. [Der Grund, warum ich "malloc" an erster Stelle genannt habe, ist eine Nullzeiger-Dereferenzierung zu verhindern.] (Https://stackoverflow.com/questions/47320398/idiom-for-aliasing-structs#comment81592277_47320398) – yangmillstheory