Argumentos de línea de comandos argc y argv

Intermedio
C
C
Actualizado: 18/04/2026

Argumentos de línea de comandos: argc y array argv

La firma de main con argc y argv

Hasta ahora, la función main se ha utilizado sin parámetros. Sin embargo, el estándar de C define una firma alternativa que permite a un programa recibir datos externos cuando se ejecuta desde la terminal. Esta firma es:

int main(int argc, char *argv[])

El parámetro argc (argument count) es un entero que indica cuántos argumentos se han pasado al programa, incluyendo el propio nombre del ejecutable. El parámetro argv (argument vector) es un array de punteros a cadenas de caracteres, donde cada posición contiene uno de los argumentos como texto.

Siempre se cumple que argc >= 1, ya que argv[0] contiene el nombre (o ruta) del programa ejecutable. Los argumentos proporcionados por el usuario comienzan en argv[1].

Un ejemplo mínimo que imprime todos los argumentos recibidos:

#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Numero de argumentos: %d\n", argc);
    for (int i = 0; i < argc; i++) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    return 0;
}

Si se compila este programa como args y se ejecuta con:

./args hola mundo 42

La salida será:

Numero de argumentos: 4
argv[0] = ./args
argv[1] = hola
argv[2] = mundo
argv[3] = 42

Es importante tener presente que todos los argumentos son cadenas de caracteres, independientemente de si representan números u otro tipo de datos. El valor 42 en el ejemplo anterior se almacena como la cadena "42", no como un entero.

Equivalencia entre char *argv[] y char **argv

La declaración char *argv[] es equivalente a char **argv. Ambas formas indican que argv es un puntero a un puntero a char, es decir, un puntero al primer elemento de un array de cadenas. Usar una u otra es cuestión de preferencia, aunque char *argv[] resulta más expresiva al comunicar que se trata de un array.

// Ambas firmas son válidas y equivalentes
int main(int argc, char *argv[]) { /* ... */ }
int main(int argc, char **argv)  { /* ... */ }

Recorrer y procesar argumentos

El patrón más habitual para trabajar con argumentos consiste en recorrer argv con un bucle for, empezando en el índice 1 para saltar el nombre del programa:

#include <stdio.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        printf("Argumento %d: %s\n", i, argv[i]);
    }
    return 0;
}

En muchos programas, los argumentos tienen un significado posicional. Por ejemplo, un programa que copia ficheros podría esperar exactamente dos argumentos: el fichero de origen y el de destino. Para estos casos, se accede directamente a posiciones concretas de argv:

#include <stdio.h>

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Uso: %s <origen> <destino>\n", argv[0]);
        return 1;
    }
    printf("Copiar de %s a %s\n", argv[1], argv[2]);
    return 0;
}

Utilizar argv[0] en los mensajes de error es una buena práctica, ya que muestra al usuario el nombre real del ejecutable sin necesidad de escribirlo manualmente en el código.

Detectar opciones con prefijo

Los programas de consola suelen aceptar opciones precedidas por un guion, como -v o -o. Se puede detectar si un argumento es una opción comprobando su primer carácter:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            printf("Opcion: %s\n", argv[i]);
        } else {
            printf("Parametro: %s\n", argv[i]);
        }
    }
    return 0;
}

Para comparar opciones específicas se utiliza strcmp:

if (strcmp(argv[i], "-v") == 0) {
    printf("Modo verbose activado\n");
}

Conversión de argumentos a tipos numéricos

Dado que argv contiene exclusivamente cadenas de texto, cualquier argumento que represente un número debe convertirse explícitamente al tipo numérico correspondiente. La biblioteca estándar proporciona varias funciones para esta tarea.

atoi y atof

Las funciones atoi y atof, declaradas en <stdlib.h>, convierten una cadena a int y double respectivamente:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Uso: %s <entero> <decimal>\n", argv[0]);
        return 1;
    }
    int entero = atoi(argv[1]);
    double decimal = atof(argv[2]);
    printf("Entero: %d, Decimal: %.2f\n", entero, decimal);
    return 0;
}

