Argomenti della Riga di Comando in Linguaggio C

In questa lezione studieremo gli argomenti della riga di comando in Linguaggio C.

Gli argomenti della riga di comando sono informazioni aggiuntive che vengono passate a un programma quando viene lanciato da console. Essi vengono passati sotto forma di un array di stringhe. Studieremo, in questa lezione, come accedervi nei nostri programmi scritti in C.

Argomenti della Riga di Comando

Spesso, quando lanciamo un programma dalla riga di comando, cioè dalla console, abbiamo bisogno di passare delle informazioni aggiuntive. Tali informazioni potrebbero essere il nome di un file da processare, il percorso di una cartella dove scrivere l'output, oppure, semplicemente, uno switch, una sorta di flag che attiva o disattiva una funzionalità del programma.

Prendiamo un esempio dal mondo Linux. Se vogliamo visualizzare il contenuto della cartella in cui ci troviamo, possiamo adoperare il comando ls, contrazione di list. Tipicamente, se eseguiamo ls, otteniamo un output del genere:

$ ls
file1.txt file2.txt file3.txt

Tuttavia, se vogliamo visualizzare anche i file nascosti, possiamo passare un argomento al comando ls. In particolare, possiamo passare l'argomento -a, che sta per all, ovvero tutti. In questo modo, il comando ls visualizzerà anche i file nascosti:

$ ls -a
. .. file1.txt file2.txt file3.txt .hiddenfile

Se poi, vogliamo visualizzare informazioni dettagliate sui file, possiamo passare l'argomento -l, che sta per long, ovvero lungo:

$ ls -l
-rw-r--r-- 1 user user 0 Jan  1 00:00 file1.txt
-rw-r--r-- 1 user user 0 Jan  1 00:00 file2.txt
-rw-r--r-- 1 user user 0 Jan  1 00:00 file3.txt

In questo caso, il comando ls visualizzerà informazioni dettagliate sui file, come i permessi, il numero di link, il proprietario, il gruppo, la dimensione, la data di creazione e il nome del file.

Ora, questi switch, contrassegnati da un trattino -, sono detti argomenti della riga di comando. Essi sono opzionali, del resto solo il nome del file o comando da eseguire è obbligatorio, ma attraverso di essi è possibile personalizzare il comportamento del programma.

Queste informazioni aggiuntive prendono il nome di argomenti della riga di comando.

Definizione

Argomenti della Riga di Comando

Gli argomenti della riga di comando sono informazioni aggiuntive che vengono passate a un programma quando viene eseguito dalla riga di comando.

Essi sono separati dal nome del programma da spazi:

$ nome_programma argomento1 argomento2 argomento3 ...

Accesso agli Argomenti della Riga di Comando

Gli argomenti della riga di comando non sono disponibili soltanto per i comandi del sistema, ma possono essere sfruttati da qualunque programma scritto in C.

Per poter accedere a questi argomenti nel nostro programma dobbiamo, tuttavia, modificare la firma della funzione main del nostro programma.

In particolare, dobbiamo modificare la funzione main in maniera tale che accetti due parametri chiamati, tipicamente, argc e argv. Per cui la funzione main diventa:

int main(int argc, char *argv[])
{
    // Codice del programma
    return 0;
}

Il primo parametro argc sta per argument count, ovvero contatore degli argomenti. Esso rappresenta il numero totale di argomenti passati al programma, compreso il nome del programma stesso.

Il secondo parametro argv sta per argument vector, ovvero vettore degli argomenti. Esso è un array di stringhe, dove ogni elemento rappresenta un argomento passato al programma.

In generale, argv[0] contiene il nome del programma, mentre argv[1], argv[2], ..., argv[argc-1] contengono gli argomenti passati al programma. Inoltre, l'array argv contiene anche un elemento aggiuntivo, argv[argc], che è sempre NULL ossia un puntatore che non punta a nulla. Vedremo meglio il puntatore NULL nelle prossime lezioni.

In base a quanto detto, se invochiamo un programma prova in questo modo:

$ ./prova arg1 arg2 arg3

Quello che accade è che:

  • argc sarà uguale a 4, poiché abbiamo passato 3 argomenti al programma ma dobbiamo anche contare il suo stesso nome;
  • argv[0] sarà uguale a "./prova", cioè il nome del programma;
  • argv[1] sarà uguale a "arg1", cioè il primo argomento;
  • argv[2] sarà uguale a "arg2", cioè il secondo argomento;
  • argv[3] sarà uguale a "arg3", cioè il terzo argomento;
  • argv[4] sarà uguale a NULL.

