Wat is het verschil tussen char s[] en char *s?

In C kan men een letterlijke tekenreeks gebruiken in een declaratie als deze:

char s[] = "hello";

of zoals dit:

char *s = "hello";

Dus wat is het verschil? Ik wil weten wat er werkelijk gebeurt in termen van opslagduur, zowel tijdens compileren als uitvoeren.


Antwoord 1, autoriteit 100%

Het verschil hier is dat

char *s = "Hello world";

plaatst "Hello world"in de alleen-lezen delen van het geheugen, en maakt seen verwijzing naar dat schrijven bewerking op dit geheugen illegaal.

Tijdens het doen:

char s[] = "Hello world";

zet de letterlijke tekenreeks in het alleen-lezen geheugen en kopieert de tekenreeks naar nieuw toegewezen geheugen op de stapel. Zo makend

s[0] = 'J';

legaal.


Antwoord 2, autoriteit 28%

Ten eerste zijn ze in functieargumenten precies equivalent:

void foo(char *x);
void foo(char x[]); // exactly the same in all respects

In andere contexten wijst char *een pointer toe, terwijl char []een array toewijst. Waar gaat de string naartoe in het eerste geval, vraag je? De compiler wijst in het geheim een statische anonieme array toe om de tekenreeks letterlijk te houden. Dus:

char *x = "Foo";
// is approximately equivalent to:
static const char __secret_anonymous_array[] = "Foo";
char *x = (char *) __secret_anonymous_array;

Merk op dat u nooit moet proberen de inhoud van deze anonieme array via deze aanwijzer te wijzigen; de effecten zijn niet gedefinieerd (vaak betekent dit een crash):

x[1] = 'O'; // BAD. DON'T DO THIS.

Als u de array-syntaxis gebruikt, wordt deze direct toegewezen aan nieuw geheugen. Wijzigen is dus veilig:

char x[] = "Foo";
x[1] = 'O'; // No problem.

De array leeft echter maar zo lang als de bijbehorende scope, dus als je dit in een functie doet, retourneer of lek geen pointer naar deze array – maak in plaats daarvan een kopie met strdup()of vergelijkbaar. Als de array in globale scope wordt toegewezen, is dat natuurlijk geen probleem.


Antwoord 3, autoriteit 13%

Deze verklaring:

char s[] = "hello";

Maakt éénobject – een chararray van grootte 6, genaamd s, geïnitialiseerd met de waarden 'h', 'e', 'l', 'l', 'o', '\0'. Waar deze array in het geheugen wordt toegewezen en hoe lang hij meegaat, hangt af van waar de declaratie verschijnt. Als de declaratie binnen een functie valt, zal deze blijven bestaan tot het einde van het blok waarin hij is gedeclareerd, en vrijwel zeker worden toegewezen aan de stapel; als het buiten een functie is, zal het waarschijnlijkworden opgeslagen in een “geïnitialiseerd gegevenssegment” dat vanuit het uitvoerbare bestand in het schrijfbare geheugen wordt geladen wanneer het programma wordt uitgevoerd.

Aan de andere kant, deze verklaring:

char *s ="hello";

Maakt tweeobjecten:

  • A alleen-lezen array van 6 chars met de waarden 'h', 'e', 'l', 'l', 'o', '\0', die geen naam heeft en statische opslagduur heeft (wat betekent dat het voor het hele leven van het programma leeft); en
  • Een variabele van het type pointer-to-char, genaamd s, die wordt geïnitialiseerd met de locatie van het eerste teken in die niet-benoemde alleen-lezen array.

De niet-benoemde alleen-lezen array is meestal in het segment “Tekst” van het programma, dat betekent dat deze wordt geladen van schijf in het alleen-lezen geheugen, samen met de code zelf. De locatie van de sPOSER-variabele in het geheugen is afhankelijk van waar de aangifte wordt weergegeven (net als in het eerste voorbeeld).


Antwoord 4, autoriteit 3%

char s[] = "hello";

verklaart sals een array van chardie lang genoeg is om de initializer (5 + 1 chars) vast te houden en initialiseert de array door de leden van de gegeven string letterlijk naar de array te kopiëren.

char *s = "hello";

verklaart sals een verwijzing naar een of meer (in dit geval meer) chars en wijst deze direct naar een vaste (alleen-lezen) locatie met de letterlijke "hello".


Antwoord 5

char s[] = "Hello world";

Hier is seen reeks tekens, die desgewenst kan worden overschreven.

