Regla 0x7005h: Inicializá todos los campos de estructuras y arreglos
Robustez y manejo de errores (0x70XX)
0x7005h: Inicializá todos los campos de estructuras y arreglos¶
Enunciado normativo¶
Toda variable de tipo
struct,uniono arreglo DEBE inicializarse completamente antes de leerse. Si no se conoce el valor de todos los campos, DEBE inicializarse a cero con{0}(o con un inicializador explícito), y NO DEBE dejarse ningún miembro indeterminado.
¿Por qué existe esta regla?¶
El problema¶
En C, una variable local de tipo agregado no se inicializa automáticamente: sus campos contienen basura de la pila. Si se asignan algunos campos y se lee un campo olvidado, el programa usa un valor impredecible. El bug es intermitente y depende del estado previo de la pila, lo que lo hace extremadamente difícil de reproducir.
La inicialización completa elimina esa clase entera de errores y es barata: una línea.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Bug no reproducible | Un campo no asignado a veces vale 0 y a veces basura. |
| Comportamiento indefinido | Un puntero no inicializado se desreferencia. |
| Propagación | La basura se copia a otras estructuras y viaja por el programa. |
| Seguridad | Fugas de información por campos no inicializados. |
Fundamento en el estándar C11¶
ISO/IEC 9899:2011 §6.7.9 permite el inicializador {0} que pone en cero
todos los miembros. Para objetos con duración automática sin inicializador,
el valor es indeterminado (§6.2.4). La cátedra complementa 0x7001h: Siempre debés inicializar las variables a un valor conocido
(variables escalares) con esta regla para agregados.
Alcance y excepciones¶
Aplica a struct, union y arreglos locales. En arreglos que se llenan
completamente en un lazo inmediato, la inicialización previa puede omitirse
sólo si el lazo cubre todos los elementos y se documenta. Las variables
globales se inicializan a cero por el estándar, pero la cátedra prohíbe
globales (0x2004h: No se permite el uso de variables globales).
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Struct parcialmente inicializada¶
typedef struct {
int x;
int y;
bool activo;
} punto_t;
punto_t p;
p.x = 10;
p.y = 20;
/* p.activo sin inicializar */
if (p.activo) {
dibujar(&p);
}Por qué falla: p.activo contiene basura; el if puede ser verdadero o
falso de forma impredecible entre ejecuciones.
❌ Contraejemplo 2 — Arreglo parcial¶
int v[10];
v[0] = 1;
v[1] = 2;
/* se usan v[2]..v[9] mas adelante */Por qué falla: los elementos no asignados tienen valores indeterminados y se propagan a los cálculos.
✅ Ejemplo conforme 1 — Inicialización completa¶
punto_t p = {0};
p.x = 10;
p.y = 20;
p.activo = true;{0} garantiza que cualquier campo no mencionado sea cero/falso antes de
asignar los conocidos.
✅ Ejemplo conforme 2 — Inicializador explícito¶
punto_t p = { .x = 10, .y = 20, .activo = true };
int v[10] = {0};Los inicializadores designados asignan cada campo por nombre y {0} limpia
el arreglo completo de una vez.
⚠️ Casos límite¶
union: inicializar sólo un miembro es correcto, pero debe leerse sólo ese miembro;{0}inicializa el primero.Arreglo llenado por completo: si un lazo escribe todos los elementos antes de cualquier lectura, la inicialización previa es redundante; se admite con comentario.
memset:{0}es preferible para inicializar en la declaración; si se usamemset, cuidar el orden de argumentos (0x3016h: Orden incorrecto o sospechoso de argumentos en llamadas a memset).
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
valgrind | valgrind ./programa | “Conditional jump depends on uninitialised value”. |
gcc | gcc -Wall -Wextra | -Wmaybe-uninitialized en algunos casos. |
cppcheck | cppcheck archivo.c | Miembros no inicializados. |
Checklist de autocontrol¶
¿Toda struct se inicializa completa antes de leerse?
¿Usé
{0}o inicializadores designados?¿Algún campo quedó sin asignar?
¿Valgrind reporta valores no inicializados?
Reglas relacionadas¶
0x7001h: Siempre debés inicializar las variables a un valor conocido — inicialización de variables escalares.
0x3018h: Inicialización idiomática de agregados con {0} en lugar de memset inmediato — inicialización idiomática con
{0}.0x3016h: Orden incorrecto o sospechoso de argumentos en llamadas a memset — argumentos de
memset.0x2004h: No se permite el uso de variables globales — prohibición de variables globales.