Todo programa que ejecutas desde una terminal puede recibir argumentos: gcc -Wall hello.c -o hello le pasa cuatro. Tus propios programas en C leen los suyos a través de dos parámetros de main, y ese es todo el mecanismo: sin llamadas a bibliotecas, sin configuración.
La firma
Hasta ahora todos los ejemplos de estos docs han usado int main(void). La otra forma estándar recibe la línea de comandos:
int main(int argc, char *argv[]) {
/* ... */
}
argc("argument count", cantidad de argumentos) es cuántos argumentos hay, incluyendo el nombre del programa.argv("argument vector", vector de argumentos) es un array de cadenas.char *argv[]significa "array de punteros a char", que es un array de cadenas de C.
char **argv es una forma equivalente de escribirlo que verás con la misma frecuencia; los parámetros de tipo array se degradan a punteros, así que ambas declaran lo mismo.
Usa el panel Args del editor para proporcionar argumentos (cada campo es un argumento) y luego pulsa Run. Prueba con tres campos: hola, mundo, 42.
La anatomía
Ejecutar ./greet Ada Lovelace produce:
| Índice | Valor | |
|---|---|---|
argv[0] | "./greet" | el nombre del programa tal como se invocó |
argv[1] | "Ada" | primer argumento real |
argv[2] | "Lovelace" | segundo argumento real |
argv[3] | NULL | el terminador |
argc | 3 | la cuenta, incluyendo argv[0] |
Cuatro hechos que vale la pena memorizar:
argcvale al menos 1 en la práctica, porqueargv[0]es el nombre del programa. Los argumentos reales empiezan en el índice 1, que es la razón por la que los bucles sobre ellos empiezan eni = 1.- Todo es una cadena.
./prog 42te da"42", los dos caracteres, nunca el número 42. Convertirlo es tarea tuya. argv[argc]esNULL. Lo garantiza el estándar, así que puedes recorrer el array sinargcsi lo prefieres:for (char **p = argv + 1; *p != NULL; p++).- El shell separa las palabras, no tu programa.
./prog "Ada Lovelace"es un solo argumento; las comillas las consume el shell y nunca llegan aargv.
Comprobar antes de leer
Un argumento que no se pasó no es una cadena vacía: es memoria que no tienes derecho a tocar. Valida siempre argc primero:
Dos convenciones en ese programita, ambas estándar en las herramientas Unix:
- El mensaje de uso va a
stderr, no astdout, para que no contamine una salida que se esté redirigiendo por una tubería. - Un retorno distinto de cero desde
mainseñala un fallo a quien haya ejecutado el programa.0significa éxito; cualquier otra cosa significa que algo salió mal. Los scripts de shell lo comprueban.
Imprimir argv[0] en lugar de un nombre escrito a mano hace que el mensaje coincida con la forma en que el usuario invocó el programa, incluso si lo renombraron o llegaron a él por otra ruta.
Convertir argumentos numéricos
argv[1] es texto. Para hacer aritmética tienes que convertirlo, y la función adecuada es strtol, de <stdlib.h>:
Añade 10, 20 y 30 como tres campos de Args y luego cambia uno por banana para ver la ruta de error.
El tercer parámetro de strtol es la base: 10 para decimal, 16 para hexadecimal, o 0 para detectarla automáticamente a partir de un prefijo 0x o un cero inicial. El segundo es dónde guardar un puntero al primer carácter que no consumió, y eso es lo que hace posible la comprobación de errores:
end == textsignifica que no procesó nada: el argumento no empezaba con un número.*end != '\0'significa que sobraba texto después del número, así que"12abc"se rechaza en lugar de convertirse calladamente en 12.errno == ERANGEsignifica que el valor desbordólong.
Compara con atoi, que es más corto y no puede informar nada de esto:
int n = atoi(argv[1]); /* "banana" -> 0, "0" -> 0, desbordamiento -> indefinido */
atoi devuelve 0 para una entrada inválida, lo cual es indistinguible de un cero genuino. Usa strtol (y strtod para punto flotante) siempre que la entrada venga de fuera de tu programa. Hay más en conversión de cadenas.
Una pequeña calculadora
Juntándolo todo: un programa que recibe un número, un operador y otro número:
Prueba 12 + 30, luego 7 x 6, luego 5 / 0.
Fíjate en strcmp(op, "+") == 0 en lugar de op == "+". Comparar valores char * con == compara direcciones, no contenidos, y sería falso incluso para textos idénticos. Consulta funciones de cadenas.
La x en lugar de * es un detalle del mundo real: la mayoría de los shells expanden un * suelto a la lista de archivos del directorio actual antes de que tu programa siquiera se ejecute. Ponerlo entre comillas ('*') también funciona, pero elegir un carácter que el shell ignora es más amable.
Procesar banderas
Por convención, las opciones empiezan con -. Un bucle simple hecho a mano cubre los casos comunes:
Pruébalo con cuatro campos de Args: -v, -n, 3, hola.
La comprobación i + 1 >= argc antes de argv[++i] es la línea importante: una opción que espera un valor debe confirmar que el valor realmente está ahí, o -n como último argumento lee más allá del final del array. En sistemas Unix reales, getopt de <unistd.h> hace todo esto por ti, incluidas las opciones cortas agrupadas como -vn3; vale la pena recurrir a él en cuanto un programa tiene más de dos o tres banderas.
Argumentos en el editor del navegador
Los bloques de editor de esta página se compilan y ejecutan por ti, y el panel Args es donde escribes lo que iría después del nombre del programa en una terminal. Cada campo que añades con Add arg se convierte exactamente en una entrada de argv: no hay ningún shell de por medio, así que nada se separa por espacios y no hace falta ningún entrecomillado; un campo que contenga hola mundo llega como el único argumento hola mundo. Para pasar -n 3 hola, añade tres campos. Dejar el panel vacío da argc == 1, que es la razón por la que la guarda argc < 2 se dispara en la primera ejecución, y la razón por la que vale la pena escribirla.
Errores comunes
- Leer
argv[1]sin comprobarargc. Comportamiento indefinido cuando no se pasó ningún argumento, y el fallo más común en esta área. - Empezar el bucle en
i = 0. Eso procesa el nombre del programa como si fuera un dato. - Tratar
argv[1]como un número. Es texto hasta que lo conviertes. - Usar
atoicon entrada del usuario. No hay forma de distinguir un argumento inválido de un cero. - Comparar cadenas con
==. Usastrcmp. - Escribir dentro de las cadenas de
argv. El estándar permite modificarlas, pero el espacio es limitado y depende de la plataforma; copia a tu propio búfer si necesitas cambiar algo.
Preguntas frecuentes
¿Qué son argc y argv en C?
Son los dos parámetros de int main(int argc, char *argv[]). argc es la cantidad de argumentos de la línea de comandos, incluido el nombre del programa; argv es un array con esos argumentos como cadenas. argv[0] es el nombre del programa, argv[1] es el primer argumento real y argv[argc] siempre es NULL.
¿Cómo se le pasan argumentos a un programa en C?
Los escribes después del nombre del ejecutable en la terminal: ./program hola 42. Eso da argc == 3, con argv[1] igual a la cadena "hola" y argv[2] igual a la cadena "42". En el editor de esta página, los argumentos van en el panel Args en vez de una terminal.
¿Cómo se convierte un argumento de línea de comandos a int en C?
Usa strtol: char *end; long n = strtol(argv[1], &end, 10); y después comprueba que end no siga apuntando al inicio (no se procesó nada) y que *end sea '\0' (sin basura al final). atoi es más corto pero devuelve 0 tanto para "0" como para "banana", así que no puede informar un error.
¿Qué es argv[0] en C?
El nombre con el que se invocó el programa, normalmente ./program o la ruta completa. Es útil en los mensajes de uso (fprintf(stderr, "uso: %s ARCHIVO\n", argv[0])) para que el mensaje coincida con la forma en que el usuario realmente lo llamó. En casos poco habituales puede ser una cadena vacía, así que no des por hecho que está presente.