Estas funciones son sencillas de usar, pero tienen una limitación importante: si la cadena no contiene un número válido, devuelven 0 sin indicar error. No es posible distinguir entre una conversión fallida y un valor legítimo de 0.

Las funciones atoi y atof resultan adecuadas para prototipos rápidos, pero en código de producción se recomienda usar strtol y strtod, que ofrecen detección de errores.

strtol y strtod

La función strtol (string to long) convierte una cadena a long int y permite detectar errores de conversión. Su prototipo es:

long int strtol(const char *str, char **endptr, int base);

El parámetro endptr recibe un puntero al primer carácter que no pudo convertirse. Si tras la llamada endptr apunta al inicio de la cadena, significa que no se extrajo ningún número. El parámetro base permite indicar la base numérica (10 para decimal, 16 para hexadecimal, etc.).

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Uso: %s <numero>\n", argv[0]);
        return 1;
    }

    char *fin;
    long valor = strtol(argv[1], &fin, 10);

    if (*fin != '\0') {
        printf("Error: '%s' no es un numero valido\n", argv[1]);
        return 1;
    }
    printf("Valor convertido: %ld\n", valor);
    return 0;
}

De forma análoga, strtod convierte una cadena a double con detección de errores:

char *fin;
double valor = strtod(argv[1], &fin);
if (*fin != '\0') {
    printf("Error: argumento no numerico\n");
    return 1;
}

La comprobación *fin != '\0' verifica que toda la cadena fue consumida durante la conversión. Si queda algún carácter sin procesar, la entrada no era un número puro.

Validación de argumentos

Un programa robusto debe validar los argumentos antes de utilizarlos. Las validaciones más frecuentes incluyen comprobar la cantidad de argumentos, verificar que los valores numéricos estén en un rango aceptable y mostrar mensajes de uso claros.

Validar la cantidad de argumentos

El primer paso consiste en verificar que el usuario ha proporcionado el número correcto de argumentos:

if (argc < 2) {
    printf("Uso: %s <argumento_obligatorio> [opcionales...]\n", argv[0]);
    return 1;
}

Devolver un código de retorno distinto de 0 indica al sistema operativo que el programa terminó con un error, lo cual es relevante cuando se integra en scripts o automatizaciones.

Validar rangos numéricos

Tras la conversión, se debe comprobar que el valor cae dentro de un rango razonable:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Uso: %s <edad>\n", argv[0]);
        return 1;
    }

    char *fin;
    errno = 0;
    long edad = strtol(argv[1], &fin, 10);

    // Comprobar errores de conversion
    if (*fin != '\0' || errno == ERANGE) {
        printf("Error: valor no valido\n");
        return 1;
    }
    // Comprobar rango logico
    if (edad < 0 || edad > 150) {
        printf("Error: la edad debe estar entre 0 y 150\n");
        return 1;
    }
    printf("Edad registrada: %ld\n", edad);
    return 0;
}

La variable global errno, definida en <errno.h>, se establece a ERANGE cuando strtol detecta que el resultado excede el rango representable por un long. Es buena práctica asignar errno = 0 antes de la llamada para evitar falsos positivos.

Ejemplos prácticos

Calculadora de linea de comandos

Este programa recibe una operación aritmética como tres argumentos: operando, operador y operando.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc != 4) {
        printf("Uso: %s <num1> <operador> <num2>\n", argv[0]);
        printf("Operadores: + - x /\n");
        return 1;
    }

    double a = atof(argv[1]);
    double b = atof(argv[3]);
    char *op = argv[2];
    double resultado;

    if (strcmp(op, "+") == 0) {
        resultado = a + b;
    } else if (strcmp(op, "-") == 0) {
        resultado = a - b;
    } else if (strcmp(op, "x") == 0) {
        resultado = a * b;
    } else if (strcmp(op, "/") == 0) {
        if (b == 0.0) {
            printf("Error: division por cero\n");
            return 1;
        }
        resultado = a / b;
    } else {
        printf("Operador '%s' no reconocido\n", op);
        return 1;
    }

    printf("%.2f %s %.2f = %.2f\n", a, op, b, resultado);
    return 0;
}

