2015-07-25 15 views
6

Non capisco la differenza tra questo caso:In C, perché non è possibile modificare il valore di una variabile pointer-to-char dopo che è stato assegnato?

#include <stdio.h> 

int main() 
{ 
    int i = 0; 
    i = 1; 

    return 0; 
} 

E questo caso:

#include <stdio.h> 

int main() 
{ 
    char *mychar = "H"; 
    *mychar = "E"; 

    return 0; 
} 

che produce l'avviso del compilatore "Assegnazione rende intero da puntatore senza un cast".

Non dovrebbe *mychar = "E" dereference mychar per assegnargli il valore di "E"?

Molte grazie.

+6

Nota: dopo aver corretto l'avviso cambiando '" E "' a ''E'', non sorprenderti quando il tuo processo si blocca per scrivere in memoria di sola lettura. Stai invocando UB. – WhozCraig

risposta

4

"E" è una stringa letterale (char *) e "E" è un carattere letterale (char).

Si noti che i due pezzi di codice che si stanno confrontando non sono analoghi! La differenza tra i due pezzi di codice (int vs char *) sarà più chiaro è che si scrive

char* mychar = "H"; 
*mychar = "E"; 

il tipo corrispondente all'esempio int è (char *). Cioè, il codice essendo analogico all'esempio "int" è

char* mychar = "H"; 
mychar = "E"; 
2

Le stringhe possono essere memorizzate in sola lettura sezione di memoria. La modifica di una stringa letterale richiama il comportamento non definito. Non puoi modificarlo.

Aggiungi const qualificatore di lasciare il vostro compilatore sa che stringa è non modificabile

char const *mychar = "H"; 

Si deve anche notare che la dichiarazione

*mychar = "E"; 

è sbagliato di per sé. Stai assegnando un tipo char * a char.

+4

Il problema è più che sta assegnando un 'const char *' a un '(const) char'; l'UB è un problema "secondario". Nota: non è equivalente, in quanto potrebbe cambiare il puntatore in un secondo momento in modo che punti a una stringa non-'conven». – Olaf

+0

@Olaf; Sì. Aggiunto alla risposta. – haccks

+1

Sidenotes: 'char const *' è deprecato (almeno da C11). Dovresti usare lo stesso 'const char *. 'const' potrebbe causare problemi se il puntatore viene modificato lateralmente in un' char' non const (tipico per la stringa predefinita di un puntatore). – Olaf

6

Hai confuso alcune cose.

  • Nota "E" è in realtà const char[] che memorizza 'E' e '\0'. Non è un singolo personaggio. Per singoli caratteri si utilizza '', ad esempio 'E'.
  • mychar punti al letterale stringa e non è possibile modificare i valori letterali stringa.

Se quello che aveva in mente è questa:

char *mychar = "H"; 
mychar = "E"; 

Questo è ok, non si sta cambiando la stringa letterale, appena prima volta il puntatore mychar punti a stringa letterale "H", poi a "E".

Questo non si può fare:

char *mychar = "Hello"; 
    *mychar = 'E'; // Can't modify the string literal 

Ma questo si può fare:

char c = 0; 
    char *mychar = &c; 
    *mychar = 'E'; // This is ok 
1

Credo che si intende il seguente

#include <stdio.h> 

int main() 
{ 
    char *mychar = "H"; 
    mychar = "E"; 

    return 0; 
} 

Dopo l'assegnazione dei punti di puntatore per stringa letterale "E".

Così come si vede il puntatore può essere riassegnato. Solo tu dovresti usare una sintassi corretta. Espressione *mychar significa il dereferenziamento di un puntatore. Il suo valore non è il valore memorizzato nel puntatore ma il valore di un oggetto puntato dal puntatore.

Per quanto riguarda il codice originale, allora in questa informativa

*mychar = "E"; 

l'operando sinistro della cessione *mychar è digitare char mentre l'operando di destra "E" ha tipo di puntatore char * (il tipo array che corrisponde alla stringa letterale è implicitamente convertito nel puntatore al suo primo elemento) e il compilatore ti avverte che stai cercando di fare qualcosa di sbagliato.

