Warum kann ich ein Array nicht mit '=' kopieren?

7

Ich fange an, C zu lernen, indem ich K & amp; R lese und einige der Übungen durchführe. Nach einigen Schwierigkeiten konnte ich die Übung 1-19 mit dem folgenden Code abschließen:

%Vor%

Meine Frage bezieht sich auf das letzte Bit des Codes, in dem das Array tmp char in s kopiert wird. Warum funktioniert nicht einfach ein s = tmp; ? Warum muss man den Array-Index nach Index kopieren?

    
felideon 20.06.2009, 19:46
quelle

9 Antworten

20

Vielleicht bin ich nur alt und mürrisch, aber die anderen Antworten, die ich gesehen habe, scheinen den Punkt völlig zu verfehlen.

C führt keine Array-Zuweisungen durch, Punkt. Im Gegensatz zu einigen anderen Sprachen (zB PL / 1; Pascal und viele seiner Nachkommen - Ada, Modula, Oberon usw.) kann man kein Array einem anderen Array durch eine einfache Zuweisung zuweisen. Auch hat C keinen String-Typ. Es hat nur Arrays von Zeichen, und Sie können Arrays von Zeichen (so wenig wie Sie Arrays eines anderen Typs kopieren können) nicht kopieren, ohne eine Schleife oder einen Funktionsaufruf zu verwenden. [String-Literale zählen nicht wirklich als String-Typ.]

Das einzige Mal, wenn Arrays kopiert werden, ist es, wenn das Array in eine Struktur eingebettet ist und Sie eine Strukturzuweisung vornehmen.

In meiner Ausgabe von K & amp; R 2nd Edition fragt Übung 1-19 nach einer Funktion reverse(s) ; in meiner Kopie von K & amp; R 1. Ausgabe war es Übung 1-17 statt 1-19, aber die gleiche Frage wurde gestellt.

Da Zeiger in dieser Phase noch nicht behandelt wurden, sollte die Lösung Indizes anstelle von Zeigern verwenden. Ich glaube, das führt zu:

%Vor%

Kompilieren Sie dies mit -DTEST, um das Testprogramm einzuschließen und ohne nur die Funktion reverse() definiert zu haben.

Mit der in der Frage angegebenen Funktionssignatur vermeiden Sie, pro Zeile der Eingabe strlen() zweimal aufzurufen. Beachten Sie die Verwendung von fgets() - selbst in Testprogrammen ist es eine schlechte Idee, gets() zu verwenden. Der Nachteil von fgets() im Vergleich zu gets() besteht darin, dass fgets() die nachlaufende neue Zeile, in der gets() enthalten ist, nicht entfernt. Die Vorteile von fgets() sind, dass Sie keine Array-Überläufe erhalten und Sie erkennen können, ob das Programm eine neue Zeile gefunden hat oder ob der Speicherplatz (oder die Daten) erschöpft war, bevor eine neue Zeile gefunden wurde.

    
Jonathan Leffler 20.06.2009, 21:26
quelle
8

Ihr tmp -Array wurde auf stack deklariert, und wenn Ihre Methode fertig ist, wird der Speicher gehalten Die Werte werden aufgrund des Lösungsumfangs freigegeben.

s = tmp bedeutet, dass s auf den gleichen Speicherort wie tmp zeigen sollte. Das heißt, wenn tmp freigegeben ist, zeigt s immer noch auf einen jetzt möglichen ungültigen, freigegebenen Speicherplatz.

Dieser Fehlertyp wird als fliegender Zeiger bezeichnet.

Bearbeiten: Dies ist kein veränderlicher Modifikator, wie in den Kommentaren dieser Antwort angegeben. Das Problem ist, dass s = tmp nur ändert, worauf der Parameter verweist, nicht was das tatsächliche Array ist, das übergeben wurde.

Sie können auch mit einem einzigen Durchlauf rückwärts arbeiten, ohne ein ganzes Array im Speicher zu reservieren, indem Sie einfach die Werte nacheinander austauschen:

%Vor%     
Ben S 20.06.2009 19:55
quelle
4

Weil sowohl s als auch tmp Speicheradressen sind. Wenn Sie s = tmp, würden beide Zeiger auf das gleiche Array zeigen.

Angenommen, wir haben

%Vor%

nach s = tmp hättest du

%Vor%

