C Confusión de puntero
-
19-08-2019 - |
Pregunta
Quiero almacenar una cadena en la memoria y leerla más tarde:
$->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
Aunque la línea B y la línea D muestran la misma dirección, el printf en la línea C falla con una falla de segmentación. ¿Qué me estoy perdiendo?
¡Cualquier ayuda sería realmente apreciada!
Solución
printf("->%i\n", $->desc.constant); //LINE B
Eso no es válido. A medida que muestra la línea anterior a ella que constante
es en realidad un puntero, no puede tratarla como si fuera del tipo int
. No necesariamente tienen el mismo tamaño y alineación. Use el formato utilizado para void *
. Producirá direcciones de memoria correctamente:
printf("->%p\n", (void*)$->desc.constant); //LINE B
Otros consejos
- siempre verifique el valor de retorno de
malloc
. -
sprintf
- >snprintf
-
"% f "
- >"%.*g"
Aquí hay un ejemplo:
/** $ 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;
}
Salida:
number: 12345678901234567000.000000 1.23456789012346e+19
¿Quizás entre el tiempo de las dos piezas de código que tiene desde free
d la cadena?
$->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
Dado que el programa está produciendo una falla de segmentación, creo que el problema es más probable que la estructura designada (señalada) por expr- > desc.constant
se haya reutilizado desde que el espacio fue asignado, o posiblemente el espacio nunca fue realmente asignado en absoluto.
El código exhibe varios pecados veniales, como usar sprintf ()
en lugar de snprintf ()
, y asignar gratuitamente 200 bytes para la representación de cadena de un número de coma flotante . (Es muy poco probable que necesite tanto espacio; si lo hace, probablemente debería permitir al menos 100 dígitos más de los que tiene, ya que el rango de exponente para números de coma flotante es generalmente +/- 308, y la única razón por la que Necesitaría 200 caracteres para permitir números increíblemente grandes o increíblemente pequeños).
Ha demostrado que $$ - > desc.constant
apunta al mismo lugar, pero no ha mostrado cómo se asigna ese espacio. Luego asigna el espacio de cadena en $$ - > desc.constant- > base.id
, sin asignar claramente el espacio para base
.