2014-01-14 14 views
5

Ich habe einige konzeptionelle Fragen über die Umkehrung einer nullterminierten C-Zeichenfolge und Klärungsfragen über die Art von Zeigern.Umkehren einer ' 0' terminierten C-Zeichenfolge an Ort und Stelle?

könnten Der Eingang

sein
char arr[] = "opal"; 

und der Code:

void reverse(char *str) { /* does *str = opal or does *str = o since the pointer str is type char? */ 

    char* end = str; /* what is the difference between char* end and char *end? and is *end pointing to opal now? */ 

    char tmp; 

    if (str) { /* if str isn't null? */ 
     while (*end) 
      ++end; 
    } 
    --end; /* end pointer points to l now */ 

    while (str < end) {  /* why not *str < *end? is this asking while o < l? */ 
     tmp = *str; /* tmp = o */ 

     *str++ = *end; /* what is the difference between *str++ and ++str? does *str++ = l? */ 
     *end-- = tmp; /* *end points to o */ 
     } 
    } 
} 
+2

Wenn Sie "opal" 'wortwörtlich weitergeben, wäre dies ein undefiniertes Verhalten, da Sie kein Zeichenfolgenliteral ändern dürfen. –

+0

@ShafikYaghmour was würdest du dann passieren? – Opal

+0

Ein char-Array, 'char arr [] =" opal ";'. –

Antwort

8

Viele Fragen ... versuchen, Antworten auf jede zu erfassen:

/* macht * str = opal oder tut * str = o, da der Zeiger str char ist? */

*str ist 'o', da es beim ersten Zeichen weist

/* Was ist der Unterschied zwischen char * Ende und char * Ende? und * zeigt jetzt auf Opal?*/

Es gibt keinen Unterschied zwischen char *end und char* end. Es wird schwieriger, wenn Sie

char* a, b; 

schreiben, da dies zu

entspricht
char *a, b; 

und nicht, wie Sie

char *a, *b; 

vielleicht denken Aus diesem Grund ist es sauberer char *end; zu schreiben.

Und end zeigt auf opal jetzt - *end ist 'o'.

if (str) {/ * wenn str nicht null ist? */

Ja - Tests, die Sie nicht einen NULL-Zeiger

Um zu testen, dass Sie nicht eine Zeichenfolge der Länge 0, übergeben bekommen haben würden Sie *str testen (nach der Prüfung übergeben bekommen haben, dass str nicht NULL ist, sonst hat man einen Segmentation Fehler erhalten für "gewagt an * NULL suchen")

während (str < Ende) {/ * warum nicht * str < * end? fragt das, während o < l? */

Testen der Zeiger - man gegen Ende bewegt, der andere zurück bewegt. Wenn du dich in der Mitte triffst, hörst du auf; sonst haben Sie die Swap zweimal, und es wird kein Nettoeffekt sein ...

*str++ = *end; /* what is the difference between *str++ and ++str? does *str++ = l? */ 

Sie zuerst den Wert von *end-*str kopieren, dann erhöhen Sie die str Zeiger. Wenn Sie ++str eingeben, inkrementieren Sie zuerst, dann verwenden Sie es. Und das würde bedeuten, dass Sie die l an Stelle der anstelle der o setzen.

bearbeiten eine Kritik an Ihrem Code (geht über die gestellten Fragen Sie, und auf einen Kommentar von @chux reagiert): Wenn Sie für if(str){} testen Sie wirklich brauchen eine else return; Aussage, da Sie tatsächlich end--; tun und dann verwenden *end. Ziemlich sicher, dass 0xFFFFFFFFFFFFFFFF ist fast immer eine ungültige Adresse ...

Wenn Sie in der Tat für if(*str!='\0') testen, dann sollten Sie immer noch nur zurückgeben (eine leere Zeichenfolge ist "irreversible" - oder vielmehr, es braucht nichts zu gilt als umgekehrt).

Übrigens ziehe ich es vor, die Bedingung explizit zu machen (wie damals); es zeigt nicht nur Ihre Absicht deutlicher, aber der Compiler könnte tatsächlich beschweren, wenn Sie if(str!='\0') oder if(*str != NULL) getan haben, da die Typen, die Sie vergleichen, inkompatibel sind. Dies bedeutet, dass Sie einen Code haben, der robuster, lesbarer und mit größerer Wahrscheinlichkeit für das geeignet ist, was Sie vorhaben.

+1

Wenn ich könnte, würde ich Sie noch einmal für die Kommentare zum expliziten Testen im letzten Absatz +1 geben. –

+0

@ JonathanLeffler - sehr wahrscheinlich habe ich die Bedeutung dieses Ansatzes irgendwann im letzten Jahr durch das Lesen einer Ihrer Antworten/Kommentare gelernt. Ja, ich bin hauptsächlich hier, um zu lernen, obwohl ich es versuche, indem ich versuche, Fragen zu beantworten. Danke für das Kompliment! – Floris

2

tut * str = opal oder tut * str = o, da der Zeiger str char ist?

str Zeiger auf das erste Element der opal ist, das heißt, ist es Zeiger auf ersten Buchstaben o. Also, *s bedeutet, dass Sie den s (die erste Adresse) dereferenzieren, daher ist es 'o'.

Was ist der Unterschied zwischen char * end und char * end? und * zeigt jetzt auf Opal?

Es gibt keinen Unterschied. Nein. Es ist end, das auf opal zeigt, d. H. Sein erstes Element jetzt.

wenn str nicht null ist?

Ja.

Ende Zeiger zeigt auf l jetzt

Ja. Es zeigt jetzt auf den letzten Buchstaben des Wortes.

Was ist der Unterschied zwischen * str ++ und ++ str? Ist * str ++ = l?

*str++ bedeutet str erhöht wird, nachdem der Wert str zeigt auf dereferenziert. ++str einfach die Vorinkrementierung von str.
*str++ = Weisen Sie der dereferenzierten Variablen den Wert zu, bevor Sie str inkrementieren.

+0

Woooooo! Warum die down vote? – haccks

+0

Ich habe nicht abgestimmt, jemand anderes muss haben. Ich habe gerade die Frage editiert, um 'char arr [] =" opal "zu übergeben;' – Opal

+0

@Opal; Jetzt bearbeitet. – haccks

2

tut * str = opal oder macht * str = o, da der Zeiger str Typ char ist?

*str dereferenzieren den Zeiger, die vom Typ ist char*, so der Typ Sie ist char bekommen. Dieser char wird der Wert sein, auf den str zeigt, der 'o' sein wird.

Was ist der Unterschied zwischen char * end und char * end?

Nichts.

und ist * Ende auf Opal jetzt zeigen?

Ja, naja, nah. end zeigt auf genau die gleiche Adresse wie str, die der Anfang Ihrer Zeichenkette ist. *end ist ein Zeichentyp, kein Zeiger. Sein Wert wird 'o' sein.

wenn str nicht null ist?

Korrekt, ein boolescher Test an einem Zeiger ist ein Standardtest. Es wird zu einem 'wahren' Wert ausgewertet, wenn der Zeiger nicht Null ist und andernfalls 'falsch'. Beachten Sie, dass dies nicht mit einem Nullwert identisch ist. Der C-Standard ermöglicht, dass jeder Wert eine Nulladresse darstellt.

warum nicht * str < * ende? fragt das, während o < l?

Nein, es wird die tatsächliche Speicheradresse verglichen. Es heißt, Schleife, während str zeigt auf einen früheren Teil der Zeichenfolge als end. Sie werden feststellen, dass während der Schleife str zunimmt und end abnimmt. Sie werden sich also am gleichen Zeichen (dh die Mitte der Zeichenfolge) übergeben.

Was ist der Unterschied zwischen * str ++ und ++ str? Ist * str ++ = l?

str++ zuerst angewendet wird, was str inkrementiert und gibt den vorherigen Wert, dann sind die * unärer Operator derferences das Zeichen an dieser alten Position zu geben. Ja, beim ersten Mal wird die 'l' von end dem Anfang der Zeichenfolge zugewiesen (wobei str verwendet wurde, um vor dem Inkrementieren zu zeigen). Die tmp wird verwendet, um das alte Zeichen zu tragen und es end zuzuweisen. Dies ist eine Standard-Swap-Operation.

1

tut *str = opal oder tut *str = 'o' da der Zeiger str ist char geben?

Es ist beides. Ich weiß, dass es verwirrend ist, aber hier ist was passiert: In C kann ein Zeiger auf zwei Arten interpretiert werden - entweder wörtlich, dh als Zeiger auf ein einzelnes Element (char in diesem Fall) oder als Zeiger auf den Anfang von a Sequenz von Elementen des gleichen Typs. Im letzteren Fall ist das Ende der Sequenz zu definieren. Es gibt drei Wege zu wissen, wo die Sequenz endet - durch explizite Kenntnis der Länge, durch Kenntnis des Endzeigers oder durch Platzierung eines "Terminator" -Elements am Ende der Sequenz. Bei C-Strings wird ein Sonderzeichen '\0' namens "null terminator" verwendet, um die Sequenz zu beenden.

Was ist der Unterschied zwischen char* end und char *end? und ist *end auf Opal jetzt zeigen?

Es gibt absolut keinen Unterschied - beide zeigen auf den gleichen Ort. Die Platzierung von Sternchen spielt keine Rolle.

wenn str nicht null ist?

Correct

end Zeiger zeigt auf 'l' jetzt

Absolut!

warum nicht *str < *end? fragt das while o < l?

Sie vergleichen Orte im Speicher, nicht die Zeichen, auf die sie zeigen. Dies verlangt, dass sich die Zeiger nicht "kreuzen", weil die beiden von beiden Enden der Saite zur Mitte gehen.

tmp = o

Auf der ersten Iteration ist es. Auf der zweiten Iteration, verweist er auf 'p'

was ist der Unterschied zwischen *str++ und ++str? tut *str++ = 'l'?

++str Der Ausdruck erhöht den Wert des Zeigers, und wertet auf den Wert des Zeigers nach dem Inkrement; Der Ausdruck *str++ erhöht den Wert des Zeigers und berechnet den Wert Zeichen, auf den der Zeiger vor das Inkrement zeigte.

2

reverse Angenommen wird wie folgt aufgerufen:

char str[] = "opal"; 
reverse(str); 

und an Speicher zugewiesen, als Beispiel wie folgt aus:

 
Memory Address: 100 101 102 103 104 
Memory Value: ['o'] ['p'] ['a'] ['l'] ['\0'] 

Die folgenden, in Bezug auf Adressen erfüllt sind:

  1. str + 0 == &str[0] == 100
  2. str + 1 == &str[1] == 101
  3. str + 2 == &str[2] == 102
  4. str + 3 == &str[3] == 103
  5. str + 4 == &str[4] == 104

und die folgenden, in Bezug auf Werte, erfüllt sind:

  1. *(str + 0) == str[0] == 'o'
  2. *(str + 1) == str[1] == 'p'
  3. *(str + 2) == str[2] == 'a'
  4. *(str + 3) == str[3] == 'l'
  5. *(str + 4) == str[4] == '\0'

Bezüglich NULL, wenn ein Zeiger nicht initialisiert ist, das heißt, nicht in gültige Speicher zeigt, sollte es den Wert von NULL, die die Adresse in den meisten Fällen werden zugewiesen ist 0. Betrachten Sie das folgende:

char *str = NULL; 
reverse(str); 

Wenn der folgende Ausdruck ausgewertet wird:

if(str) 

Es wird FALSE ausgewertet. Inside reverse, sollte es (Sie sollten es beheben) sofort return, da die Verwendung eines Zeigers mit einer Adresse NULL zu unbestimmtem Verhalten wie einem Segmentierungsfehler führt.

die Zuweisung der Adresse str zu end, wenn seine Adresse NULL ist und dann Vermindern es:

--end; 

in unbestimmten Verhalten führen.

+1

Dies deckt nicht alle Fragen in der Frage ab. –

+0

@ JonathanLeffler Du hast Recht, aber wenn du das verstehst, werden die Antworten auf die anderen Fragen offensichtlich. –

+0

@Awwww. Nein. Aber einverstanden mit Jonathan Leffler: D – haccks

Verwandte Themen