Dies wäre nicht gültig: char p[3] = "hello"; Die Initialisierungszeichenfolge ist zu lang für die Größe des deklarierten Arrays. Tippfehler?
– Cody Grey ♦
17. April 2012 um 7:17 Uhr
Oder nur char p[]="hello"; würde genügen!
– Tieftauchgang
2. Juli 2014 um 10:03 Uhr
mögliches Duplikat von C: Unterschiede zwischen Zeichenzeiger und Array
– Saschoalm
1. Februar 2015 um 18:27 Uhr
mögliches Duplikat von Was ist der Unterschied zwischen char s[] und char *s in C? Dies fragt zwar auch speziell nach dem Funktionsparameter, aber das ist es nicht char Spezifisch.
– Ciro Santilli OurBigBook.com
5. Juni 2015 um 7:44 Uhr
Sie müssen verstehen, dass sie sich grundlegend unterscheiden. Die einzige Gemeinsamkeit dabei ist, dass die Basis des Arry p[] ist ein konstanter Zeiger, der den Zugriff auf das Array p ermöglicht[] über einen Zeiger. p[] selbst enthält Speicher für eine Zeichenfolge, während *p nur auf die Adresse des ersten Elements von nur EINEM ZEICHEN zeigt (dh auf die Basis einer bereits zugewiesenen Zeichenfolge). Um dies besser zu veranschaulichen, betrachten Sie Folgendes: char *cPtr = {‘h’,’e’,’l’,’l’,’o’, ‘\0’}; ==>Dies ist ein Fehler, da cPtr ein Zeiger auf nur ein Zeichen char cBuff ist[] = {‘h’, ‘e’,’l’,’l’,’o’,’\0′}; ==>Das ist in Ordnung, bcos cBuff selbst ist ein char-Array
– Ilavarasan
27. Oktober 2015 um 3:20 Uhr
Jon
char* und char[]sind verschiedene Arten, aber es ist nicht in allen Fällen sofort ersichtlich. Dies liegt daran, dass Arrays zerfallen in Zeigerwas bedeutet, dass wenn ein Ausdruck vom Typ char[] vorgesehen ist, wo eine vom Typ char* erwartet wird, wandelt der Compiler das Array automatisch in einen Zeiger auf sein erstes Element um.
Ihre Beispielfunktion printSomething erwartet einen Zeiger, wenn Sie also versuchen, ihm ein Array wie folgt zu übergeben:
char s[10] = "hello";
printSomething(s);
Der Compiler gibt vor, dass Sie Folgendes geschrieben haben:
char s[10] = "hello";
printSomething(&s[0]);
Hat sich von 2012 bis heute etwas geändert. Für ein Zeichenarray druckt “s” das gesamte Array, dh “hello”
– Bhanu Tez
9. Mai 2019 um 6:48 Uhr
@BhanuTez Nein, wie Daten gespeichert werden und was mit den Daten gemacht wird, sind separate Anliegen. Dieses Beispiel gibt die gesamte Zeichenfolge aus, da dies so ist printf behandelt die %s Format-String: Beginnen Sie an der angegebenen Adresse und fahren Sie fort, bis Sie auf ein Null-Terminator stoßen. Wenn Sie nur ein Zeichen drucken möchten, können Sie die verwenden %c Format-String, zum Beispiel.
– Jacobq
17. Juni 2019 um 10:59 Uhr
Wollte nur fragen ob char *p = "abc"; das NULL-Zeichen \0 wird wie bei char automatisch angehängt [] Reihe?
– ajaysinghnegi
8. Juli 2019 um 17:53 Uhr
warum ich einstellen kann char *name; name="123"; kann aber das gleiche mit machen int Typ? Und nach dem Gebrauch %c zu drucken name die Ausgabe ist eine unlesbare Zeichenfolge: �?
– Tom Sawyer
23. April 2020 um 19:52 Uhr
JJJ
Mal schauen:
#include <stdio.h>
#include <string.h>
int main()
{
char *p = "hello";
char q[] = "hello"; // no need to count this
printf("%zu\n", sizeof(p)); // => size of pointer to char -- 4 on x86, 8 on x86-64
printf("%zu\n", sizeof(q)); // => size of char array in memory -- 6 on both
// size_t strlen(const char *s) and we don't get any warnings here:
printf("%zu\n", strlen(p)); // => 5
printf("%zu\n", strlen(q)); // => 5
return 0;
}
foo* und foo[] sind unterschiedliche Typen und werden vom Compiler unterschiedlich behandelt (Zeiger = Adresse + Darstellung des Zeigertyps, Array = Zeiger + optionale Länge des Arrays, sofern bekannt, z. B. wenn das Array statisch zugewiesen ist), können die Details sein in der Norm gefunden. Und auf der Ebene der Laufzeit gibt es keinen Unterschied zwischen ihnen (in Assembler, naja, fast, siehe unten).
Mein Programm stürzt ab, wenn ich versuche, p einen neuen Wert zuzuweisen[i].
EIN: Ein Zeichenfolgenliteral (der formale Begriff für eine Zeichenfolge in doppelten Anführungszeichen in C-Quellen) kann auf zwei leicht unterschiedliche Arten verwendet werden:
Als Initialisierer für ein Array von char, wie in der Deklaration von char a[] gibt es die Anfangswerte der Zeichen in diesem Array an (und, falls erforderlich, seine Größe).
Überall sonst wird es zu einem unbenannten, statischen Array von Zeichen, und dieses unbenannte Array kann im Nur-Lese-Speicher gespeichert werden und kann daher nicht unbedingt geändert werden. In einem Ausdruckskontext wird das Array wie üblich sofort in einen Zeiger umgewandelt (siehe Abschnitt 6), sodass die zweite Deklaration p so initialisiert, dass es auf das erste Element des unbenannten Arrays zeigt.
Einige Compiler haben einen Schalter, der steuert, ob String-Literale schreibbar sind oder nicht (zum Kompilieren von altem Code), und einige haben möglicherweise Optionen, um zu bewirken, dass String-Literale formal als Arrays von const char behandelt werden (für eine bessere Fehlererkennung).
Siehe auch Fragen 1.31, 6.1, 6.2, 6.8 und 11.8b.
Referenzen: K&R2 Sek. 5,5 p. 104
ISO-Sek. 6.1.4, Kap. 6.5.7
Begründung Sek. 3.1.4
H&S Sek. 2.7.4 S. 31-2
Warum zerfällt q in sizeof(q) nicht in einen Zeiger, wie @Jon in seiner Antwort erwähnt?
– garp
21. April 2016 um 19:23 Uhr
@garyp q zerfällt nicht in einen Zeiger, weil sizeof ein Operator und keine Funktion ist (selbst wenn sizeof eine Funktion wäre, würde q nur zerfallen, wenn die Funktion einen char -Zeiger erwartet).
– GiriB
14. August 2016 um 17:07 Uhr
danke, aber printf(“%u\n” statt printf(“%zu\n” , ich denke du solltest z entfernen.
– Zakaria
17. Februar 2018 um 20:11 Uhr
Ciro Santilli OurBigBook.com
Was ist der Unterschied zwischen Char-Array und Char-Zeiger in C?
C99 N1256-Entwurf
Es gibt zwei verschiedene Verwendungen von Zeichenfolgenliteralen:
Initialisieren char[]:
char c[] = "abc";
Dies ist “mehr Magie” und unter 6.7.8/14 “Initialisierung” beschrieben:
Ein Array vom Zeichentyp kann durch ein Zeichenfolgenliteral initialisiert werden, das optional in geschweiften Klammern eingeschlossen ist. Aufeinanderfolgende Zeichen des Zeichenfolgenliterals (einschließlich des abschließenden Nullzeichens, wenn Platz vorhanden ist oder das Array eine unbekannte Größe hat) initialisieren die Elemente des Arrays.
Das ist also nur eine Abkürzung für:
char c[] = {'a', 'b', 'c', '\0'};
Wie jedes andere reguläre Array, c können geändert werden.
Überall sonst: es erzeugt ein:
unbenannt
array of char Was ist der Typ von String-Literalen in C und C++?
mit statischer Lagerung
das gibt UB (undefiniertes Verhalten), wenn es modifiziert wird
Also wenn du schreibst:
char *c = "abc";
Dies ist ähnlich wie:
/* __unnamed is magic because modifying it gives UB. */
static char __unnamed[] = "abc";
char *c = __unnamed;
Beachten Sie die implizite Umwandlung von char[] zu char *was immer legal ist.
Dann, wenn Sie ändern c[0]ändern Sie auch __unnameddas ist UB.
Dies ist unter 6.4.5 “String-Literale” dokumentiert:
5 In Übersetzungsphase 7 wird an jede Multibyte-Zeichenfolge, die aus einem oder mehreren String-Literalen resultiert, ein Byte oder Code mit dem Wert Null angehängt. Die Mehrbyte-Zeichenfolge wird dann verwendet, um ein Array von statischer Speicherdauer und -länge zu initialisieren, die gerade ausreicht, um die Folge zu enthalten. Bei Zeichenkettenliteralen sind die Array-Elemente vom Typ char und werden mit den einzelnen Bytes der Multibyte-Zeichenfolge initialisiert […]
6 Es ist nicht spezifiziert, ob diese Arrays unterschiedlich sind, vorausgesetzt, ihre Elemente haben die entsprechenden Werte. Wenn das Programm versucht, ein solches Array zu ändern, ist das Verhalten undefiniert.
6.7.8/32 “Initialisierung” gibt ein direktes Beispiel:
BEISPIEL 8: Die Deklaration
char s[] = "abc", t[3] = "abc";
definiert “einfache” Char-Array-Objekte s und t deren Elemente mit Zeichenkettenliteralen initialisiert werden.
Der Inhalt der Arrays ist modifizierbar. Andererseits die Deklaration
char *p = "abc";
definiert p vom Typ „pointer to char“ und initialisiert es so, dass es auf ein Objekt vom Typ „array of char“ der Länge 4 zeigt, dessen Elemente mit einem Zeichenfolgenliteral initialisiert werden. Wenn versucht wird, zu verwenden p um den Inhalt des Arrays zu ändern, ist das Verhalten undefiniert.
so wird es im Stack gespeichert (relativ zu %rbp).
Beachten Sie jedoch, dass das standardmäßige Linker-Skript puts .rodata und .text im selben Segment, das Ausführungs-, aber keine Schreibberechtigung hat. Dies kann beobachtet werden mit:
readelf -l a.out
was beinhaltet:
Section to Segment mapping:
Segment Sections...
02 .text .rodata
@leszek.hanusz Undefiniertes Verhalten stackoverflow.com/questions/2766731/… Google “C-Sprache UB” 😉
– Ciro Santilli OurBigBook.com
3. Mai 2016 um 9:47 Uhr
potrzebie
Sie dürfen den Inhalt einer String-Konstante nicht ändern, was die erste ist p verweist auf. Der Zweite p ist ein Array, das mit einer String-Konstante initialisiert wird, und Sie kann seinen Inhalt ändern.
Jonathan Holz
In solchen Fällen ist der Effekt derselbe: Sie übergeben am Ende die Adresse des ersten Zeichens in einer Zeichenkette.
Die Deklarationen sind jedoch offensichtlich nicht gleich.
Im Folgenden wird Speicher für eine Zeichenfolge und auch einen Zeichenzeiger reserviert und dann der Zeiger so initialisiert, dass er auf das erste Zeichen in der Zeichenfolge zeigt.
char *p = "hello";
Während im Folgenden Speicher nur für die Zeichenfolge reserviert wird. Es kann also tatsächlich weniger Speicher verbrauchen.
char p[10] = "hello";
codeplusplus.blogspot.com/2007/09/… “Das Initialisieren der Variablen erfordert jedoch eine enorme Leistungs- und Platzeinbuße für das Array.”
– Blatt
10. März 2013 um 14:22 Uhr
@leef: Ich denke, das hängt davon ab, wo sich die Variable befindet. Wenn es sich im statischen Speicher befindet, ist es meiner Meinung nach möglich, dass das Array und die Daten im EXE-Image gespeichert werden und überhaupt keine Initialisierung erforderlich ist. Ansonsten ja, es kann sicher langsamer werden, wenn die Daten allokiert werden müssen und dann die statischen Daten hineinkopiert werden müssen.
– Jonathan Holz
31. März 2015 um 15:34 Uhr
Rick
Aus APUEAbschnitt 5.14 :
char good_template[] = "/tmp/dirXXXXXX"; /* right way */
char *bad_template = "/tmp/dirXXXXXX"; /* wrong way*/
… Beim ersten Template wird der Name auf dem Stack vergeben, da wir eine Array-Variable verwenden. Für den zweiten Namen verwenden wir jedoch einen Zeiger. In diesem Fall befindet sich nur der Speicher für den Zeiger selbst auf dem Stapel; Der Compiler sorgt dafür, dass die Zeichenfolge im schreibgeschützten Segment der ausführbaren Datei gespeichert wird. Wenn der mkstemp -Funktion versucht, die Zeichenfolge zu ändern, tritt ein Segmentierungsfehler auf.
Der zitierte Text stimmt mit der Erklärung von @Ciro Santilli überein.
codeplusplus.blogspot.com/2007/09/… “Das Initialisieren der Variablen erfordert jedoch eine enorme Leistungs- und Platzeinbuße für das Array.”
– Blatt
10. März 2013 um 14:22 Uhr
@leef: Ich denke, das hängt davon ab, wo sich die Variable befindet. Wenn es sich im statischen Speicher befindet, ist es meiner Meinung nach möglich, dass das Array und die Daten im EXE-Image gespeichert werden und überhaupt keine Initialisierung erforderlich ist. Ansonsten ja, es kann sicher langsamer werden, wenn die Daten allokiert werden müssen und dann die statischen Daten hineinkopiert werden müssen.
– Jonathan Holz
31. März 2015 um 15:34 Uhr
KosminO
Soweit ich mich erinnern kann, ist ein Array eigentlich eine Gruppe von Zeigern. Zum Beispiel
p[1]== *(&p+1)
ist eine wahre aussage
Ich würde ein Array als einen Zeiger auf die Adresse eines Speicherblocks beschreiben. Daher warum *(arr + 1) bringt Sie zum zweiten Mitglied von arr. Wenn *(arr) zeigt auf eine 32-Bit-Speicheradresse, z bfbcdf5edann *(arr + 1) verweist auf bfbcdf60 (das zweite Byte). Daher führt das Verlassen des Bereichs eines Arrays zu seltsamen Ergebnissen, wenn das Betriebssystem keinen Segfault ausführt. Wenn int a = 24; ist unter Adresse bfbcdf62dann zugreifen arr[2] könnte zurückkehren 24vorausgesetzt, es tritt nicht zuerst ein Segfault auf.
– Braden Best
5. Februar 2014 um 3:05 Uhr
14265100cookie-checkWas ist der Unterschied zwischen Char-Array und Char-Zeiger in C?yes
Dies wäre nicht gültig:
char p[3] = "hello";
Die Initialisierungszeichenfolge ist zu lang für die Größe des deklarierten Arrays. Tippfehler?– Cody Grey
♦
17. April 2012 um 7:17 Uhr
Oder nur
char p[]="hello";
würde genügen!– Tieftauchgang
2. Juli 2014 um 10:03 Uhr
mögliches Duplikat von C: Unterschiede zwischen Zeichenzeiger und Array
– Saschoalm
1. Februar 2015 um 18:27 Uhr
mögliches Duplikat von Was ist der Unterschied zwischen char s[] und char *s in C? Dies fragt zwar auch speziell nach dem Funktionsparameter, aber das ist es nicht
char
Spezifisch.– Ciro Santilli OurBigBook.com
5. Juni 2015 um 7:44 Uhr
Sie müssen verstehen, dass sie sich grundlegend unterscheiden. Die einzige Gemeinsamkeit dabei ist, dass die Basis des Arry p[] ist ein konstanter Zeiger, der den Zugriff auf das Array p ermöglicht[] über einen Zeiger. p[] selbst enthält Speicher für eine Zeichenfolge, während *p nur auf die Adresse des ersten Elements von nur EINEM ZEICHEN zeigt (dh auf die Basis einer bereits zugewiesenen Zeichenfolge). Um dies besser zu veranschaulichen, betrachten Sie Folgendes: char *cPtr = {‘h’,’e’,’l’,’l’,’o’, ‘\0’}; ==>Dies ist ein Fehler, da cPtr ein Zeiger auf nur ein Zeichen char cBuff ist[] = {‘h’, ‘e’,’l’,’l’,’o’,’\0′}; ==>Das ist in Ordnung, bcos cBuff selbst ist ein char-Array
– Ilavarasan
27. Oktober 2015 um 3:20 Uhr