Funciones con lista de argumentos variables en C
Hoy voy a explicar brevemente como podemos escribir una función en C con un número de parámetros variables. Esto no es muy habitual, pero en algunas ocasiones puede resultar interesante.
Como ejemplo vamos a implementar una función que concatene un número variable de cadenas de texto.
Para ello C nos ofrece una serie de macros (C89 y C99) incluidas en <stdarg.h>. Las macros son las siguientes:
- void va_start(va_list ap, last) - Esta macro realiza la reserva de memoria de la lista de variables en ap. Con last se indica el nombre del último parámetro antes de la lista de variables, o lo que es lo mismo, el primer elemento de la lista será el parámetro siguiente a last.
- type va_arg(va_list ap, type) - Esta macro actúa como un iterador. El parámetro ap indica la lista sobre la que se quiere iterar y type es el tipo de dato que se espera encontrar. Según la especificación oficial, utilizar va_arg después del último parámetro o con un tipo de dato que no coincida puede tener consecuencias impredecibles. Así que cuidado :)
- void va_end(va_list ap) - Esta macro, finalmente, libera la memoria reservada en la lista ap.
Por último, comentar que también disponemos de un tipo de dato va_list, que realmente se define un "puntero" para recorrer la lista de parámetros.
Ahora veamos el código en acción:
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char * concatenate(int numcad, ...)
{
char * result = 0;
char ** args = (char **)malloc(numcad*sizeof(char *));
int size = 0, i;
va_list ap;
va_start(ap, numcad);
for(i = 0; i < numcad; i++)
{
args[i] = va_arg(ap, char *);
size += strlen(args[i]);
}
result = (char *)malloc((size+1)*sizeof(char)); // size+1 para el '\0'
for(i = 0; i < numcad; i++)
sprintf(result, "%s%s", result, args[i]);
va_end(ap);
return result;
}
Es obligatorio que la función reciba al menos un parámetro, ya que éste es necesario para construir la lista de parámetros (va_start). Para la implementación de la función he decidido que el primer parámetro sea un entero que me diga cuantas cadenas se van a concatenar, aunque esto no es obligatorio. De hecho, un claro ejemplo son las funciones de la familia printf o vprintf, donde el primer parámetro es una cadena con el formato que deseamos.
Una vez implementada la función podremos realizar distintas llamadas a concatenate con distintos parámetros:
int main()
{
char * c;
c = concatenate(2, "hola", " que tal");
printf("%s\n", c);
free(c);
c = concatenate(3, "un ejemplo ", "algo mas", " largo");
...
free(c);
}
Tags
La teoría es cuando crees saber algo, pero no funciona.
La práctica es cuando algo funciona, pero no sabes por qué.
Los programadores combinan la teoría y la práctica:
Nada funciona y no saben por qué.
