C Confusione del puntatore
-
19-08-2019 - |
Domanda
Voglio archiviare una stringa in memoria e leggerla in seguito:
$->desc.constant->base.id = (char*)malloc(200);
sprintf($->desc.constant->base.id, "%f", $1);
printf("->%s\n", $->desc.constant->base.id); //LINE A
printf("->%i\n", $->desc.constant); //LINE B
//SOME OTHER CODE
//Then, later on in a function call:
printf("%i", expr->desc.constant); // LINE D
printf("%s", expr->desc.constant->base.id); // LINE C
Sebbene la riga B e la riga D mostrino lo stesso indirizzo, la stampa nella riga C non riesce con un errore di segmentazione. Cosa mi sto perdendo?
Qualsiasi aiuto sarebbe davvero apprezzato!
Soluzione
printf("->%i\n", $->desc.constant); //LINE B
Non è valido. Mentre mostri alla riga precedente che costante
è in realtà un puntatore, non puoi trattarlo come se fosse di tipo int
. Non hanno necessariamente la stessa dimensione e allineamento. Utilizza il formato utilizzato per void *
. Produrrà correttamente gli indirizzi di memoria:
printf("->%p\n", (void*)$->desc.constant); //LINE B
Altri suggerimenti
- sempre controlla il valore di ritorno di
malloc
. -
sprintf
- >snprintf
-
"% f "
- >".% * G "
Ecco un esempio:
/** $ gcc print_number.c -o print_number */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
const char* number_format = "%.*g";
const int ndigits = 15;
assert(ndigits > 0);
const int maxlen = ndigits + 8 /* -0.e+001, Infinity */ + 1 /* '\0' */;
char *str = malloc(maxlen);
if (str == NULL) {
fprintf(stderr, "error: malloc\n");
exit(1);
}
double number = 12345678901234567890.123456789012345678901234567890;
/** `number = 0/0` crashes the program */;
printf("number: %f\t", number);
int len_wouldbe = snprintf(str, maxlen, number_format, ndigits, number);
assert(len_wouldbe < maxlen);
printf("%s\n", str);
return 0;
}
Output:
number: 12345678901234567000.000000 1.23456789012346e+19
Forse tra il tempo dei due pezzi di codice che hai dalla libera
alla stringa?
$->desc.constant->base.id = (char*)malloc(200);
sprintf($->desc.constant->base.id, "%f", $1);
printf("->%s\n", $->desc.constant->base.id); //LINE A
printf("->%i\n", $->desc.constant); //LINE B
//SOME OTHER CODE
// which happens to do
free($->desc.constant->base.id);
printf("%i", expr->desc.constant); // LINE D
printf("%s", expr->desc.constant->base.id); // crash
Dato che il programma sta producendo un errore di segmentazione, penso che il problema sia molto probabile che la struttura designata (indicata da expr- > desc.constant
sia stata riutilizzata da quando lo spazio era allocato, o forse lo spazio non è mai stato realmente assegnato affatto.
Il codice mostra vari peccati veniali, come l'uso di sprintf ()
invece di snprintf ()
e l'allocazione gratuita di 200 byte per la rappresentazione in stringa di un numero in virgola mobile . (È molto improbabile che tu abbia bisogno di così tanto spazio; in tal caso, molto probabilmente dovresti consentire almeno 100 cifre in più rispetto a te, poiché l'intervallo di esponenti per i numeri in virgola mobile è di solito +/- 308 e l'unica ragione per cui occorrerebbero 200 caratteri per consentire numeri incredibilmente grandi o incredibilmente piccoli.)
Hai dimostrato che $$ - > desc.constant
punta allo stesso posto, ma non hai mostrato come è assegnato tale spazio. Quindi alloca lo spazio delle stringhe in $$ - > desc.constant- > base.id
, senza allocare chiaramente lo spazio per base
.