2015-07-21 9 views
5

Ho cercato attraverso il sito ma non ho ancora trovato una risposta a questo.In C, perché non è possibile assegnare un valore intero a un int * nello stesso modo in cui un valore stringa può essere assegnato a un char *?

È più facile (almeno per me) spiegare questa domanda con un esempio.

Non capisco perché questo è valido:

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    char *mystr = "hello"; 
} 

Ma questo produce un compilatore di avviso ("l'inizializzazione rende puntatore da interi senza un cast"):

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    int *myint = 5; 
} 

mia comprensione di il primo programma è quello che crea una variabile chiamata mystr di tipo pointer-to-char, il cui valore è l'indirizzo del primo carattere ('h') della stringa letterale "ciao". In altre parole con questa inizializzazione non si ottiene solo il puntatore, ma si definisce anche l'oggetto ("ciao" in questo caso) a cui punta il puntatore.

Perché, quindi, non sembra che int *myint = 5; ottenga qualcosa di analogo a questo, cioè creare una variabile denominata myint di tipo pointer-to-int, il cui valore è l'indirizzo del valore '5'? Perché questa inizializzazione non mi dà il puntatore e definisce anche l'oggetto a cui punta il puntatore?

+2

Penso che una domanda più equivalente sarebbe "perché non posso' int * myint = & 5; '?" – chux

+0

Il letterale stringa valuta il puntatore e il valore letterale numerico viene valutato sul numero stesso. –

risposta

8

In effetti, è possibile farlo utilizzando un composto letterale, una funzionalità aggiunta alla lingua dallo standard ISO C 1999.

Una stringa letterale è di tipo char[N], dove N è la lunghezza della stringa più 1. Come qualsiasi espressione matrice, è implicitamente convertito, nella maggior parte, ma non tutti i contesti, ad un puntatore al primo elemento dell'array. Quindi questo:

char *mystr = "hello"; 

assegna al puntatore mystr l'indirizzo del primo elemento di una matrice i cui contenuti sono "hello" (seguita da una terminazione '\0' carattere nullo). Per inciso, è più sicuro di scrivere:

const char *mystr = "hello"; 

Non ci sono tali conversioni implicite per gli interi - ma si può fare questo:

int *ptr = &(int){42}; 

(int){42} è un composto letterale, che crea un int oggetto anonimo inizializzato a 42; & prende l'indirizzo di quell'oggetto.

Ma attenzione: L'array creato da una stringa letterale sempre ha durata di conservazione statica, ma l'oggetto creato da un letterale composto può avere o durata di conservazione statica o automatica, a seconda di dove appare. Ciò significa che se il valore di ptr viene restituito da una funzione, l'oggetto con il valore 42 cesserà di esistere mentre il puntatore continua a puntare su di esso.

quanto riguarda:

int *myint = 5; 

che tenta di assegnare il valore 5 ad un oggetto di tipo int*. (A rigor di termini è un'inizializzazione piuttosto che un compito, ma l'effetto è lo stesso). Poiché non c'è alcuna conversione implicita da int a int* (diverso dal caso speciale di 0 considerato come costante di puntatore nullo), questo non è valido.

+1

Esiste un metodo corrente o proposto per dichiarare che un valore letterale costante deve avere una durata statica [ad es. qualcosa come '& (static int) {42};']? Dato che un valore letterale stringa "Foo" è essenziale equivalente a un char statico issato [4] __string24601 = {'F', 'o', 'o', 0}; 'seguito da un riferimento a' __string24601', compilatori dovrebbe già avere un meccanismo per fornire tale comportamento. – supercat

+0

L'unica cosa che si dimentica è che è valido assegnare un indirizzo (non '5' ovviamente) a un puntatore. che viene utilizzato molto con sistemi incorporati in cui vengono comunemente utilizzate risorse mappate in memoria. –

+0

@TomerW: valido in che senso? L'assegnazione di un valore intero diverso da una costante puntatore nullo su un oggetto puntatore è una violazione del vincolo. È possibile assegnare il risultato della conversione di tale valore a un tipo di puntatore; è solo assegnando un puntatore a un puntatore. (Alcuni compilatori non rispettano le assegnazioni da intero a puntatore. Se non lo mettono in guardia, non sono compilatori C conformi.) –

