Cosa causa l'arresto anomalo di questa riassegnazione del puntatore intero?

StackOverflow https://stackoverflow.com/questions/207800

  •  03-07-2019
  •  | 
  •  

Domanda

Sono nuovo di C e ho questa domanda. perché il codice seguente si arresta in modo anomalo:

int *a = 10;
*a = 100;
È stato utile?

Soluzione

Perché stai cercando di scrivere 100 nella posizione di memoria 0x0000000A che probabilmente non è allocata al tuo programma. Cioè,

int *a = 10;

non significa che il puntatore 'a' indicherà una posizione nella memoria con il valore di 10. Significa che punta all'indirizzo 10 (0x0000000A) nella memoria. Quindi, vuoi scrivere qualcosa in quell'indirizzo, ma non hai i "diritti" per fare ciò, poiché non è allocato

Puoi provare quanto segue:

int *a = malloc(sizeof(int));
*a = 100;

Funzionerebbe, sebbene orribilmente inefficiente. Se hai solo bisogno di un singolo int, dovresti semplicemente inserirlo nello stack, non nell'heap . Su un'architettura a 32 bit, un puntatore è lungo 32 bit e anche un int è lungo 32 bit, quindi la struttura del puntatore a un int prende ( almeno ) 8 byte di spazio di memoria in questo modo anziché 4. E non abbiamo nemmeno menzionato problemi di memorizzazione nella cache.

Altri suggerimenti

Devi assegnare il puntatore a una posizione di memoria , non a un valore arbitrario (10).

int cell = 10;
int *a = &cell; // a points to address of cell
*a = 100;       // content of cell changed

Vedi la mia risposta ad un altro domanda sull'attenzione a C .

Vorrei proporre una leggera modifica nell'uso di malloc (), per tutte le risposte che suggeriscono di usarlo per allocare memoria per l'int. Invece di:

a = malloc(sizeof(int));

Suggerirei di non ripetere il tipo di variabile, poiché questo è noto al compilatore e ripeterlo manualmente rende il codice più denso e introduce un rischio di errore. Se successivamente cambi la dichiarazione in ad esempio

long *a;

Senza modificare l'allocazione, si finirà per allocare una quantità errata di memoria (nel caso generale, su macchine a 32 bit int e long sono spesso uguali taglia). È meglio usare IMO:

a = malloc(sizeof *a);

Questo significa semplicemente " la dimensione del tipo indicato da un " ;, in questo caso int , che ovviamente è esattamente giusto. Se si modifica il tipo nella dichiarazione come sopra, questa riga è ancora corretta. Esiste ancora un rischio, se si modifica il nome della variabile sul lato sinistro del compito, ma almeno non si ripetono più le informazioni inutilmente.

Nota anche che non è necessaria alcuna parentesi con sizeof quando la usi su oggetti reali (cioè variabili), solo con nomi di tipi, che sembrano espressioni di cast. sizeof non è una funzione, è un operatore.

Perché non hai mai assegnato memoria per a. Hai appena assegnato dello spazio di stack per un puntatore a.

int *a = NULL;

a = malloc (sizeof (int));

if (a != NULL)
{
*a =10;
}

Funzionerà.

In alternativa potresti fornire l'indirizzo di qualche variabile esistente, che funzionerebbe anche.

cioè.

int a* = NULL;
int b = 10;

a = &b;

Ciò significa che fare qualcosa del genere

*a = 100;

imposterà anche b su == 100

Dai un'occhiata a questo: http://home.netcom.com/~tjensen/ptr/pointers.pdf

La seguente riga,

int *a = 10;

definisce un puntatore a un numero intero a . Quindi punta il puntatore a nella posizione di memoria 10.

La riga successiva,

*a = 100;

Mette il valore 100 nella posizione di memoria indicata da a.

Il problema è:

  1. Non sai dove puntare. (Non conosci il valore della posizione di memoria 10)
  2. Ovunque sia indicato, probabilmente non hai alcun diritto a modificare quel valore. Probabilmente è la memoria di qualche altro programma / processo. Ladro!