Obwohl beide Arrays die gleichen Daten haben, wirkt sich eine Änderung von tmp auf beide aus, da beide Arrays tatsächlich gleich sind. Sie enthalten beide Daten, die sich in der gleichen Speicheradresse befinden. Wenn man also irgendeine Position des tmp-Arrays ändert oder das tmp-Array zerstört, wird s auf die gleiche Weise beeinflusst.

Indem Sie das Array durchlaufen, verschieben Sie einen Teil der Daten von einer Speicheradresse zu einer anderen.

In meiner Kopie von K & amp; R, Zeiger werden in Kapitel 4 erklärt. Ein kurzer Blick auf die ersten Seiten kann hilfreich sein.

    
Tom 20.06.2009 19:51
quelle
1

Um die Diskussion hier abzurunden, gibt es noch zwei andere Möglichkeiten, als String umzukehren:

%Vor%

Oder rekursiv:

%Vor%     
iwanttoprogram 20.06.2009 20:25
quelle
0

weil tmp ein Zeiger ist, und Sie brauchen eine Kopie, keine "Verbindung".

    
Macarse 20.06.2009 19:51
quelle
0

Im Falle von s = tmp würde der Wert von tmp, der auch die Anfangsadresse des Arrays ist, nach s kopiert werden.

Auf diese Weise zeigen sowohl s als auch tmp auf dieselbe Adresse im Speicher, was meiner Meinung nach nicht der Zweck ist.

Prost

    
Arnkrishn 20.06.2009 19:55
quelle
0

Versuchen Sie zu experimentieren und sehen Sie, was passiert, wenn Sie solche Dinge tun:

%Vor%

Was passiert, wenn Sie das Array direkt in attemptModifyArray ändern, überschreiben Sie gerade eine lokale Kopie der Adresse des Arrays x . Wenn Sie zurückkehren, ist die ursprüngliche Adresse immer noch in main 's Kopie von x.

Wenn Sie die Werte im Array in modifyArrayValues ändern, ändern Sie das eigentliche Array selbst, dessen Adresse in modifyArrayValues lokale Kopie von x gespeichert ist. Wenn Sie zurückkehren, behält x immer noch das gleiche Array bei, aber Sie haben die Werte in diesem Array geändert.

    
Eclipse 20.06.2009 20:16
quelle
0

In diesem Thread gibt es einen interessanten Unter-Thread über Arrays und Zeiger Ich fand diesen Link Wikipedia mit einer eigentümlichen Snippet-Code zeigt, wie ‚Plastilin‘ C sein kann!

%Vor%

Was in C noch verwirrender ist, ist natürlich, dass ich das tun kann:

%Vor%

Die Austauschbarkeit von Zeigern und Arrays scheint also in der C-Sprache so tief verankert zu sein, dass sie fast beabsichtigt ist Was denken alle anderen?

--- Original Beitrag ---
s und tmp sind beide Zeiger, also macht s = tmp einfach s auf die Adresse zeigen, wo tmp im Speicher lebt.
Ein weiteres Problem, mit dem, was skizzierte Sie ist, dass tmp eine lokale Variable ist, wird so ‚undefined‘ werden, wenn es den Bereich verlässt das heißt, wenn die Funktion zurückkehrt.

Stellen Sie sicher, dass Sie diese drei Konzepte gründlich verstehen, und Sie werden nicht sehr falsch gehen

  1. Geltungsbereich
  2. Der Unterschied zwischen dem Stapel und dem Heap
  3. Zeiger

Hoffe, das hilft und macht weiter!

    
zebrabox 20.06.2009 19:57
quelle
-2

Eine sehr direkte Antwort wäre - Sowohl s als auch tmp sind Zeiger auf einen Speicherort und nicht die Arrays selbst. Mit anderen Worten sind s und tmp Speicheradressen, in denen die Array-Werte gespeichert sind, aber nicht die Werte selbst. Eine der gebräuchlichsten Methoden, auf diese Array-Werte zuzugreifen, besteht in der Verwendung von Indizes wie s [0] oder tmp [0].

Wenn Sie jetzt versuchen, einfach zu kopieren, s = tmp, wird die Speicheradresse des tmp-Arrays in s kopiert. Das bedeutet, dass das ursprüngliche s-Array verloren geht und selbst der Speicherpointer auf das tmp-Array zeigt.

Sie werden diese Konzepte zu gegebener Zeit gut verstehen, also gehen Sie weiter durch das Buch. Ich hoffe, diese elementare Erklärung hilft.

    
Elitecoder 20.06.2009 19:52
quelle

Tags und Links