-2

Il problema è che si sta tentando di assegnare l'indirizzo 5 al puntatore. Qui non stai dereferenziando il puntatore, lo stai dichiarando come puntatore e inizializzandolo sul valore 5 (come un indirizzo che sicuramente non è quello che intendi fare). Potresti fare quanto segue

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    int *myint, b; 
    b = 5; 
    myint = &b; 
} 
+0

In primo luogo, hai scritto 0x5 in un indirizzo che non conosci ... così GRANDE NO-NO. Secondo, a volte lanci un uint32 su un ptr –

+0

Il mio male, lo fisso. Preferirei dineferenziare piuttosto che assegnarlo all'indirizzo di b. – Dan

-2

Il primo programma sta effettivamente creando un puntatore a una stringa che è una matrice di caratteri. In questo caso, l'array sarebbe in realtà un puntatore. Nel tuo secondo programma stai assegnando un valore intero scalare a un puntatore.

Si dovrebbe provare questo invece:

int main(int argc, char* argv[]) 
{ 
    int temp = 5; 
    int * my_int_pointer = &temp; 
} 
+1

"* In questo caso, l'array sarebbe effettivamente un puntatore *" - No, gli array non sono puntatori. Leggi la sezione 6 delle [domande frequenti su comp.lang.c (http://www.c-faq.com/). –

+0

Hai ragione nel caso generale che gli array non sono puntatori. In questo caso l'array agisce come un puntatore quando viene assegnato a mystr. – phox

+1

@phox no, non agisce come un puntatore. agisce come un array, ed è per questo che può essere convertito implicitamente in un puntatore. –

0

Quando si esegue char* mystr = "foo";, il compilatore creerà la stringa "foo" in una speciale porzione di sola lettura del tuo eseguibile, e riscrivere in modo efficace l'istruzione come char* mystr = address_of_that_string;

Lo stesso non è implementato per nessun altro tipo, inclusi interi. int* myint = 5; imposterà myint in modo che punti all'indirizzo 5.

0

sarò diviso la mia risposta a due parti:

1st, perché char* str = "hello"; vale:

char* str dichiarano uno spazio per un puntatore (numero che rappresenta un indirizzo di memoria sull'architettura corrente)

quando si scrive "hello" effettivamente riempire lo stack con 6 byte di dati
(non dimenticate la terminazione null) Diciamo all'indirizzo 0x1000 - 0x1005.

str="hello" assegna l'indirizzo iniziale di tale 5 byte (0x1000) al *str

quindi ciò che abbiamo è:
1. str, che prende 4 byte in memoria, contiene il numero 0x1000 (punti ! solo il primo carattere)
2. 6 byte 'h' 'e' 'l' 'l' 'o' '\ 0'

2 °, perché int* ptr = 0x105A4DD9; non è valida:

beh, questo non è completamente vero!
come detto prima, un puntatore è un numero che rappresenta un indirizzo,
quindi perché non posso assegnare quel numero?

non è comune perché per lo più si estraggono gli indirizzi di dati e non si immette l'indirizzo manualmente.
ma è possibile se avete bisogno !!! ...
perché non è qualcosa che viene comunemente fatto,
il compilatore vuole fare in modo di farlo in proponete, e non per errore e ti costringe a lanciare la vostra dati
int* ptr = (int*)0x105A4DD9;
(usato principalmente per la memoria mappata risorse hardware)

Spero che questo chiarisca le cose.
Cheers

0

"In C, perché non è possibile assegnare un valore intero a un int * nello stesso modo in cui un valore stringa può essere assegnato a un carattere *?"

Perché è nemmeno una situazione simile, e tanto meno "allo stesso modo".

Una stringa letterale è una matrice di char s che - essendo un array - può essere convertita implicitamente in un puntatore al suo primo elemento. Detto puntatore è un char *.

Ma uno int non è né un puntatore in sé, né un array, né qualsiasi altra cosa implicitamente convertibile in un puntatore. Questi due scenari solo non hanno nulla in comune.

+0

Sì, non ero a conoscenza del concetto di conversione implicita - così è stato fuorviato dalla somiglianza sintattica tra i due casi. Grazie per l'aiuto. – sav0h

Problemi correlati