Prendere in considerazione che i valori letterali stringa non possono essere modificati. Così, per esempio questa dichiarazione

*mychar = 'E'; 

ha undefined comportamento (qui viene utilizzato il carattere costante intera 'E')

0

char *mychar = "H" dice al compilatore che mychar punta a un array di caratteri. *mychar dereferenze il primo carattere nella matrice, letteralmente 'H' (notare le virgolette singole).

quando si scrive:

*mychar = "E" si sta cercando di mettere una stringa (letteralmente un puntatore-a-character-array) in cui un letterale caratteri dovrebbe andare, in modo che il codice tecnicamente corretta sarebbe:

*mychar = 'E'; // assign a character-literal, not a string

Nota però che le stringhe sono in genere creati in memoria di sola lettura, quindi se in realtà scrive 'E' alla locazione di memoria di sola lettura in cui 'H' è attualmente, il programma sarà probabilmente in crash.

Se si voleva evitare il compilatore di avviso (ma ancora scrivere il codice del tutto errata e crash) si scrive:

(char *)(*mychar) = "E"; // make the compiler think *mychar is pointer-to-char, very bad, will crash, but won't warn any more

0

ci sono due questioni in gioco qui - la comprensione del tipo di il tuo puntatore e capire quali parti della memoria puoi modificare.

versioni recenti del problema del compilatore gcc un avvertimento per la linea:

char *mychar = "H"; 

anche se l'avviso può essere difficile da capire:

warning: deprecated conversion from string constant to ‘char*’ 

Quella riga di codice compila ancora e corre nonostante la avvertimento. Fondamentalmente, ti scoraggiano dal farlo - mychar ora è un puntatore ad un posto in memoria dove il compilatore ha posto i due caratteri, 'H' e '\ 0'. Se fai qualcosa come mychar [3] = 'X', stai scrivendo un'area della memoria di cui non sai nulla e che non controlli; a seconda dell'implementazione, ciò potrebbe causare un errore in fase di esecuzione. Se si aggiunge const:

const char *mychar = "H"; 

o

char const *mychar = "H"; 

l'avvertimento va via, ma ora hanno messo in chiaro a te stesso che non è possibile utilizzare questo puntatore per cambiare la memoria. Se in seguito fai

*mychar = 'E'; 

che causerà un errore di compilazione (non un avvertimento), perché non è possibile utilizzare un const char * a cambiare la memoria.

Ora, per quanto riguarda il messaggio di errore è effettivamente ottenuto, è perché hai scritto

*mychar = "E"; 

invece di

*mychar = 'E'; 

Quando il compilatore vede "E", si mette da parte un po 'di memoria nella eseguibile con i caratteri 'E' e '\ 0', e il valore di "E" è un puntatore (char *) a quel punto in memoria. * mychar è il carattere all'indirizzo indicato da mychar. Così

*mychar = "E"; 

sta prendendo il char * puntatore alla "E" stringa, e metterlo nella posizione in memoria puntata da MyChar. La cosa veramente confusa sul tuo messaggio di errore è che si riferisce a un numero intero; Suppongo che sia perché char può essere considerato un tipo di intero (il char senza segno può assumere qualsiasi valore compreso tra 0 e 255).

si sta tentando di impostare il valore di un carattere sul valore di un puntatore. E 'legale (anche se raramente una buona idea) per attivare un puntatore in un intero, così si potrebbe provare

*mychar = (char)"E"; 

ma con la mia versione di gcc (4.9.3) che produce un errore di compilazione perché il cast si riduce precisione: stai prendendo un valore a 32 o 64 bit e lo trasformi in un valore a 8 bit. Anche in questo caso, con la mia versione di gcc,

*mychar = (int)"E"; 

compila (se non ho fatto MyChar un const char *), ma produce un errore di run-time, perché sta cercando di cambiare memoria di sola lettura.

Forse ciò che realmente intendeva era

mychar = "E"; 

Questo cambia MyChar dalla punta al posto di memoria che contiene "H" al posto in memoria contenente "E". Questo compila e funziona correttamente.

Problemi correlati