Regla 0x2010h: Prohibición de reasignar o modificar parámetros recibidos por valor dentro de la función
Funciones, contratos y modularizacion (0x20XX)
0x2010h: Prohibición de reasignar o modificar parámetros recibidos por valor dentro de la función¶
Enunciado normativo¶
NO DEBEN reasignarse ni incrementarse los parámetros recibidos por valor. Cuando se necesite un valor mutable, DEBE copiarse el parámetro a una variable local explícita antes de modificarla.
¿Por qué existe esta regla?¶
El problema¶
Un parámetro por valor es, para el llamador, un dato de entrada: su función
promete no tocarlo. Que C lo reciba como copia modificable es un detalle de
implementación, no una invitación a usarlo de acumulador. Si hacés n-- o
limite = 0, el contrato se rompe: parece que el argumento cambió aunque no sea
así. Copiar a una local con nombre propio separa el dato original del cálculo.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Contrato confuso | El lector cree que la función modifica el argumento del llamador. |
| Bug de reutilización | Tras modificar el parámetro ya no se puede consultar el valor original. |
| Recursión | Reasignar el parámetro altera la llamada recursiva de forma sutil. |
Fundamento en el estándar y en la cátedra¶
En C11 los parámetros tienen duración automática y son modificables dentro de la función (§6.9.1 párrafo 9). La norma permite mutarlos; el problema es de contrato y legibilidad, no de comportamiento indefinido. La cátedra exige la copia a local para que la firma sea una promesa estable, en armonía con 0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique y 0x7001h: Siempre debés inicializar las variables a un valor conocido. Si el parámetro debe modificarse, se pasa un puntero.
Alcance y excepciones¶
Cubre parámetros escalares (enteros, flotantes, punteros) recibidos por valor.
No se aplica a parámetros por referencia simulada con punteros: ahí modificar
*p es el propósito de la función y debe documentarse.
Excepción razonable: en una función recursiva, reasignar el parámetro antes
de la llamada recursiva es un patrón común (n = n - 1;), pero la cátedra
prefiere pasar la expresión directamente (recursiva(n - 1)) o copiar a una
local. La recursión sin caso base que describe 0x2017h: Toda funcion recursiva debe tener un caso base explicito suele venir
acompañada de este descuido.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Parámetro como acumulador¶
int calcular(int limite)
{
while (limite > 0) {
limite--;
}
return limite;
}Por qué falla: limite deja de ser el dato de entrada y pasa a ser el
acumulador. Al terminar, vale 0 siempre, y el valor original se perdió. Un
lector que ve la firma no espera que la función consuma su parámetro.
❌ Contraejemplo 2 — Reasignación que oculta un error¶
int sumar_hasta(int n)
{
int suma = 0;
for (n = 1; n <= 10; n++) {
suma += n;
}
return suma;
}Por qué falla: n se reasigna en la inicialización del for y el parámetro
recibido nunca se usa. La función ignora su entrada y devuelve siempre 55;
reescribir el parámetro disimula que el argumento es irrelevante.
✅ Ejemplo conforme 1 — Copia a variable local¶
int restar_hasta_cero(int limite)
{
int restante = limite;
while (restante > 0) {
restante--;
}
return restante;
}limite conserva su valor de entrada y restante es explícitamente el
acumulador. La firma se sostiene: la función no modifica lo que recibe.
✅ Ejemplo conforme 2 — Pasar la expresión en la recursión¶
static int sumar_hasta(int n)
{
if (n <= 0) {
return 0;
}
return n + sumar_hasta(n - 1);
}La recursión avanza con n - 1 sin reasignar n. El parámetro permanece
intacto durante toda la invocación y el caso base corta la cadena, evitando el
desborde de pila que documenta 0x2017h: Toda funcion recursiva debe tener un caso base explicito.
⚠️ Casos límite¶
Recursión mutua: además de no reasignar, cada función del ciclo debe tener su caso base; sin él, el agotamiento de pila es inmediato.
consten parámetros: marcarconst int ndocumenta la intención y hace que el compilador rechace la reasignación (0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique).
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gcc / clang | gcc -Wall -Wextra -Wshadow -std=c11 ... | Asignación a un parámetro dentro del cuerpo. |
cppcheck | cppcheck --enable=style archivo.c | “Parameter is modified but not used as such”. |
| Revisión manual | — | param = ... o param++ sobre un parámetro por valor. |
Checklist de autocontrol¶
¿Reasigné algún parámetro dentro del cuerpo?
¿Necesito el valor original después de modificarlo?
¿Copié a una local con nombre que describa su rol de trabajo?
¿Marqué los parámetros de solo lectura con
const?
Reglas relacionadas¶
0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique —
constsobre punteros expresa el contrato de solo lectura.0x7001h: Siempre debés inicializar las variables a un valor conocido — toda variable mutable debe nacer con un valor conocido.
0x200Ch: Cada función debe tener a lo sumo un return — el resultado se concentra en una local, no en el parámetro.
0x2003h: Todas las funciones deben incluir documentación completa y estructurada — documentar si la función modifica o no sus entradas.