Warum kann ich nicht kopieren eines Arrays mittels `=`?
Ich bin angefangen C zu lernen durch Lesen K&R und gehen durch einige der übungen. Nach einigen kämpfen war ich endlich in der Lage, komplette übung 1-19 mit dem folgenden code:
/* reverse: reverse the character string s */
void reverse(char s[], int slen)
{
char tmp[slen];
int i, j;
i = 0;
j = slen - 2; /* skip '\0' and \n */
tmp[i] = s[j];
while (i <= slen) {
++i;
--j;
tmp[i] = s[j];
}
/* code from copy function p 29 */
i = 0;
while ((s[i] = tmp[i]) != '\0')
++i;
}
Meine Frage ist in Bezug auf das Letzte bit des Codes, wo die tmp
char-array kopiert s
. Warum nicht eine einfache s = tmp;
Arbeit statt? Warum muss man haben, um das array Durchlaufen kopieren von index zu index?
- K&R nicht benutzen ist die Lösung - Sie schrieb für C89, nicht in C99, aber in Ihrer Lösung verwendet ein VLA (variable length array), die wurde nur Hinzugefügt, in C99. Darüber hinaus gibt es keine Garantie, dass es einen Zeilenumbruch in den string - AFAIK. Und konventionell, die Länge eines Strings schon schließt das terminal null. Das bedeutet, dass Ihre '-2', ist wahrscheinlich falsch. Die Bedingung in der ersten while-Schleife verwenden soll, '<' anstelle von '<='; es ist keine Tugend der Austausch der Hauptfigur mit sich selbst. Die Schnellste Lösung vertauscht die array in situ mit keine temporären array.
- Vielen Dank für die Einsicht. Du hast Recht, ich dachte über die -2 diesem morgen, da war ein hack, ich habe Letzte Nacht um 3 Uhr, nur um es zu arbeiten. Ich wahrscheinlich sollte setzen Sie einfach ein if (s[i] != '\n' || s[i] != '\0') in die in der ersten while-Schleife.
- Alte Kommentar, aber (s[i] != '\n' || s[i] != '\0') ist immer true.
- Es gibt keine logische Antwort - es ist absolut möglich, eine solche Funktion in der Sprache - eigentlich bin ich derzeit ein modifizierter gcc-compiler akzeptiert arrays und Struktur Aufgaben auch mit inkompatiblen Typen (weil, die Zeit haben zu schreiben, dumm-casts).
- Sie können sogar so etwas wie
char arr[20] = *p;
seit*p
ist ein lvalue. Die änderung hat mich wie 5 Minuten zu machen - ich habe nur Hinzugefügt, ein einzelnesif
.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Vielleicht bin ich auch nur alt und mürrisch, aber die anderen Antworten, die ich gesehen habe scheinen verpassen den Punkt völlig.
C, bedeutet nicht, array assignments, Zeitraum. Sie können nicht zuweisen einer array in ein anderes array durch eine einfache Zuordnung im Gegensatz zu einigen anderen Sprachen (PL/1, zum Beispiel, Pascal und viele seiner Nachkommen zu Ada, Modula, Oberon, etc.). Noch hat C wirklich ein string-Typ. Es hat nur arrays von Zeichen, und Sie können nicht kopieren arrays von Zeichen (mehr, als Sie können kopieren arrays von einem anderen Typ) ohne Verwendung einer Schleife oder eine Funktion aufrufen. [String-Literale nicht wirklich count als string-Typ.]
Die einzige Zeit, die arrays kopiert wird, wenn das array eingebettet ist in eine Struktur und Sie brauchen eine Struktur, die Abtretung mitteilt.
In mein Exemplar von K&R 2nd Edition, übung 1-19 fordert für eine Funktion
reverse(s)
; in meinem Exemplar von K&R 1st Edition, es war übung 1-17 statt 1-19, aber die gleiche Frage gestellt wurde.Da Zeiger nicht erfasst wurde in dieser Phase sollte die Lösung Indizes verwenden, anstelle von Zeigern. Ich glaube, dass führt zu:
Kompilieren Sie diese mit der -DTEST gehören das Programmieren und testen ohne haben nur die Funktion
reverse()
definiert.Mit der Funktion Signatur gegeben, in der Frage, die Sie vermeiden, fordern
strlen()
zweimal pro Zeile. Beachten Sie die Verwendung vonfgets()
— auch in test-Programme, es ist eine schlechte Idee, verwenden Siegets()
. Der Nachteilfgets()
im Vergleich zugets()
ist, dassfgets()
nicht entfernen, die trailing newline wogets()
tut. Die Oberseiten derfgets()
sind, dass Sie nicht bekommen, array-überläufe und Sie kann sagen, ob das Programm fand ein newline oder ob es lief aus dem Raum (oder Daten), die vor der Begegnung einen Zeilenumbruch.Ihre
tmp
array deklariert wurde auf stack und so, wenn Ihr Verfahren abgeschlossen ist, wird der Arbeitsspeicher zu halten, werden die Werte freigegeben werden, da der scoping.s = tmp
bedeutet, dasss
sollten zeigen Sie auf die gleiche Speicherposition wietmp
. Dies bedeutet, dass, wenntmp
befreit,s
noch den Verweis auf eine nun möglich, ungültige, befreit Speicherplatz.Diese Art von Fehler wird bezeichnet als dangling pointer.
Edit: Dies ist nicht ein baumelnder Modifikator wie bereits in den Kommentaren zu dieser Antwort. Das Problem ist, dass zu sagen
s = tmp
nur änderungen der parameter zeigt, nicht das, was das eigentliche array, das übergeben wurde.Außerdem könnten Sie führen Sie Ihre Rückseite mit einem Durchgang und ohne Zuweisung eine ganze array im Speicher nur durch vertauschen der Werte an Stelle eins nach dem anderen:
Weil s-und tmp-Speicher Adressaten. Wenn Sie s = tmp, beide Zeiger zeigen auf dasselbe array.
Angenommen, wir haben
nach s= tmp hätten Sie
Obwohl beide arrays haben die gleichen Daten, die eine änderung in tmp, beeinflussen beide, weil beide arrays sind eigentlich die gleichen. Sie beide enthalten Daten, das ist in der gleichen Speicheradresse. Also durch ändern der position der tmp-array, oder die Zerstörung der tmp-array, s wäre in gleicher Weise betroffen.
Per Schleife über das array, was Sie tun, ist Bewegung ein Stück von Daten von einer Speicher-Adresse zu einer anderen.
In mein Exemplar von K & R, die Zeiger sind in Kapitel 4 dargelegt. Ein kurzer Blick durch die ersten Seiten, die weiterhelfen können.
Zur Abrundung der Diskussion sind hier zwei weitere Möglichkeiten, um reverse string:
Oder rekursiv:
weil tmp ist ein Zeiger, und Sie brauchen, um eine Kopie, nicht um einen "link".
Im Falle von s=tmp Wert von tmp, die ist die auch der Anfang der Adresse des Arrays bekommen würde, kopiert s.
Dass Weg von s-und tmp zeigen auf die gleiche Adresse im Speicher, die ich denke, ist nicht der Zweck.
cheers
Experimentieren und sehen, was passiert, wenn Sie tun Dinge wie diese:
Was passiert, wenn Sie ändern Sie das array direkt in
attemptModifyArray
sind Sie nur überschreiben einer lokalen Kopie der Adresse des Arraysx
. Wenn Sie wieder die original-Adresse ist noch inmain
's Kopie von x an.Beim ändern der Werte im array in
modifyArrayValues
Sie modifizieren die tatsächliche array selbst hat seine Adresse gespeichertmodifyArrayValues
lokale Kopiex
. Wenn Sie zurückkehren,x
ist immer noch das festhalten an der gleichen array ist, aber Sie haben sich geändert, die Werte im array.Es ist eine interessante sub-thread in diesem thread über arrays und Zeiger
Ich fand dieser link auf wikipedia mit einer eigenartigen code-snippet zeigt, wie 'Plastilin' C sein kann!
Natürlich, was noch mehr verwirrend in C ist, dass ich dies tun kann:
Also die interchangibility von Zeigern und arrays scheint so tief in der Sprache C fast absichtlich.
Was auch alle anderen denken?
---Original Post---
s und tmp sind die beiden Zeiger, die so tun, s = tmp einfach machen s Punkt, an die Adresse, wo tmp Leben in Erinnerung.
Ein weiteres problem mit dem, was Sie skizziert ist, die tmp ist eine lokale variable, so wird 'undefined', wenn es den Bereich verlässt ich.e wenn die Funktion zurückgibt.
Stellen Sie sicher, dass Sie gründlich das Verständnis dieser drei Begriffe und du wirst nicht viel falsch machen
Hoffe, das hilft und keep going!
Sehr straight-forward beantworten wäre -
s-und tmp-Zeiger auf einen Speicherbereich und nicht die arrays selbst.
In anderen Worten, s und tmp sind die Speicheradressen, wo die array-Werte werden gespeichert, aber nicht die Werte selbst.
Und einer der häufigsten Wege, um den Zugriff auf diese array-Werte sind durch die Verwendung von Indizes wie s[0] oder tmp[0].
Nun, wenn Sie versuchen, kopieren Sie einfach s = tmp, die Speicher-Adresse von tmp-array kopiert zu en. Dies bedeutet, dass, die original s-array verloren, und sogar s-Speicher-Zeiger wird nun auf tmp-array.
Werden Sie diese Konzepte verstehen sich gut mit, zu gegebener Zeit, also halten Sie gehen durch das Buch.
Ich hoffe, dass diese Elementare Erklärung hilft.
tmp
ist ein array, und nicht einen Zeiger. Arrays sind keine Zeiger, obwohl Sie nahe verwandt sind. Leider nur 10k kann der Benutzer sehen, die Informationen, hinwies.