Verschil tussen char* en char** (in C)

Ik heb deze code geschreven die eenvoudig is

#include <stdio.h>
#include <string.h>
void printLastLetter(char **str)
{
    printf("%c\n",*(*str + strlen(*str) - 1));
    printf("%c\n",**(str + strlen(*str) - 1));
}
int main()
{
    char *str = "1234556";
    printLastLetter(&str);
    return 1;
}

Als ik nu de laatste char in een string wil afdrukken, weet ik dat de eerste regel van printLastLetter de juiste regel code is. Wat ik niet helemaal begrijp is wat het verschil is tussen *str en **str. De eerste is een reeks karakters, en de tweede??
Wat is ook het verschil in geheugentoewijzing tussen char *str en str[10]?
Bedankt


Antwoord 1, autoriteit 100%

char*is een pointer naar char, char **is een pointer naar een pointer naar char.

char *ptr;wijst GEEN geheugen toe voor karakters, het wijst geheugen toe voor een pointer naar char.

char arr[10];wijst 10 tekens toe en arrbevat het adres van het eerste teken. (hoewel arrGEEN pointer is (niet char *) maar van het type char[10])

Voor demonstratie: char *str = "1234556";is als:

char *str;         // allocate a space for char pointer on the stack
str = "1234556";   // assign the address of the string literal "1234556" to str

Zoals @oli Charlesworth Commentaar, als u een aanwijzer op een constante reeks gebruikt, zoals in het bovenstaande voorbeeld, moet u de aanwijzer aangeven als constconst char *str = "1234556";Dus als u probeert het te wijzigen, dat niet is toegestaan, krijgt u een compiler-time-fout en geen runtime-toegangsovertredingsfout, zoals segmentatiefout. Als je daar niet bekend mee bent, kijk dan hier .

Zie ook de uitleg in de veelgestelde vragen van nieuwsgroep comp.lang.c .


Antwoord 2, Autoriteit 67%

CHAR ** X is een aanwijzer naar een aanwijzer, die handig is wanneer u een bestaande aanwijzer buiten de reikwijdte wilt wijzigen (bijvoorbeeld in een functie-oproep).

Dit is belangrijk omdat C Pass-by Copy is, dus om een ​​aanwijzer in een andere functie te wijzigen, moet u het adres van de aanwijzer doorgeven en een aanwijzer op de aanwijzer gebruiken zoals SO:

void modify(char **s)
{
  free(*s); // free the old array
  *s = malloc(10); // allocate a new array of 10 chars
}
int main()
{
  char *s = malloc(5); // s points to an array of 5 chars
  modify(&s); // s now points to a new array of 10 chars
  free(s);
}

U kunt ook CHAR ** gebruiken om een ​​reeks snaren op te slaan. Als u echter alles dynamisch toewijst, vergeet dan om bij te houden hoe lang de reeks van de snaren is, zodat u door elk element loopt en het bevrijdt.

Wat betreft je laatste vraag, char *str; declareert eenvoudig een pointer zonder toegewezen geheugen, terwijl char str[10]; wijst een array van 10 tekens toe aan de lokale stapel. De lokale array zal echter verdwijnen zodra deze buiten het bereik valt. Daarom wil je, als je een tekenreeks van een functie wilt retourneren, een aanwijzer gebruiken met dynamisch toegewezen (malloc’d) geheugen.

Ook char *str = “Sommige tekenreeksconstante”; is ook een pointer naar een stringconstante. Stringconstanten worden opgeslagen in de algemene gegevenssectie van uw gecompileerde programma en kunnen niet worden gewijzigd. Je hoeft er geen geheugen voor toe te wijzen omdat ze gecompileerd/hardcoded zijn in je programma, dus ze nemen al geheugen in beslag.


Antwoord 3, autoriteit 10%

De eerste is een reeks karakters, en de tweede??

De tweede is een verwijzing naar je array. Aangezien je het adres van str doorgeeft en niet de aanwijzer (str) zelf, heb je dit nodig voor derefensie.

printLastLetter( str ); 

en

printf("%c\n",*(str + strlen(str) - 1)); 

is logischer, tenzij u de waarde van str moet wijzigen.


Antwoord 4, autoriteit 10%

Misschien wil je deze kleine variatie van je programma bestuderen (de functie printLastLetter()is ongewijzigd, behalve dat het statisch is gemaakt), en uitzoeken waarom de uitvoer:

3
X

De uitvoer is volledig deterministisch – maar alleen omdat ik de variabele listzorgvuldig heb ingesteld, zodat deze deterministisch zou zijn.

#include <stdio.h>
#include <string.h>
static void printLastLetter(char **str)
{
    printf("%c\n", *(*str + strlen(*str) - 1));
    printf("%c\n", **(str + strlen(*str) - 1));
}
int main(void)
{
    char *list[] = { "123", "abc", "XYZ" };
    printLastLetter(list);
    return 0;
}

Antwoord 5

Char ** is voor een reeks snaren in principe – een reeks karakterarrays. Als u meerdere karakter array-argumenten wilt doorgeven, kunt u dit gebruiken dat ze correct zijn toegewezen.

Char ** X;
* x zou nerfectiëren en u de eerste karakterarray geven die in x is toegewezen.
** x zou die karakterarray meederen die u het eerste teken in de array geeft.


Antwoord 6

**stris niets anders dan (*str)[0]en het verschil tussen *stren str[10](in de verklaring, ik neem aan) Ik denk dat het is dat de eerste slechts een aanwijzer is die naar een constante string-letterlijke wijzend is die ergens in het wereldwijde statische geheugen kan worden opgeslagen, terwijl de laatste 10 byte van geheugen kan worden opgeslagen de stapel waar de letterlijke wordt opgeslagen.


Antwoord 7

Char * is een aanwijzer naar een geheugenlocatie. voor Char * Str = “123456”; Dit is het eerste teken van een tekenreeks. De “” zijn slechts een handige manier om een ​​reeks tekenwaarden in te voeren.
Str [10] is een manier om 10 tekens in het geheugen te reserveren zonder te zeggen wat ze zijn. (NB sinds het laatste personage is een null die dit daadwerkelijk 9 letters kan bevatten. Wanneer een functie een * parameter neemt, kunt u een parameter [] parameter gebruiken. Maar niet andersom.

Je maakt het onnodig ingewikkeld door het adres van str te nemen voordat je het als parameter gebruikt. In C geef je vaak het adres van een object door aan een functie omdat het een stuk sneller is dan het hele object doorgeven. Maar aangezien het al een pointer is, maak je de functie niet beter door een pointer aan een pointer door te geven. Ervan uitgaande dat u de aanwijzer niet wilt wijzigen om naar een andere tekenreeks te wijzen.


Antwoord 8

voor uw codefragment houdt *strhet adres vast aan een char en **strhoudt het adres vast aan een variabel adres van een char. Met andere woorden, aanwijzer naar aanwijzer.

Als je *str hebt, wordt er alleen genoeg geheugen toegewezen om een variabele van het aanwijzertype (4 byte op een 32-bits machine) te bevatten. Met str[10]is er al geheugen toegewezen voor 10 char.

Other episodes