C: Unterschiede zwischen Char-Zeiger und Array [duplicate]

Lesezeit: 9 Minuten

Benutzeravatar von Midnight Blue
Mitternachtsblau

In Betracht ziehen:

char amessage[] = "now is the time";
char *pmessage = "now is the time";

Ich lese ab Die Programmiersprache C2. Auflage, dass die beiden obigen Aussagen nicht dasselbe tun.

Ich dachte immer, dass ein Array eine bequeme Möglichkeit ist, Zeiger zu manipulieren, um einige Daten zu speichern, aber das ist eindeutig nicht der Fall … Was sind die “nicht trivialen” Unterschiede zwischen Arrays und Zeigern in C?

  • Ich erinnere mich vielleicht falsch, aber ich möchte darauf hinweisen, dass Sie die verwenden können [] Notation für Zeiger und die Notation * für Arrays. Der einzige große Unterschied aus der Sicht des Codes besteht darin, dass sich der Wert von amessage nicht ändern kann, also sollte amessage++ fehlschlagen (aber ich glaube, *(amessage+1) wird erfolgreich sein. Es gibt andere interne Unterschiede, glaube ich, aber sie spielen fast nie eine Rolle.

    – Bill K

    26. August 2009 um 17:25 Uhr

  • Oh, und im Allgemeinen (nicht in den von Ihnen erwähnten Fällen) weisen Arrays automatisch Speicher zu, Zeiger müssen Sie Ihren eigenen Speicher zuweisen. Ihre beiden sollten nur auf Speicherblöcke verweisen, die als Teil des Programmladens zugewiesen wurden.

    – Bill K

    26. August 2009 um 17:26 Uhr

  • Zusammen mit dem K&R (das übrigens ein großartiges Buch ist) würde ich vorschlagen, dass Sie es lesen pw2.netcom.com/~tjensen/ptr/cpoint.htm – Zwischendurch.

    – amaterasu

    26. August 2009 um 17:45 Uhr

  • Siehe stackoverflow.com/a/10186799/632951

    – Schrittmacher

    14. Mai 2015 um 13:12 Uhr

  • Schließen Sie dies als Duplikat, da wir zwei “kanonische” FAQ-Threads zu genau derselben Frage hatten.

    – Ludin

    10. September 2015 um 11:52 Uhr

Benutzeravatar von John Bode
Johannes Bode

Hier ist eine hypothetische Speicherkarte, die die Ergebnisse der beiden Deklarationen zeigt:

                0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07
    0x00008000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00008008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
        ...
amessage:
    0x00500000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00500008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
pmessage:
    0x00500010:  0x00  0x00  0x80  0x00

Das Zeichenfolgenliteral “jetzt ist die Zeit” wird als ein 16-Element-Array von Zeichen an der Speicheradresse 0x00008000 gespeichert. Dieser Speicher darf nicht beschreibbar sein; Es ist am besten anzunehmen, dass dies nicht der Fall ist. Sie sollten niemals versuchen, den Inhalt eines Zeichenfolgenliterals zu ändern.

Die Erklärung

char amessage[] = "now is the time";

weist ein 16-Element-Array von char an der Speicheradresse 0x00500000 zu und kopiert die Inhalt des String-Literals dazu. Dieser Speicher ist beschreibbar; Sie können den Inhalt von amessage nach Herzenslust ändern:

strcpy(amessage, "the time is now");

Die Erklärung

char *pmessage = "now is the time";

weist char an der Speicheradresse 0x00500010 einen einzelnen Zeiger zu und kopiert die die Anschrift des String-Literals dazu.

Da pmessage auf das Zeichenfolgenliteral zeigt, sollte es nicht als Argument für Funktionen verwendet werden, die den Inhalt der Zeichenfolge ändern müssen:

strcpy(amessage, pmessage); /* OKAY */
strcpy(pmessage, amessage); /* NOT OKAY */
strtok(amessage, " ");      /* OKAY */
strtok(pmessage, " ");      /* NOT OKAY */
scanf("%15s", amessage);      /* OKAY */
scanf("%15s", pmessage);      /* NOT OKAY */

usw. Wenn Sie pmessage geändert haben, um auf amessage zu verweisen:

pmessage = amessage;

dann kann es überall verwendet werden, wo eine Nachricht verwendet werden kann.

  • @John Bode, tolle Antwort :).

    – Soumya

    3. September 2009 um 12:21 Uhr

  • Die letzte Zeile stimmt nicht ganz: Das Verhalten ist anders, wenn es als verwendet wird sizeof message oder &pmessage .

    – MM

    28. Juli 2015 um 6:30 Uhr

  • @zen: Einstellung pmessage auf einen anderen String zu zeigen, hat absolut keine Auswirkung auf den Inhalt des String-Literals, das unter gespeichert ist 0x0000800. Der Speicher für dieses Zeichenfolgenliteral wird erst freigegeben, wenn das Programm beendet wird.

    – Johannes Bode

    30. Dezember 2015 um 12:21 Uhr

  • @Zen: deine Freunde sind falsch; Arrays wie amessage sind nicht Zeiger. Array Objekte Speichern Sie nirgendwo eine Adresse (was aus der Speicherkarte in meiner Antwort hervorgehen sollte). Eher Array Ausdrücke wird zu Zeigertypen “zerfallen”, es sei denn, sie sind Operanden des Unären & oder sizeof Operatoren (daher der Unterschied im Verhalten für sizeof).

    – Johannes Bode

    4. Januar 2016 um 12:25 Uhr


  • @Zen: Weitere Informationen finden Sie in dieser Antwort.

    – Johannes Bode

    4. Januar 2016 um 13:07 Uhr

