Desreferenciar una ubicación de memoria desconocida : los programadores de C utilizan principalmente la función scanf() para recibir información, pero a veces un pequeño error puede generar un error o incluso bloquear todo el programa.
La sintaxis de scanf() es scanf(“%d”, &a); . Es posible que se pierda un & y escriba &a como un ahora scanf(“%d”, a); está desreferenciando a una ubicación desconocida.
Ahora, el programa puede terminar con una excepción o puede corresponder a una ubicación válida (no relacionada con el programa actual sino con algún otro programa) y puede sobrescribirse, lo que puede causar un efecto desconocido más adelante.
// A C program to demonstrate that missing // an & in scanf() may cause memory problems. #include <stdio.h> int main() { int a; scanf("%d", a); printf("%d", a); return 0; }
Lectura de una Memoria no inicializada. En C, los principiantes generalmente usan malloc() para proporcionar memoria de tiempo de ejecución, pero con malloc() el bloque de memoria no se inicializa y se puede acceder a .
// A C program to demonstrate that missing // an & may cause memory problems. #include <stdio.h> int main() { int* p = (int*)malloc(sizeof(int) * 4); int i; // p[] contains some garbage value so // below loop does not make any sense. for (i = 0; i < 4; i++) p[i] += 100; }
Una solución es usar calloc() en su lugar, que inicializa el bloque a 0.
Desbordamiento de búfer: este es un error muy común que ocurre en C y se vuelve aún más común debido a la presencia de una función defectuosa en C mismo, es decir, la función gets() que se usa para tomar una string como entrada. No verifica la memoria provista para almacenar la string en el programa, por lo que si un usuario ingresa una string de mayor tamaño, obtiene() con la ubicación de memoria de sobrescritura después de la string y causa un desbordamiento.
void read() { char str[20]; gets(str); printf("%s", str); return; }
El código sufre de desbordamiento de búfer ya que gets() no realiza ninguna prueba de límite de array. gets() sigue leyendo hasta que ve un carácter de nueva línea. Para evitar el desbordamiento del búfer, se debe usar fgets() en lugar de gets(), ya que fgets() se asegura de que no se lean más de MAX_LIMIT caracteres.
#define MAX_LIMIT 20 void read() { char str[MAX_LIMIT]; fgets(str, MAX_LIMIT, stdin); printf("%s", str); return; }
Fugas de memoria Esta situación surge cuando la memoria del montón utilizada no se desasigna debido a que la memoria principal finalmente se llena y la memoria libre se reduce.
/* Function with memory leak */ #include <stdlib.h> void f() { int* ptr = (int*)malloc(sizeof(int)); /* Do some work */ return; /* Return without freeing ptr*/ }
Deberíamos usar free() después de malloc() si la memoria ya no se usa.
/* Function without memory leak */ #include <stdlib.h> void f() { int* ptr = (int*)malloc(sizeof(int)); /* Do some work */ free(ptr); // Deallocate memory return; }
Error debido a la precedencia Una menor comprensión del operador y su precedencia puede producir un error, especialmente con punteros como
// C program to demonstrate bug introduced due // to precedence. #include <stdlib.h> int demo() { int a = 10; int* p = &a; // intention was to increase the value of a *p++; }
La precedencia de * (operador de desreferencia/indirección, no de multiplicación) y el postfijo ++ no son iguales, pero el prefijo ++ y * tienen el mismo y, por lo tanto, primero el valor de p aumentará y apuntará a un área de memoria incorrecta y luego la desreferencia y lo hará. sobrescribir esa ubicación o el programa puede terminar. Consulte Diferencia entre ++*p, *p++ y *++p para obtener más detalles.
Dirección de envío de una variable inexistente La dirección de retorno de una variable local causa problemas,
#include <stdlib.h> int fun() { int x = 10; return &x; } int main() { int* p = fun(); *p = 20; }
Cuando se llama a la función fun(), se crea la variable a, pero tan pronto como la función regresa, se destruye. Dado que se devuelve la función, su dirección p apuntará a un área de memoria en el área de la pila y si se llama a otra función, un cambio por parte del puntero p puede generar un error.
Aritmética de punteros La aritmética de punteros puede ser confusa. Tomemos un ejemplo, supongamos que el número entero es de 4 bytes.
int main() { int x[10] = { 0 }, i = 0, *p; // p point to starting address of array x p = &x[0]; while (i < 10) { *p = 10; // intention was to point to integer at x[1] p = p + 4; i++; } }
Aunque parece correcto, ya que el número entero es de 4 bytes y p está en la ubicación inicial, por lo que agregar 4 hará que p apunte al siguiente número entero en la array n, pero la aritmética del puntero funciona de acuerdo con el tamaño de su tipo de datos, por lo que agregar 1 a un puntero de Se le agregará un entero, luego se le agregará sizeof (int), lo mismo se aplica para el puntero a cualquier otro tipo de datos.
int main() { int x[10] = { 0 }, i = 0, *p; p = &x[0]; // p point to starting address of array x while (i < 10) { *p = 10; p++; // means p = p + sizeof(int) i++; } }
Pasar una array como parámetro Cuando pasamos una array a una función, siempre se trata como un puntero en la función. Es por eso que nunca debemos usar sizeof en el parámetro de array. Preferiríamos pasar siempre el tamaño como segundo parámetro.
#include <stdio.h> // arr is a pointer even if we have // use square brackets. void printArray(int arr[]) { int i; /* sizeof should not be used here to get number of elements in array*/ int arr_size = sizeof(arr) / sizeof(arr[0]); for (i = 0; i < arr_size; i++) { printf("%d ", arr[i]); } } int main() { int arr[4] = { 1, 2, 3, 4 }; printArray(arr); return 0; }
A continuación se muestra el código corregido
#include <stdio.h> // arr is a pointer even if we have // use square brackets. void printArray(int arr[], int arr_size) { int i; for (i = 0; i < arr_size; i++) { printf("%d ", arr[i]); } } int main() { int arr[] = { 1, 2, 3, 4 }; int arr_size = sizeof(arr) / sizeof(arr[0]); printArray(arr, arr_size); return 0; }
Referencia:
Sistemas informáticos: la perspectiva de un programador