Differenza tra char * e const char *?


177

Qual è la differenza tra

char* name

che indica una stringa costante letterale e

const char* name

cosa intendi per " costante stringa letterale" in C (non C ++)
gbulmer

1
... char * name può essere fatto indicare una costante stringa letterale
Iceman

la costante in "costante stringa letterale" è ridondante, poiché tutti i letterali stringa sono in teoria entità costanti. È il contenuto della variabile che può essere reso costante o modificabile. La dichiarazione "const" genererà semplicemente un errore di tempo di compilazione se provi a cambiare il contenuto del personaggio indicato dal "nome"
Cupcake

Semplice: il nome "char * name" è un puntatore a char, ovvero qui è possibile cambiare entrambi. Il nome "const char * name" è un puntatore a const char, ovvero il puntatore può cambiare ma non char.
AkD

Leggi queste cose da destra a sinistra.
Jiapeng Zhang,

Risposte:


406

char*è un puntatore mutabile a un carattere / stringa mutabile .

const char*è un puntatore mutevole a un carattere / stringa immutabile . Non è possibile modificare il contenuto delle posizioni a cui punta questo puntatore. Inoltre, i compilatori sono tenuti a fornire messaggi di errore quando si tenta di farlo. Per lo stesso motivo, la conversione da const char *a char*è obsoleta.

char* constè un puntatore immutabile (non può puntare a nessun'altra posizione) ma i contenuti della posizione in cui punta sono mutabili .

const char* constè un puntatore immutabile a un carattere / stringa immutabile .


4
La confusione può essere chiarita con l'uso di una variabile dopo le dichiarazioni di cui sopra e facendo riferimento a tale variabile.
ankit.karwasra,

3
@ ankit.karwasra, Ne hai perso uno in più:char const *
Pacerier,

Suppongo che due opzioni con carattere / stringa mutabili siano altamente pericolose, dal momento che potresti fare una memoria di errore di segmetazione e se sei davvero intelligente potresti hackerare il computer. Questo è il motivo per cui i compilatori hanno sempre mostrato avvertimenti in quelle implementazioni, credo
Daniel N.

1
La mutazione non char *fornisce un errore di segmentazione durante l'esecuzione?
Divyanshu Maithani,

1
Quindi uso constse voglio che il compilatore dia l'errore se ho dimenticato e modificato i dati per errore, giusto?
Ragioniere م

43
char *name

È possibile modificare il carattere a cui namepunta e anche il carattere a cui punta.

const char* name

È possibile modificare il carattere in cui namepunti, ma non è possibile modificare il carattere in corrispondenza del quale punta.
correzione: è possibile modificare il puntatore, ma non il carattere a cui namepunta ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , vedere "Esempi" ). In questo caso, si constapplica lo specificatore char, non l'asterisco.

Secondo la pagina MSDN e http://en.cppreference.com/w/cpp/language/declarations , il constprima *è parte della sequenza del decl-specificatore, mentre il constdopo *fa parte del dichiaratore.
Una sequenza di specificatori di dichiarazioni può essere seguita da più dichiaratori, motivo per cui const char * c1, c2dichiara c1come const char *e c2come const char.

MODIFICARE:

Dai commenti, la tua domanda sembra porre la differenza tra le due dichiarazioni quando il puntatore punta a una stringa letterale.

In tal caso, non è necessario modificare il carattere in quali namepunti, in quanto potrebbe comportare un comportamento indefinito . I letterali di stringa possono essere allocati in aree di memoria di sola lettura (implementazione definita) e un programma utente non dovrebbe modificarlo in alcun modo. Qualsiasi tentativo di farlo comporta un comportamento indefinito.

Quindi l'unica differenza in quel caso (di utilizzo con valori letterali stringa) è che la seconda dichiarazione offre un leggero vantaggio. I compilatori di solito ti avvisano nel caso in cui tenti di modificare la stringa letterale nel secondo caso.

Esempio di esempio online:

#include <string.h>
int main()
{
    char *str1 = "string Literal";
    const char *str2 = "string Literal";
    char source[] = "Sample string";

    strcpy(str1,source);    //No warning or error, just Undefined Behavior
    strcpy(str2,source);    //Compiler issues a warning

    return 0;
}

Produzione:

cc1: avvertenze trattate come errori
prog.c: nella funzione 'main':
prog.c: 9: errore: passando l'argomento 1 di 'strcpy' scarta i qualificatori dal tipo di target puntatore

Si noti che il compilatore avvisa per il secondo caso ma non per il primo.


Grazie .. stavo mescolando con la costante stringa letterale, che è definita come: char * name = "String Literal"; Cambiare "String Literal" non è definito ..
Iceman

@ user1279782: Err, aspetta! Stai parlando di punti che indicano letterali stringa qui? In tal caso , non è necessario modificare il carattere a cui i namepunti in entrambi i casi potrebbero causare UB.
Risparmia il

Sì, quello era il punto. Quindi in quel caso char * name e const char * name si comportano in modo simile, giusto?
Iceman,

4
Questa risposta è estremamente ambigua o semplicemente sbagliata. Interpreterei "Non è possibile modificare il carattere a cui punta il nome, ma è possibile modificare il carattere a cui punta". Come non essere in grado di modificare il puntatore stesso, ma essere in grado di modificare la posizione di memoria a cui punta, che non è corretto: ideone.com/6lUY9s alternativamente pura C: ideone.com/x3PcTP
shroudednight

