initialize - declare string pointer c



Qual è la differenza tra la restituzione di un carattere*e un carattere (4)

Perché la prima funzione restituisce la stringa "Hello, World" ma la seconda funzione non restituisce nulla. Ho pensato che il valore di ritorno di entrambe le funzioni sarebbe indefinito dal momento che stanno restituendo dati che non rientrano nell'ambito.

#include <stdio.h>
// This successfully returns "Hello, World"
char* function1()
{
    char* string = "Hello, World!";
    return string;
}
// This returns nothing
char* function2()
{
    char string[] = "Hello, World!";
    return string; 
}

int main()
{
    char* foo1 = function1();
    printf("%s\n", foo1); // Prints "Hello, World"
    printf("------------\n");
    char* foo2 = function2(); // Prints nothing
    printf("%s\n", foo2);
    return 0;
}

Answer #1

Ho pensato che il valore di ritorno di entrambe le funzioni sarebbe indefinito dal momento che stanno restituendo dati che non rientrano nell'ambito.

Entrambe le funzioni restituiscono un puntatore. Ciò che conta è la portata del referente .

In function1 , il referente è la stringa letterale "Hello, World!" , che ha una durata di archiviazione statica. string è una variabile locale che punta a quella stringa e concettualmente viene restituita una copia di quel puntatore (in pratica, il compilatore eviterà di copiare inutilmente il valore).

In function2 , concettualmente il referente è la string array locale, che è stata automaticamente dimensionata (in fase di compilazione) per essere abbastanza grande da contenere letteralmente la stringa (incluso un terminatore nullo), ed è stata inizializzata con una copia della stringa . La funzione restituirebbe un puntatore a quell'array, tranne per il fatto che l'array ha una durata di memorizzazione automatica e quindi non esiste più dopo essere uscito dalla funzione (è davvero "fuori campo", in termini più familiari). Poiché si tratta di un comportamento indefinito, il compilatore può in pratica fare ogni sorta di cose .

Ciò significa che tutti i char* sono statici?

Ancora una volta, è necessario distinguere tra puntatore e referente. I puntatori indicano i dati; essi stessi non "contengono" i dati.

Hai raggiunto un punto in cui dovresti studiare correttamente quali matrici e puntatori si trovano effettivamente in C - sfortunatamente, è un po 'un casino. Il miglior riferimento che posso offrire a mano è this , in formato Domande e risposte.


Answer #2

Ho pensato che il valore di ritorno di entrambe le funzioni sarebbe indefinito dal momento che stanno restituendo dati che non rientrano nell'ambito.

No. Non è così.

Nella funzione function1 stai restituendo il puntatore a una stringa letterale. Restituire il puntatore a un valore letterale di stringa va bene perché i valori letterali di stringa hanno una durata di memorizzazione statica . Ma questo non è vero con la variabile locale automatica .

Nella funzione function2 la string array è una variabile locale automatica e l'istruzione

return string; 

restituisce un puntatore a una variabile locale automatica. Una volta restituita la funzione, la string variabile non esisterà più. Dereferenziare il puntatore restituito causerà un comportamento indefinito.


Answer #3

La prima cosa che devi imparare sulle stringhe è che una stringa letterale è in realtà una matrice di caratteri di sola lettura con una durata dell'intero programma. Ciò significa che non usciranno mai dal campo di applicazione, esisteranno sempre durante l'esecuzione del programma.

Quello che fa la prima funzione ( function1 ) è restituire un puntatore al primo elemento di tale array.

Con la seconda funzione ( function2 ) le cose sono leggermente diverse. Qui la string della variabile è una variabile locale all'interno della funzione. Come tale, uscirà dal campo di applicazione e cesserà di esistere una volta che la funzione tornerà. Con questa funzione restituisci un puntatore al primo elemento di quell'array, ma quel puntatore diventerà immediatamente non valido poiché punterà a qualcosa che non esiste più. Dereferenziarlo (che succede quando lo si passa a printf ) porterà a un comportamento indefinito .


Answer #4

Una cosa molto importante da ricordare quando si codifica in C o in altri linguaggi basati su stack è che quando una funzione ritorna, essa (e tutta la sua memoria locale) è sparita. Ciò significa che se vuoi che qualcun altro sia in grado di vedere i risultati del tuo duro lavoro con i tuoi metodi, devi metterlo in un posto che esisterà ancora dopo che il tuo metodo sarà cessato, e farlo significa che devi capire dove C immagazzina cose e come.

Probabilmente sai già come funziona un array in C. È solo un indirizzo di memoria che viene incrementato dalla dimensione dell'oggetto e probabilmente sai anche che C non esegue il controllo dei limiti, quindi se vuoi accedere all'undicesimo elemento di un dieci array di elementi, nessuno ti fermerà, e finché non provi a scrivere nulla, nessun danno fatto. Quello che potresti non sapere è che C estende questa idea al modo in cui utilizza funzioni e variabili. Una funzione è solo un'area di memoria su uno stack che viene caricato su richiesta e l'archiviazione per le sue variabili sono solo offset da quella posizione. La tua funzione ha restituito un puntatore a una variabile locale, in particolare l'indirizzo di una posizione nello stack che contiene la "H" di "Hello World \ n \ 0" ma quando hai chiamato un'altra funzione (il metodo di stampa), quella memoria era riutilizzato dal metodo di stampa per fare ciò di cui aveva bisogno. Puoi vederlo abbastanza facilmente (NON FARLO NEL CODICE DI PRODUZIONE !!!)

char* foo2 = function2(); // Prints nothing
ch = foo2[0];  // Do not do this in live code!
printf("%s\n", foo2);  // stack used by foo2 now used by print()
printf("ch is %c\n", ch);  // will have the value 'H'!




pointers