c - dumped - segmentation fault raspberry pi
Accidente o "falla de segmentación" cuando los datos se copian/escanean/leen a un puntero no inicializado (5)
Esta pregunta está destinada a ser utilizada como referencia para todas las preguntas frecuentes de la naturaleza:
¿Por qué obtengo una falla misteriosa o "falla de segmentación" cuando copio / escaneo datos a la dirección a la que apunta un puntero no inicializado?
Por ejemplo:
char* ptr;
strcpy(ptr, "hello world"); // crash here!
o
char* ptr;
scanf("%s", ptr); // crash here!
-
Los punteros solo apuntan a una ubicación de memoria. Creó un puntero pero aún no se unió a una ubicación de memoria.
strcpy
quiere que pases dos punteros (el primero no debe ser constante ) que apunten a dos matrices de caracteres como esta firma:char * strcpy ( char * destination, const char * source );
uso de muestra:
char* ptr = malloc(32); strcpy(ptr, "hello world");
char str[32]; strcpy(str, "hello world");
-
Puede probar el siguiente fragmento de código para leer la cadena hasta llegar al carácter de nueva línea (* también puede agregar otros caracteres de espacio en blanco como
"%[^/t/n]s"
( tab, nueva línea ) o"%[^ /t/n]s"
( espacio, tabulación, nueva línea )).char *ptr = malloc(32); scanf("%31[^/n]", ptr);
(¡En la vida real, no olvides comprobar el valor de retorno de
scanf()
!)
Esto sucede porque no ha
asignado
memoria para el
puntero
char* ptr
.
En este caso, debe
asignar dinámicamente
memoria para el puntero.
Se pueden usar dos funciones
malloc()
y
calloc()
para
dynamic memory allocation
.
Prueba este código: -
char* ptr;
ptr = malloc(50); // allocate space for 50 characters.
strcpy(ptr, "hello world");
Cuando el uso de
*ptr
over no olvide
desasignar la memoria
asignada para
*ptr
. Esto se puede hacer usando
free()
función
free()
.
free(ptr); // deallocating memory.
El tamaño de
la memoria asignada dinámicamente
se puede cambiar usando
realloc()
.
char *tmp = realloc(ptr, 100); // allocate space for 100 characters.
if (! tmp) {
// reallocation failed, ptr not freed
perror("Resize failed");
exit(1);
}
else {
// reallocation succeeded, old ptr freed
ptr = tmp;
}
En la mayoría de los casos, se produce un "error de segmentación" debido a un error en la asignación de memoria o una matriz fuera de los casos vinculados .
No es este el caso, pero una situación que ocurre con frecuencia al principio es cuando se utilizan comillas simples y se intenta definir un literal de cadena como:
char ptr[5];
strcpy(ptr, ''hello''); // crash here!
^ ^ // because of '' instead "
En C ''h'' es un literal de un solo carácter, mientras que "h" es un literal de cadena que contiene una ''h'' y un terminador nulo / 0 (que es una matriz de 2 caracteres). Además, en C, el tipo de literal de caracteres es, es decir, sizeof ''h'' es 4 (en 32 bits), mientras que sizeof (char) es 1.
char h = ''h'';
printf("Size: %d/n",sizeof(h)); //Size: 1
printf("Size: %d/n",sizeof(''h'')); //Size: 4
Para hacer una copia modificable de una cadena, en lugar de usar
malloc
,
strlen
y
strcpy
, la biblioteca POSIX C tiene una función práctica llamada
strdup
en
<string.h>
que devolverá una copia de la cadena terminada en nulo pasada con asignación asignada duración del almacenamiento
Después de usar el puntero se debe liberar con
free
:
char* ptr;
ptr = strdup("hello world");
ptr[0] = ''H'';
puts(ptr);
free(ptr);
Un puntero es un tipo especial de variable, que solo puede contener una dirección de otra variable. No puede contener ningún dato. No puede "copiar / almacenar datos en un puntero", eso no tiene ningún sentido. Solo puede establecer un puntero para apuntar a los datos asignados en otro lugar.
Esto significa que para que un puntero sea significativo, siempre debe apuntar a una ubicación de memoria válida. Por ejemplo, podría apuntar a la memoria asignada en la pila:
{
int data = 0;
int* ptr = &data;
...
}
O memoria asignada dinámicamente en el montón:
int* ptr = malloc(sizeof(int));
Siempre es un error utilizar un puntero antes de que se haya inicializado. Todavía no apunta a una memoria válida.
Todos estos ejemplos podrían conducir a bloqueos del programa u otros tipos de comportamiento inesperado, como "fallas de segmentación":
/*** examples of incorrect use of pointers ***/
// 1.
int* bad;
*bad = 42;
// 2.
char* bad;
strcpy(bad, "hello");
En su lugar, debe asegurarse de que el puntero apunta a (suficiente) memoria asignada:
/*** examples of correct use of pointers ***/
// 1.
int var;
int* good = &var;
*good = 42;
// 2.
char* good = malloc(5 + 1); // allocates memory for 5 characters *and* the null terminator
strcpy(good, "hello");
Tenga en cuenta que también puede establecer un puntero para que apunte a un "lugar" bien definido, dejándolo apuntar a
NULL
.
Esto lo convierte en un
puntero nulo
, que es un puntero que se garantiza que no apuntará a ninguna memoria válida.
Esto es diferente de dejar el puntero completamente sin inicializar.
int* p1 = NULL; // pointer to nowhere
int* p2; // uninitialized pointer, pointer to "anywhere", cannot be used yet
Sin embargo, si intenta acceder a la memoria apuntada por un puntero nulo, puede obtener problemas similares a los que se producen al usar un puntero no inicializado: bloqueos o fallas de segmentación. En el mejor de los casos, su sistema se da cuenta de que está intentando acceder a la dirección nula y luego lanza una "excepción de puntero nulo".
La solución para los errores de excepción de puntero nulo es la misma: debe configurar el puntero para que apunte a la memoria válida antes de usarlo.
Otras lecturas:
Punteros apuntando a datos no válidos
¿Cómo acceder a una variable local desde una función diferente usando punteros?
¿Se puede acceder a la memoria de una variable local fuera de su alcance?
Falla de segmentación y causas
¿Qué es una falla de segmentación?
¿Por qué aparece un error de segmentación al escribir en una cadena inicializada con "char * s" pero no "char s []"?
¿Cuál es la diferencia entre char s [] y char * s?
Lista definitiva de razones comunes para fallas de segmentación
¿Qué es un error de bus?