In memoria, argv sarà organizzato in questo modo:

Struttura di argv del programma di esempio
Figura 1: Struttura di argv del programma di esempio

Accedere agli Argomenti della Riga di Comando

Dal momento che gli argomenti sono memorizzati in un array, la maggior parte dei programmi, per potervi accedere, implementa un ciclo for che scorre l'array argv.

Ad esempio, possiamo scrivere un programma che stampa tutti gli argomenti passati al programma:

#include <stdio.h>

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

    return 0;
}

Se compiliamo e lanciamo il programma prova con gli argomenti arg1, arg2 e arg3, otteniamo:

$ ./prova arg1 arg2 arg3
Argomento 0: ./prova
Argomento 1: arg1
Argomento 2: arg2
Argomento 3: arg3

Il ciclo for presente all'interno del programma può essere, in realtà, riscritto in un altro modo. Tenendo conto, infatti, che l'ultimo elemento dell'array argv è NULL, possiamo modificare il ciclo for in questo modo:

char **p;
int i;
for (i = 0, p = argv; *p != NULL; p++, i++) {
    printf("Argomento %d: %s\n", i, *p);
}

In questo modo, il ciclo for scorre l'array argv fino a quando non trova il puntatore NULL.

Esempio

Proviamo a scrivere un programma di esempio, che prende dalla riga di comando vari numeri interi e ne calcola la somma.

Prima di poter scrivere il programma, dobbiamo introdurre la funzione atoi, che converte una stringa in un numero intero. La funzione atoi è definita nella libreria stdlib.h.

int atoi(const char *str);

La funzione atoi prende in input una stringa str e restituisce il corrispondente numero intero. Se la stringa str non rappresenta un numero intero, la funzione restituisce 0.

Iniziamo a realizzare lo scheletro del nostro programma:

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

int main(int argc, char *argv[]) {
    int somma = 0;

    // Codice del programma

    return 0;
}

Per prima cosa, dobbiamo controllare che l'utente abbia effettivamente passato una serie di parametri al programma. Se argc è minore di 2, allora l'utente non ha passato alcun parametro. In tal caso, stampiamo un messaggio di errore e terminiamo il programma.

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

int main(int argc, char *argv[]) {
    int somma = 0;

    if (argc < 2) {
        printf("Errore: nessun parametro passato\n");
        return -1;
    }

    // Codice del programma

    return 0;
}

A questo punto, possiamo calcolare la somma dei numeri passati come argomenti al programma. Per farlo, dobbiamo scorrere l'array argv a partire dall'elemento argv[1], poiché argv[0] contiene il nome del programma, e convertire ogni elemento in un numero intero.

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

int main(int argc, char *argv[]) {
    int somma = 0;

    if (argc < 2) {
        printf("Errore: nessun parametro passato\n");
        return -1;
    }

    for (int i = 1; i < argc; i++) {
        somma += atoi(argv[i]);
    }

    printf("La somma dei numeri passati è: %d\n", somma);

    return 0;
}

Se compiliamo e lanciamo il programma con i parametri 1, 2 e 3, otteniamo:

$ ./somma 1 2 3
La somma dei numeri passati è: 6

La cosa interessante è che se dovessimo inserire un parametro non numerico, la funzione atoi restituirebbe 0, e quindi il programma sommerebbe 0 alla somma parziale.

Ad esempio, se lanciamo il programma con i parametri 1, 2 e ciao, otteniamo:

$ ./somma 1 2 ciao
La somma dei numeri passati è: 3

In Sintesi

In questa lezione abbiamo studiato gli argomenti della riga di comando in Linguaggio C.

Abbiamo visto che, modificando il prototipo della funzione main, possiamo accedere agli argomenti passati al programma dalla riga di comando. In particolare, abbiamo visto che la funzione main accetta due parametri, argc e argv, che rappresentano rispettivamente il numero totale di argomenti passati al programma e un array di stringhe contenente gli argomenti stessi.

In particolare, argv è un array di stringhe, dove ogni elemento rappresenta un argomento passato al programma. L'elemento argv[0] contiene il nome del programma, mentre gli elementi argv[1], argv[2], ..., argv[argc-1] contengono gli argomenti passati al programma. L'elemento argv[argc] è sempre NULL.

Infine, abbiamo visto un esempio di programma che calcola la somma dei numeri passati come argomenti dalla riga di comando.