Se utiliza x en lugar de * como operador de multiplicación porque el carácter * tiene un significado especial para la shell (expansión de comodines) y requeriría escapado.

Ejemplo de ejecución:

./calc 10.5 + 3.2
10.50 + 3.20 = 13.70

Procesador de ficheros con opciones

Un ejemplo más completo que acepta un nombre de fichero obligatorio y opciones para controlar el comportamiento:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int verbose = 0;
    char *fichero = NULL;

    // Recorrer argumentos buscando opciones y parametros
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-v") == 0) {
            verbose = 1;
        } else if (fichero == NULL) {
            fichero = argv[i];
        } else {
            printf("Error: argumento inesperado '%s'\n", argv[i]);
            return 1;
        }
    }

    if (fichero == NULL) {
        printf("Uso: %s [-v] <fichero>\n", argv[0]);
        return 1;
    }

    if (verbose) {
        printf("Modo verbose activado\n");
        printf("Procesando fichero: %s\n", fichero);
    }

    FILE *f = fopen(fichero, "r");
    if (f == NULL) {
        printf("Error: no se puede abrir '%s'\n", fichero);
        return 1;
    }

    // Contar lineas del fichero
    int lineas = 0;
    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), f) != NULL) {
        lineas++;
    }
    fclose(f);

    printf("El fichero '%s' tiene %d lineas\n", fichero, lineas);
    return 0;
}

Este programa ilustra un patrón habitual: separar las opciones (argumentos que empiezan por -) de los parámetros posicionales mediante un bucle que clasifica cada argumento. Las opciones activan flags (variables booleanas) y los parámetros se almacenan en variables dedicadas.

Generador de tablas de multiplicar

Un ejemplo que combina validación numérica con strtol y lógica de negocio sencilla:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Uso: %s <numero>\n", argv[0]);
        return 1;
    }

    char *fin;
    long n = strtol(argv[1], &fin, 10);

    if (*fin != '\0' || n < 1 || n > 100) {
        printf("Error: introduce un numero entre 1 y 100\n");
        return 1;
    }

    printf("Tabla de multiplicar del %ld:\n", n);
    for (int i = 1; i <= 10; i++) {
        printf("%ld x %d = %ld\n", n, i, n * i);
    }
    return 0;
}

Ejecución:

./tabla 7
Tabla de multiplicar del 7:
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
...
7 x 10 = 70

Buenas prácticas con argumentos de linea de comandos

Al diseñar programas que reciben argumentos, conviene seguir una serie de pautas que mejoran la usabilidad y la robustez del software:

  • Mostrar siempre un mensaje de uso cuando los argumentos no son correctos, indicando la sintaxis esperada.

  • Utilizar strtol y strtod en lugar de atoi y atof cuando se necesite detectar entradas no numéricas.

  • Comprobar errno tras llamar a funciones de conversión para detectar desbordamientos de rango.

  • Devolver códigos de salida distintos de 0 cuando el programa termina por un error, de forma que los scripts puedan reaccionar adecuadamente.

  • Documentar las opciones aceptadas directamente en el mensaje de uso del programa, ya que este es el primer recurso al que acude el usuario.

  • Evitar acceder a posiciones de argv sin antes verificar que argc es suficientemente grande, ya que hacerlo produce comportamiento indefinido.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, C es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de C

Explora más contenido relacionado con C y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Comprender la firma de main con argc y argv. Acceder y recorrer los argumentos recibidos. Convertir argumentos de texto a tipos numéricos con atoi, atof y strtol. Validar la cantidad y formato de los argumentos.

Cursos que incluyen esta lección

Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje