Looking for Computer Science  & Information Technology online courses ?
Check my new web site: https://www.yesik.it !

A partir de votre shell, vous avez sans doute déjà utilisé des commandes de la forme:

sh$ ls /etc
sh$ javac Demo.java
sh$ g++ -Wall -Werror -o hello hello.cc
sh$ firefox http://www.chicoree.fr
etc...

Dans chacun de ces exemples, la commande sert à lancer un programme (ls, javac, g++ ou firefox). Mais l'exécution de ce programme dépend des autres informations qui vous avez données sur la ligne de commande. Ces informations sont des arguments du programme. Dans la terminologie de l'informatique, on dit que vous avez invoqué un programme en lui passant des arguments sur la ligne de commande.

Nous allons voir ici comment récupérer ces arguments dans un programme.

Java

En Java, le programme principal prend en paramètre un tableau de chaînes de caractères traditionnellement appelé args:

static public void main(String[] args) {
...

Ce tableau sert à récupérer les arguments de la ligne de commande lorsque le programme est exécuté.

Note:

Les arguments récupérés sont ceux de la ligne de commande lorsque le programme est exécuté, pas ceux passés lorsqu'il a été compilé!

public class Arguments {
    public static void main(String[] args) {
        System.out.println("Nombre d'arguments: " + args.length);
        for(int i = 0; i < args.length; ++i) {
            System.out.println("Argument " + i + ": " + args[i]);
        }
    }
}

Le programme ci-dessus affiche le nombre et les arguments reçus. Pour le compiler et l'exécuter, vous pouvez utiliser les commandes suivantes:

sh$ javac Arguments.java
sh$ java Arguments
Nombre d'arguments: 0
sh$ java Arguments hello Java
Nombre d'arguments: 2
Argument 0: hello
Argument 1: Java

Un exemple utile en Java

Vous connaissez la commande shell echo? Celle-ci permet d'afficher un message sur la sortie standard, par exemple lors de l'exécution d'un script:

sh$ echo Salut!
Salut!

Nous allons réaliser un programme similaire à la commande echo, mais qui affiche le message en MAJUSCULES.

Le principe est simple: nous allons parcourir le tableau des arguments, et afficher chacun d'eux après l'avoir converti en majuscule. Il nous faut donc:

Muni de ces informations, le programme suivant ne doit receler aucune complexité:

public class Upper {
    static public void main(String[] args) {
        for(String arg : args) { // pour chaque argument
            String  enMajuscule = arg.toUpperCase();
            System.out.print(enMajuscule);  // affiche la chaîne en majuscule
            System.out.print(" ");          // ajoute un blanc de séparation
        }
 
        System.out.println(); // fini par un retour à la ligne
    }
}

La compilation et l'exécution se fait de manière classique:

sh$ javac Upper.java
sh$ java Upper Hello world!
HELLO WORLD!

Pour vous convaincre du fonctionnement de ce programme, n'hésitez pas à expérimenter un peu. Par exemple en l'appelant sans argument. Ou en séparant les arguments par plusieurs espaces au lieu d'un seul...

Groovy

Tout ce que nous avons dit plus haut est tout aussi valide pour Groovy. En fait, les deux programmes Java ci-dessus sont également des programmes Groovy valides – et qui font bien sûr la même chose:

sh$ cp Arguments.java Arguments.groovy
sh$ groovy Arguments.groovy
Nombre d'arguments: 0
sh$ groovy Arguments.groovy abc def ghi
Nombre d'arguments: 3
Argument 0: abc
Argument 1: def
Argument 2: ghi
sh$ cp Upper.java Upper.groovy
sh$ groovy Upper.groovy Hello world!
HELLO WORLD!

Néanmoins, on peut faire un tout petit peu mieux en Groovy:

args.each() {
    def enMajuscule = it.toUpperCase();
    print("$enMajuscule ");
}
println();

Remarque:

Pourquoi print("$enMajuscule "); plutôt que simplement print(enMajuscule);?

En fait, si vous regardez attentivement, vous verrez qu'il y a un espace à la fin de la chaîne:

print("$enMajuscule ");
/*                 ^ il y a un blanc ici ! */

Cela me permet d'ajouter un blanc de séparation après chaque argument. Et m'épargne la concaténation suivante:

print(enMajuscule + " ");

C++

C++ tout comme Java permet de récupérer les arguments passés par le shell dans un tableau. Par contre, ce tableau est un peu différent. Sans rentrer dans les détails, il contient non pas une chaîne de caractère contenant chaque argument, mais l'adresse en mémoire où se trouve le premier caractère de l'argument. La fin de chaque argument pouvant être déterminée par la présence du caractère spécial 0 (zéro).

Vous savez également qu'il n'est pas facile de connaître, en C++, la taille d'un tableau. Pour cette raison, celle-ci est communiquée au programme en même temps que le tableau des arguments.

Sachant qu'en C++, l'adresse d'un caractère est du type char*, cela nous donne la déclaration suivante pour le programme principal:

int main(int argc, char * argv[])
{
    /* ... */

    return 0;
}

Pour visualiser les arguments reçus par le programme nous pouvons utiliser le programme suivant:

#include <iostream>
 
int main(int argc, char * argv [])
{
    std::cout << "Nombre d'arguments: " << argc << std::endl;
    for(int i = 0; i < argc; i = i+1)
    {
        std::cout << "Argument " << i << ": "
                  << argv[i] << std::endl;
    }
 
    return 0;
}

Nous pouvons compiler et exécuter le programme ainsi:

sh$ g++ arguments.cc -Wall -Werror -o arguments
sh$ ./arguments
Nombre d'arguments: 1
Argument 0: ./arguments
sh$ ./arguments Hello c++
Nombre d'arguments: 3
Argument 0: ./arguments
Argument 1: Hello
Argument 2: c++

Piège:

Si vous avez déjà testé le programme Java équivalent, vous remarquerez qu'en C++, le programme reçoit un argument supplémentaire: En effet, en C++ le programme reçoit systématiquement son nom en premier argument.

sh$ ./arguments
Nombre d'arguments: 1
Argument 0: ./arguments

Remarquez aussi que le nom du programme est reçu comme il a été tapé dans le shell. Y compris avec le chemin:

sh$ pwd
/home/sylvain/Developpement/args/cc/arguments
sh$ /home/sylvain/Developpement/args/cc/arguments
Nombre d'arguments: 1
Argument 0: /home/sylvain/Developpement/args/cc/arguments

Un exemple utile en C++

Tout comme avec Java, nous allons écrire un programme utilitaire pour afficher un message en majuscules. Résumons les informations à notre disposition:

Comme c'est peut être un peu compliqué, nous allons y aller progressivement. Tout d'abord, commençons par le programme principal et une boucle pour parcourir le tableau des arguments.

int main(int argc, char * argv [])
{
    /* Commence à 1 pour ''sauter'' le nom du programme */
    for(int i = 1; i < argc; i = i+1) /* pour chaque argument */
    {
        /* ... */
    }
 
    return 0;
}

Maintenant, pour chaque argument, il nous faut le parcourir caractère par caractère. En effet: le fonction toupper travaille au niveau des caractères individuels:

#include <iostream>
 
int main(int argc, char * argv [])
{
    /* Commence à 1 pour ''sauter'' le nom du programme */
    for(int i = 1; i < argc; i = i+1) /* pour chaque argument */
    {
        /* pour chaque caractère de l'argument */
        for(char *argument = argv[i]; *argument != 0; argument = argument+1)
        {
            /* ... */
        }
    }
 
    return 0;
}

Remarquez l'utilisation de la boucle for. Celle-ci sert à parcourir caractère par caractère un argument. Ce qui est notable ici, c'est que nous utilisons pour variable de boucle une adresse mémoire (en C++, on utilise le terme de pointeur). Celle-ci peut être incrémentée comme n'importe quelle autre variable de boucle. Enfin, denier point notable, pour savoir ce qui se trouve à l'adresse désignée par un pointeur, on utilise une étoile (*).

Tout cela pour dire que dans la boucle la plus interne, *argument désigne bien un caractère d'un argument. Pour vous en convaincre, vous pouvez l'afficher:

       for(char *argument = argv[i]; *argument != 0; argument = argument+1)
       {
           std::cout << *argument << std::endl;
       }

Bien, maintenant que nous parcourons nos arguments caractère par caractère, reste à utiliser la fonction toupper. C'est ce que fait le programme ci-dessous. Pour enjoliver l'affichage, il ajoute également un espace pour séparer les arguments et d'un retour à la ligne après le dernier:

#include <ctype.h>
#include <iostream>
 
int main(int argc, char * argv [])
{
    /* Commence à 1 pour ''sauter'' le nom du programme */
    for(int i = 1; i < argc; i = i+1) /* pour chaque argument */
    {
        /* pour chaque caractère de l'argument */
        for(char *argument = argv[i]; *argument != 0; argument = argument+1)
        {
            char majuscule = toupper(*argument);
            std::cout << majuscule;
        }
        std::cout << " "; /* espace de séparation */
    }
    std::cout << std::endl; /* retour à la ligne */
 
    return 0;
}

Comme toujours, vous pouvez compiler et tester ainsi:

sh$ g++ -Wall -Werror upper.cc -o upper
sh$ ./upper Hello world!
HELLO WORLD!

Un dernier mot: le programme C++ est définitivement plus complexe que sa contrepartie Java. En particulier parce qu'il travaille au niveau du "caractère en mémoire". Alors que le programme Java manipule une "chaîne de caractère", ce qui est un concept de plus haut niveau. C++ confirme donc son statut de langage "système". Il permet la manipulation directe de la mémoire – mais au prix d'une plus grande complexité des programmes.

A vous de jouer

On souhaite un programme C++ capable d'afficher les arguments reçus sur la ligne de commande en ne capitalisant que l'initiale, conformément aux exemples suivants:

sh$ ./capitalise david copperfield
David Copperfield
sh$ ./capitalise Oliver TWIST
Oliver Twist
  1. Ecrivez ce programme en utilisant les fonctions C toupper pour capitaliser l'initiale et tolower pour passer en minuscule les autres caractères.
  2. (plus difficile) Assurez-vous que votre programme réagit correctement aux noms composés:
    sh$ ./capitalise jean-claude
    Jean-Claude
    

    Vous aurez sans doute besoin de la fonction C isalpha.