1
@shroudednight: devi imparare un po 'di più sui comportamenti indefiniti e devi distinguere tra: permesso e non dovrebbe essere fatto. :)
Alok Salva il

16
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)

constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error

constcharp[3] = '\0'; // compile error
charconstp[3] = '\0'; // compile error
charpconst[3] = '\0'; // ok

// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";

lcharp[0] = 'X';      // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error

// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X';          // compile error
((char*)astr)[0] = 'X'; // ok

1
Nessuno dei tuoi puntatori punta a "valori letterali a stringa costante" come da domanda.
Caf

Vale la pena notare che la modifica del char *valore genera un errore di segmentazione poiché stiamo cercando di modificare una stringa letterale (che è presente nella memoria di sola lettura)
Divyanshu Maithani,

10

In nessun caso è possibile modificare un valore letterale stringa, indipendentemente dal fatto che il puntatore a quel valore letterale stringa sia dichiarato come char *o const char *.

Tuttavia, la differenza è che se il puntatore è const char *allora il compilatore deve fornire una diagnostica se si tenta di modificare il valore puntato, ma se il puntatore è char *allora non lo è.


1
"In nessun caso puoi modificare una stringa letterale, indipendentemente dal fatto che ... [sia] dichiarato come char * o const char *" Sono d'accordo che il programmatore non dovrebbe provare, ma stai dicendo che ogni compilatore C, su ogni la piattaforma rifiuterà il codice, organizzerà il fallimento del codice in fase di esecuzione o qualcos'altro? Credo che un file potrebbe avere la definizione e l'inizializzazione e un altro file potrebbe contenere extern ... namee avere *name = 'X';. Sul "sistema operativo corretto", che potrebbe non funzionare, ma sui sistemi integrati, mi aspetto che faccia qualcosa di specifico per piattaforma / compilatore.
burrasca

@gbulmer: non è possibile modificare una stringa letterale in un programma C corretto. Ciò che può causare un programma C errato che tenta non è né qui né lì.
Caf

@gbulmer: una definizione utile è un programma che non rompe alcun vincolo specificato dallo standard del linguaggio C. In altre parole, un programma che modifica un valore letterale di stringa non è corretto allo stesso modo di uno che dereferenzia un puntatore nullo o esegue una divisione per 0 non è corretto.
Caf

caf - Pensavo potesse essere quello che volevi dire. Quindi "In nessun caso è possibile modificare una stringa letterale" sembra essere troppo affermandolo. Sarebbe corretto dire "In entrambi i casi i vincoli specificati dallo standard del linguaggio C sono stati rotti, indipendentemente .... Non è possibile per il compilatore o il sistema di runtime identificare le violazioni dello standard in tutti i casi." Presumo che lo standard prenda la posizione che l'effetto non è definito?
burrasca

1
Quando uno standard non può far valere nulla in entrambi i modi, penso che definire il comportamento come "indefinito" sembra essere esattamente il confine giusto e utile. Affermare la relazione che un "programma C corretto" " non può dereferenziare un puntatore nullo" equivale a provare il problema dell'arresto. Ma non mi dispiace. Non lo farei e non mi aspetto di scappare 'scott free' :-)
burrasca

4

CASO 1:

char *str = "Hello";
str[0] = 'M'  //Warning may be issued by compiler, and will cause segmentation fault upon running the programme

Quanto sopra imposta str per indicare il valore letterale "Hello", che è codificato nell'immagine binaria del programma, che è contrassegnato come di sola lettura in memoria, significa che qualsiasi cambiamento in questo valore letterale di stringa è illegale e ciò comporterebbe errori di segmentazione.

CASO 2:

const char *str = "Hello";
str[0] = 'M'  //Compile time error

CASO 3:

char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".

2

Il primo che puoi effettivamente cambiare se vuoi, il secondo che non puoi. Leggi sulla constcorrettezza (ci sono alcune belle guide sulla differenza). C'è anche char const * namedove non puoi reimpostarlo.


Cosa può cambiare esattamente?
Antti Haapala,

2

La domanda è qual è la differenza tra

char *name

che indica una stringa costante letterale e

const char *cname

Cioè dato

char *name = "foo";

e

const char *cname = "foo";

Non c'è molta differenza tra i 2 ed entrambi possono essere visti come corretti. A causa della lunga eredità del codice C, i letterali delle stringhe hanno avuto un tipo di char[], no const char[], e ci sono molti vecchi codici che accettano anche al char *posto di const char *, anche quando non modificano gli argomenti.

La principale differenza dei 2 in generale è che *cnameo cname[n]valuteranno valori di tipo const char, mentre *nameo name[n]valuteranno valori di tipo char, che sono valori modificabili . È richiesto un compilatore conforme per produrre un messaggio di diagnostica se la destinazione dell'assegnazione non è un valore modificabile ; non è necessario generare alcun avviso in caso di assegnazione a valori di tipo char:

name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message

Il compilatore non è tenuto a interrompere la compilazione in entrambi i casi; è sufficiente che produca un avviso per l'assegnazione a cname[0]. Il programma risultante non è un programma corretto . Il comportamento del costrutto non è definito . Potrebbe bloccarsi, o peggio ancora, potrebbe non arrestarsi e potrebbe modificare letteralmente la stringa in memoria.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.