Poiché si dichiara un puntatore a int, inizializzare il puntatore su 10 (un indirizzo) e quindi provare ad assegnare un valore a un int a questo indirizzo. Poiché la memoria all'indirizzo 10 non appartiene al processo, si verifica un arresto anomalo. Questo dovrebbe funzionare:

int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);

Questo codice viene nemmeno compilato? 10 non è convertibile in un int * , a meno che non lo lanci in questo modo:

int *a = (int *) 10;
*a = 100;

In tal caso, stai provando a scrivere 100 nell'indirizzo di memoria a 10. Di solito questo non è un indirizzo di memoria valido, quindi il tuo programma si arresta in modo anomalo.

Probabilmente si sta bloccando perché stai assegnando il puntatore a una parte della memoria a cui non hai accesso e quindi stai assegnando un valore a quella posizione di memoria (cosa che non ti è permesso fare!).

Puoi anche scriverlo come:

int* a = 10;
*a = 100;

Nota la diversa spaziatura sulla prima riga. Non è uno stile popolare, ma personalmente penso che sia più chiaro. Ha esattamente lo stesso significato per il compilatore.

Quindi, leggilo ad alta voce:

"Pointer-to-int 'a' becomes 10"
"Value-pointed-to-by 'a' becomes 100"

Sostituzione del valore effettivo:

"Value-pointed-to-by 10 becomes 100"

... in cui ti rendi conto che è improbabile che 10 indichi un pezzo di memoria che puoi usare.

Praticamente non assegneresti mai a un puntatore con un valore letterale:

int* ptr = (int*)10;  // You've guessed at a memory address, and probably got it wrong
int* ptr = malloc(sizeof(int)); // OS gives you a memory address at runtime  

Suppongo che ci potrebbero essere alcuni lavori molto di basso livello in cui si specificano direttamente indirizzi di memoria assoluti. Implementazione del kernel, ad esempio?

Va ??bene, oggi cerco di dare la spiegazione più semplice, mentre provo a darti un'immagine più dettagliata di tutto. Aggiungiamo alcune parentesi, vero?

(int*) a = 10;
(*a) = 100;

Si tenta di scrivere quattro byte nell'intervallo di indirizzi [10-13]. Il layout di memoria del programma inizia di solito più in alto, quindi l'applicazione non sovrascrive accidentalmente nulla da dove potrebbe e continua a funzionare (ad esempio da .data, .bss e stack). Quindi finisce per bloccarsi invece, perché l'intervallo di indirizzi non è stato assegnato.

Il puntatore punta a una posizione di memoria e la tipizzazione statica C definisce un tipo per un puntatore. Sebbene sia possibile ignorare facilmente il puntatore. Semplicemente:

(void*) v = NULL;

Qui andiamo oltre alle cose. Che cos'è un puntatore null? È semplicemente un puntatore che punta all'indirizzo 0.

Puoi anche dare un tipo di struttura per il tuo puntatore:

struct Hello {
    int id;
    char* name;
};

...

struct Hello* hello_ptr = malloc(sizeof Hello);
hello_ptr->id = 5;
hello_ptr->name = "Cheery";

Ok, cos'è malloc? Malloc alloca la memoria e restituisce un puntatore alla memoria allocata. Ha una firma del tipo seguente:

void* malloc(size_t size);

Se non si dispone di un garbage collector conservativo, è probabile che la memoria non venga liberata automaticamente. Pertanto, se si desidera ripristinare la memoria da ciò che è stato appena allocato, è necessario:

free(hello_ptr);

Ogni malloc che fai contiene un tag size, quindi non è necessario indicare la dimensione del blocco che hai indicato per la routine gratuita.

Ok, eppure una cosa, come appare una stringa di caratteri in memoria? Quello simile a " allegro " per esempio. Semplice risposta. È un array di byte a terminazione zero.

0.1.2.3.4.5. 6
C h e e r y \0
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top