char *s = "hello";

Een letterlijke tekenreeks wordt gebruikt om deze karakterblokken ergens in het geheugen te maken waarnaar deze aanwijzer sverwijst. We kunnen hier het object waarnaar het verwijst opnieuw toewijzen door dat te wijzigen, maar zolang het verwijst naar een letterlijke tekenreeks, kan het blok met tekens waarnaar het verwijst niet worden gewijzigd.


Antwoord 6

Als toevoeging, bedenk dat, aangezien voor alleen-lezen doeleinden het gebruik van beide identiek is, u toegang kunt krijgen tot een char door te indexeren met []of *(<var> + <index>)
formaat:

printf("%c", x[1]);     //Prints r

En:

printf("%c", *(x + 1)); //Prints r

Natuurlijk, als je probeert

*(x + 1) = 'a';

U krijgt waarschijnlijk een Segmentatiefout, omdat u toegang probeert te krijgen tot alleen-lezen geheugen.


Antwoord 7

Om toe te voegen: je krijgt ook verschillende waarden voor hun maten.

printf("sizeof s[] = %zu\n", sizeof(s));  //6
printf("sizeof *s  = %zu\n", sizeof(s));  //4 or 8

Zoals hierboven vermeld, wordt voor een array '\0'toegewezen als het laatste element.


8

char *str = "Hello";

De bovenstaande sets Str om op de letterlijke waarde “Hallo” te wijzen die hardcodeerd is in het binaire beeld van het programma, dat is gemarkeerd als alleen-lezen in het geheugen, betekent dat elke verandering in deze string letterlijk illegaal is en dat zou gooien segmentatiefouten.

char str[] = "Hello";

Kopieert de string naar nieuw toegewezen geheugen op de stapel. Dus het aanbrengen van een verandering is toegestaan ​​en legaal.

means str[0] = 'M';

zal de str op “MELLO” veranderen.

Ga voor meer informatie door de vergelijkbare vraag:

Waarom krijg ik een segmentatiefout bij het schrijven naar een snaar die is geïnitialiseerd met “char * s” maar niet “char s []”?


9

char *s1 = "Hello world"; // Points to fixed character string which is not allowed to modify
char s2[] = "Hello world"; // As good as fixed array of characters in string so allowed to modify
// s1[0] = 'J'; // Illegal
s2[0] = 'J'; // Legal

10

Een voorbeeld naar het verschil:

printf("hello" + 2); //llo
char a[] = "hello" + 2; //error

In de eerste case-aanwijzer werkt rekenkundigen (arrays die zijn doorgegeven aan een functie verval naar Pointers).


11

In het geval van:

char *x = "fred";

x is een lvalue – kan worden toegewezen aan. Maar in het geval van:

char x[] = "fred";

x is geen LVALUE, het is een rvalue – u kunt er niet aan toewijzen.


12

In het licht van opmerkingen hier moet het duidelijk zijn dat: char * s = “hallo”;
Is een slecht idee en moet worden gebruikt in een zeer smalle reikwijdte.

Dit is misschien een goede gelegenheid om erop te wijzen dat “Const-correctheid” een “goede ding” is. Wanneer en waar u kunt, gebruikt u het “Const” -trefwoord om uw code te beschermen, van “ontspannen” bellers of programmeurs, die meestal het meest “ontspannen” zijn wanneer aanwijzingen in het spel komen.

Genoeg Melodrama, hier is wat men kan bereiken bij het aanbidden van aanwijzingen met “const”.
(OPMERKING: Men moet aanwijzeropgiften lezen naar links.)
Hier zijn de 3 verschillende manieren om uzelf te beschermen bij het spelen met Pointers:

const DBJ* p means "p points to a DBJ that is const" 

– dat wil zeggen, het DBJ-object kan niet worden gewijzigd via p.

DBJ* const p means "p is a const pointer to a DBJ" 

– dat wil zeggen, u kunt het DBJ-object wijzigen via P, maar u kunt de aanwijzerp niet wijzigen.

const DBJ* const p means "p is a const pointer to a const DBJ" 

– dat wil zeggen, u kunt de aanwijzerp niet wijzigen, noch kunt u het DBJ-object via p.

De fouten met betrekking tot poging tot const-ant-mutaties worden gevangen bij compileertijd. Er is geen runtime-ruimte of snelheidstraf voor const.

(Veronderstelling is dat u C++ compiler, natuurlijk gebruikt?)

– dbj

Other episodes