Stimmt, aber es ist ein feiner Unterschied. Im Wesentlichen ersteres:

char amessage[] = "now is the time";

Definiert ein Array, dessen Mitglieder sich im Stapelbereich des aktuellen Gültigkeitsbereichs befinden, während:

char *pmessage = "now is the time";

Definiert einen Zeiger, der sich im Stapelspeicher des aktuellen Bereichs befindet, aber auf den Speicher an anderer Stelle verweist (in diesem Fall wird “jetzt ist die Zeit” an einer anderen Stelle im Speicher gespeichert, üblicherweise in einer Zeichenfolgentabelle).

Beachten Sie auch, dass, da die zur zweiten Definition gehörenden Daten (der explizite Zeiger) nicht im Stackspace des aktuellen Bereichs gespeichert werden, nicht genau angegeben ist, wo sie gespeichert werden, und nicht geändert werden sollten.

Bearbeiten: Wie von Mark, GMan und Pavel hervorgehoben, gibt es auch einen Unterschied, wenn der address-of-Operator für eine dieser Variablen verwendet wird. Beispielsweise gibt &pmessage einen Zeiger vom Typ char** oder einen Zeiger auf einen Zeiger auf chars zurück, während &amessage einen Zeiger vom Typ char zurückgibt[16]

  • oder ein Zeiger auf ein Array von 16 Zeichen (das, wie ein char**, zweimal dereferenziert werden muss, wie litb betont).

    Dies ist zwar wahr, aber kaum der größte Unterschied. Was ist zum Beispiel der Unterschied zwischen &amessage und &pmessage?

    – Markieren Sie Lösegeld

  • &pmessage 26. August 2009 um 16:12 Uhr pmessagewird die Adresse von sein &amessage , irgendwo auf dem Stapel. Ebenfalls, amessagewird die Adresse des Arrays auf dem Stack sein, genauso wie &amessage . Jedoch, amessagehat einen anderen Typ als

    .

    – GManNickG

  • 26. August 2009 um 16:24 Uhr &pmessage Nein, es ist nicht undefiniert. Der Unterschied besteht darin, dass die Art der char** ist &amessage – Zeiger auf Zeiger auf char und den Typ von char(*)[16] ist

    – Zeiger auf Array von 16 Zeichen. Diese beiden Typen sind nicht kompatibel (insbesondere der zweite ist einfach die Adresse des ersten Zeichens in der Zeichenfolge, während der erste die Adresse der Variablen ist, die die Adresse des ersten Zeichens speichert).

    – Pavel Minaev

  • 26. August 2009 um 16:24 Uhr

    Seltsam, ich denke, C tut das. Ich dachte, &amessage wäre ungültig, da amessage in einen codekonstanten Zeiger aufgelöst wird. . .

    – Walter W

  • 26. August 2009 um 16:27 Uhr

    @Bill: Nein, denn die Array-Version ist eigentlich nur eine Abkürzung für die Array-Instanziierung. Das Array wird also im Stapel zugewiesen und dann mit den Daten der Zeichenfolge geladen.

    – Walter W

26. August 2009 um 17:42 Uhr

Ein Array enthält die Elemente. Ein Zeiger zeigt auf sie.

char amessage[16];
amessage[0] = 'n';
amessage[1] = 'o';
...
amessage[15] = '\0';

Die erste ist eine Kurzform des Sprichworts

Das heißt, es ist ein Array, das alle Zeichen enthält. Die spezielle Initialisierung initialisiert es für Sie und bestimmt seine Größe automatisch. Die Array-Elemente sind modifizierbar – Sie können Zeichen darin überschreiben.

char *pmessage = "now is the time";
*pmessage="p"; /* undefined behavior! */

Die zweite Form ist ein Zeiger, der nur auf die Zeichen zeigt. Es speichert die Zeichen nicht direkt. Da das Array ein String-Literal ist, können Sie den Zeiger nicht nehmen und dorthin schreiben, wo er hinzeigt

  • Dieser Code würde wahrscheinlich auf Ihrer Box abstürzen. Aber es kann tun, was es will, weil sein Verhalten undefiniert ist.

    Sir, ich möchte eine Sache fragen, ob ich %d in printf für char verwenden kann, ich dachte, dass ich das kann, weil sie standardmäßig zu integer befördert werden, aber diese Antwort sagt etwas anderes, ich bin verwirrt, wenn Sie die Verwirrung beseitigen könnten wäre eine große Hilfe stackoverflow.com/a/41349954/5473170

    – Suraj Jain

28. Dezember 2016 um 5:13 Uhr Ich kann die anderen Antworten nicht sinnvoll ergänzen, aber ich werde das in erwähnenTiefe C-Geheimnisse


, geht Peter van der Linden ausführlich auf dieses Beispiel ein. Wenn Sie diese Art von Fragen stellen, werden Sie dieses Buch lieben. pmessagePS Sie können einen neuen Wert zuweisen amessage. Sie können keinen neuen Wert zuweisen ; es istunveränderlich

. sizeof(p)/sizeof(type-of-array) Wenn ein Array so definiert ist, dass seine Größe zum Zeitpunkt der Deklaration verfügbar ist,

  • gibt die Anzahl der Elemente im Array zurück.

    Alle anderen Antworten konzentrierten sich auf “auf String-Literaladresse zeigen vs. Zeichen der Zeichenfolge in Array kopieren”, was gültig ist, aber spezifisch für den Beispielcode des OP ist. Alle haben dies (das unterschiedliche Ergebnis von sizeof()) nicht erwähnt, was meiner Meinung nach ein sehr wichtiger Unterschied zwischen Arrays und Zeigern ist.

    – Nikolaus Miari

14. Dezember 2014 um 14:24 Uhr
Benutzeravatar von Graphics Noob

Grafik Noob Abgesehen davon, dass der Speicher für den String „jetzt ist die Zeit“ an zwei verschiedenen Stellen zugewiesen wird, sollten Sie auch bedenken, dass der Array-Name als Zeiger fungiert Wert im Gegensatz zu einem Zeiger Variable

char arr[] = "now is the time";
char *pchar = "later is the time";

char arr2[] = "Another String";

pchar = arr2; //Ok, pchar now points at "Another String"

arr = arr2; //Compiler Error! The array name can be used as a pointer VALUE
            //not a pointer VARIABLE

  • welche pmessage ist. Der Hauptunterschied besteht darin, dass die Zeigervariable geändert werden kann, um auf eine andere Stelle zu zeigen, und das Array nicht.

    Alle anderen Antworten konzentrierten sich auf “auf String-Literaladresse zeigen vs. Zeichen der Zeichenfolge in Array kopieren”, was gültig ist, aber spezifisch für den Beispielcode des OP ist. Alle haben dies (das unterschiedliche Ergebnis von sizeof()) nicht erwähnt, was meiner Meinung nach ein sehr wichtiger Unterschied zwischen Arrays und Zeigern ist.

    – Nikolaus Miari

14. Dezember 2014 um 14:24 Uhr

#include <stdio.h>

int main ()
{

char amessage[] = "now is the time"; /* Attention you have created a "string literal" */

char *pmessage = "now is the time";  /* You are REUSING the string literal */


/* About arrays and pointers */

pmessage = NULL; /* All right */
amessage = NULL; /* Compilation ERROR!! */

printf ("%d\n", sizeof (amessage)); /* Size of the string literal*/
printf ("%d\n", sizeof (pmessage)); /* Size of pmessage is platform dependent - size of memory bus (1,2,4,8 bytes)*/

printf ("%p, %p\n", pmessage, &pmessage);  /* These values are different !! */
printf ("%p, %p\n", amessage, &amessage);  /* These values are THE SAME!!. There is no sense in retrieving "&amessage" */


/* About string literals */

if (pmessage == amessage)
{
   printf ("A string literal is defined only once. You are sharing space");

   /* Demostration */
   "now is the time"[0] = 'W';
   printf ("You have modified both!! %s == %s \n", amessage, pmessage);
}


/* Hope it was useful*/
return 0;
}

  • Ein Zeiger ist nur eine Variable, die eine Speicheradresse enthält. Beachten Sie, dass Sie mit “Zeichenfolgenliteralen” spielen, was ein weiteres Problem darstellt. Unterschiede inline erklärt: Grundsätzlich:

    Je nach Compiler können sich die String-Literale unterschiedlich verhalten.

    – Sergio

1424560cookie-checkC: Unterschiede zwischen Char-Zeiger und Array [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy