9 Stimmen

Warum gibt es keine Array-Zuweisungsoperation, aber eine Strukturzuweisung in der C-Sprache?

int a[10];
int b[10];

a = b; // illegal

typedef struct {
    int real;
    int imag;
    } complex;

complex c,d;
c = d; //legal

[Ich erkenne, dass a und b im ersten Fall Adressen sind, aber Symbole im zweiten Fall.]

11voto

Steve Jessop Punkte 264569

Für historische Informationen könnte dies interessant sein: http://cm.bell-labs.com/who/dmr/chist.html

In B würde durch die Deklaration eines Arrays Speicher für das Array reserviert, genauso wie es C tut, aber der bereitgestellte Name für die Variable wurde verwendet, um einen Zeiger auf das Array zu definieren. Ritchie änderte dies in C, so dass der Name das Array "ist", aber zu einem Zeiger verfallen kann, wenn er verwendet wird:

Die Regel, die im heutigen C fortbesteht, besagt, dass Werte mit Arraytyp, wenn sie in Ausdrücken erscheinen, in Zeiger auf das erste der Objekte im Array umgewandelt werden.

Diese Erfindung ermöglichte den meisten vorhandenen B-Code weiterhin zu funktionieren, trotz des zugrunde liegenden Wechsels in der Semantik der Sprache. Die wenigen Programme, die neuen Werten einen Arraynamen zuwiesen, um seinen Ursprung anzupassen – möglich in B und BCPL, bedeutungslos in C – konnten leicht repariert werden.

Wenn Ritchie bereits in diesem sehr frühen Stadium a = b definiert hätte, um das Array zu kopieren, wären die von B nach C portierten Codes nicht so leicht repariert worden. Wie er es definierte, würde dieser Code einen Fehler erzeugen, den er beheben konnte. Hätte er C das Array kopieren lassen, hätte er stillschweigend die Bedeutung des Codes geändert, um das Array zu kopieren, anstatt den Namen umzusetzen, der verwendet wurde, um auf ein Array zuzugreifen.

Es bleibt die Frage, "warum wurde dieses Feature in den letzten 40 Jahren nicht hinzugefügt", aber ich denke, deshalb war es von Anfang an nicht vorhanden. Es wäre mühsam gewesen, es zu implementieren, und dieser Aufwand hätte diese frühe Version von C tatsächlich "schlechter" gemacht, im Sinne von etwas schwieriger, B- und BCPL-Code nach C zu portieren. Also hat Ritchie es natürlich nicht gemacht.

5voto

nos Punkte 214143

Weil C sagt, dass man nicht kann, sagt es: "Ein modifizierbares lvalue ist ein lvalue, das keinen Array-Typ hat, keinen unvollständigen Typ hat", daher kann einem Array nicht zugewiesen werden.

Darüber hinaus wird, wenn Sie den Namen eines Arrays in einem Wertkontext verwenden wie a = b;, sowohl die Namen a und b &a[0] und &b[0] bedeuten. Oft bezeichnet als ein Array, das zu einem Zeiger "zerfällt".

Allerdings sind Arrays keine Zeiger, daher würde es keinen Sinn machen, ein Array durch Verwendung von Zeigern zuzuweisen.

3voto

ouah Punkte 138337

Der Hauptgrund ist natürlich der Standard. In der Zuweisungsoperator-Einschränkung heißt es:

(C99, 6.5.16p2) "Ein Zuweisungsoperator muss einen modifizierbaren lvalue als linken Operanden haben"

wo ein modifizierbarer lvalue definiert ist als

(C99, 6.3.2.1p1) "Ein modifizierbarer lvalue ist ein lvalue, der keinen Array-Typ hat, [...]".

Das Zuweisen zu Arrays ist also nicht erlaubt.

Aber die Hauptgründe sind historische Gründe aus der Zeit, als das Kopieren von Arrays für die Hardware nicht angemessen war (die alten PDP-Systeme). Beachten Sie, dass auch in den ersten Versionen von C die Zuweisung von Strukturtypenobjekten nicht erlaubt war. Es wurde später zur Sprache hinzugefügt, aber für das Array wären viele Teile der Sprache geändert worden, um das Zuweisen von Arrays zu ermöglichen.

3voto

Keith Thompson Punkte 240701

Das Erste, was zu verstehen ist, ist, dass Arrays keine Zeiger sind. Lesen Sie Abschnitt 6 des comp.lang.c FAQ. Ich warte.

...

Ok, fertig? Nein, gehen Sie zurück und lesen Sie das Ganze.

...

Super, danke.

Im Allgemeinen sind Arrays in C Bürger zweiter Klasse. Es gibt Array-Typen, Array-Objekte und sogar Array-Werte, aber Arrays werden fast immer über Zeiger auf ihre Elemente manipuliert.

Dies erfordert etwas mehr Arbeit für den Programmierer (wie Sie gesehen haben, können Sie Arrays nicht einfach zuweisen), aber es gibt Ihnen auch mehr Flexibilität. Programme, die mit Arrays umgehen, müssen in der Regel mit Arrays unterschiedlicher Größen umgehen, sogar mit Größen, die erst zur Ausführungszeit bestimmt werden können. Selbst wenn die Array-Zuweisung zulässig wäre, sind ein Array von 10 ints und ein Array von 20 ints unterschiedliche und inkompatible Typen. Wenn Sie ein Array mit fester Größe haben, wie in Ihrem Code, ist es üblich, dass nur einige der Elemente derzeit relevant sind; Sie könnten ein 10-Element-Array haben, aber derzeit nur die ersten 5 Elemente verwenden. Die Verarbeitung eines solchen Arrays elementweise erleichtert die Verarbeitung nur der Elemente, die derzeit aktiv sind (etwas, das Sie selbst im Auge behalten müssen).

Für eine Struktur hingegen werden Anzahl und Typen der Member beim Definieren des Typs bestimmt. Sie können die Member einer Struktur nicht durch Bewegen eines Zeigers durchlaufen, wie Sie es bei einem Array tun würden, da die Member typischerweise unterschiedliche Typen haben. Arrays und Strukturen sind unterschiedliche Dinge und haben unterschiedliche Sätze von Operationen, die für sie Sinn ergeben.

Es gibt ein paar Regeln in der Sprache, die versuchen, dies zu erleichtern, nämlich:

  • Ein Array-Ausdruck wird in den meisten, aber nicht allen Kontexten implizit in einen Zeiger auf das erste Element des Arrays umgewandelt. Die Ausnahmen sind:
    • Wenn der Array-Ausdruck das Operand des & (Adress-)Operators ist;
    • Wenn er der Operand von sizeof ist; und
    • Wenn es ein Zeichenkettenliteral in einem Initialisierer ist, das verwendet wird, um ein Array-Objekt zu initialisieren.
  • Ein deklarierter Array-Parameter, wie in int func(char s[]); wird zu einem Zeigerparameter geändert: int func(char *s);.

(Man könnte argumentieren, dass diese Regeln mehr Verwirrung stiften als verhindern, aber so ist die Sprache definiert.)

Jetzt nehme ich an, dass die Sprache definiert worden sein könnte oder neu definiert werden könnte, dass Array-Zuweisungen in Fällen erlaubt sind, in denen dies sinnvoll ist:

int a[10];
int b[10];
/* ... */
a = b; /* Warum nicht? */.

Möglicherweise könnte eine solche Änderung sogar ohne Zerstören vorhandenen Codes vorgenommen werden. Aber das würde ein weiteres Spezialfall für die Array-zu-Zeiger-Konvertierungsregel erfordern. Und es wäre nur in dem Fall von Arrays mit fester Größe wie a und b nützlich, die, obwohl sie in Einführungsprogrammieraufgaben recht häufig sind, in der Produktionscodierung nicht so häufig vorkommen.

-1voto

tomcheney Punkte 1620

Ein Array-Name ist ein konstanter Zeiger, sodass Sie nicht ändern können, auf was er zeigt.

Angenommen, dass Sie mit "c = d" in der letzten Zeile gemeint haben, ist dies legal, da es einfach eine nicht-konstante Variable in eine andere nicht-konstante Variable kopiert, was völlig legal ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X