IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Exécuter des commandes shell


Sujet :

C

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut Exécuter des commandes shell
    Bonjour, j'ai shell à rendre et je butte sur quelques erreurs.

    je ne comprends pas pourquoi lorsque je rentre une commande comprenant un chemin, le code se déroule correctement, et lorsque'il n'y en a pas j'ai une erreur de segmentation.

    le deuxième blocage se trouve dans la fonction Execution : la commande y arrive mais rien ne se passe.

    any idea ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
     
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
     
    typedef struct command
    {
        char chemin[256];
        char instruction[128];
        char argument[128];
     
    }command;
     
    void Execution(command cmde, int path)
    {
    	pid_t fils;
        printf("\nentrée fonction Execution :\n");
        printf("cmde.instruction : %s\n",cmde.instruction);
        printf("cmde.chemin : %s\n",cmde.chemin);
        printf("cmde.argument : %s\n",cmde.argument);
     
        fils=fork();
        if (fils==0)
        {
        	if (path>0)
    	    {
    	        printf("execl\n");
    	        execl (cmde.instruction, cmde.chemin, cmde.argument, NULL);
    	    }
     
    	    else
    	    {
    	        printf("execlp\n");
    	        execlp (cmde.instruction, cmde.argument, NULL);
    	    }
    	    exit(0);
        }
     
     
     
    }
     
    void Interpretation (char* saisie)
    {
        int i=0,j,path=0,cmpt,args=0;
        command cmde;
        cmde.argument[0]='\0';
        char* temp=strtok(saisie," ");
     
        j=i;
     
        strcpy(cmde.instruction,temp);
        printf("cmde.instruction : %s\n",cmde.instruction);
     
        for (cmpt=0;cmpt<=j;cmpt++)
        {
        	i+=strlen(temp);
            temp = strtok(0," ");
            printf("saisie[%d] = %c\n",i, saisie[i]);
     
            if (saisie[i]=='/')
            {
                path=1;
                strcpy(cmde.chemin,temp);
                printf("cmde.chemin : %s\n",cmde.chemin);
                i+=strlen(temp);
            }
     
            else
            {
                if (args>0)
                {
                    strcat(cmde.argument," ");
                    strcat(cmde.argument,temp);
                }
     
                else
                {
                    strcpy(cmde.argument,temp);
                }
     
                printf("cmde.argument : %s\n",cmde.argument);
                args++;
                i+=strlen(temp);
            }
     
            i+=strlen(temp);
        }
     
        if (saisie[i-1]=='&')
        {
            printf("PID = %d\n",getpid());
        }
     
        Execution(cmde,path);
    }
     
    int main ()
    {
        char saisie[1500]={'\0'};
        command cmde;
     
        puts("Saisir une commande :");
        fgets(saisie, 300, stdin);
     
        strncpy(cmde.chemin, saisie, sizeof(cmde.chemin));
     
        Interpretation(saisie);
     
        return 0;
    }

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Ca provient du fait que le pointeur "temp" est à NULL quand tu le copies dans "cmde.argument". Et il est à NULL quand on tape une commande sans argument style "ls" ou "/bin/ls" si on y met un chemin.
    Sinon concernant ton second blocage chez-moi il n'y est pas. J'ai exécuté ton code en y mettant une commande avec argument (style "ls -l") et il l'a exécutée (bon sans activer l'option "-l" mais je pense que c'est juste un réglage).

    PS: inclure les termes "urgence" dans un titre ou le texe est très mal vu. Déjà d'une part tes urgences ne sont pas les notres et d'autres part on part du principe que les profs donnent les TP avec assez de temps pour les faire et donc que s'ils ne sont pas faits dans les temps ce n'est ni la faute du prof ni la notre...

    PS2: tu devrais rajouter char *pt; if ((pt=strchr(saisie, '\n')) != NULL) *pt='\0'; sous ton fgets(saisie, 300, stdin)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Merci, et désolé si j'ai traumatisé mes lecteurs, je n'avais jamais posté avant et j'essayais de faire tout bien tout bien

    Je ne comprends pas à quoi sert le pointeur pt, vu qu'il n'est utilisé nulle part ailleurs dans le code

    Accessoirement, d'autres étudiants qui ont vu mon code le jugent trop compliqué, un avis ?

    P.S. : je cherche un moyen de debugger mon code (tout seul), mais ce que j'ai trouvé jusqu'à maintenant me paraît assez abscons, existe-t-il des outils un peu futés ?

    Merci encore !

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par M3lm4n Voir le message
    Je ne comprends pas à quoi sert le pointeur pt, vu qu'il n'est utilisé nulle part ailleurs dans le code
    Sisi, il est utilisé dans le if qui suit sa définition. Généralement on met ça sur 2 lignes mais j'avais pas envie que mon post soit coupé.
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char *pt;
    if ((pt=strchr(saisie, '\n')) != NULL)
    	*pt='\0';
    Utilisé une seule fois peut-être mais ça oblige quand-même à le définir...

    Citation Envoyé par M3lm4n Voir le message
    Accessoirement, d'autres étudiants qui ont vu mon code le jugent trop compliqué, un avis ?
    Non, moi je le trouve "construit". Bien/pas bien c'est à étudier mais au-moins tu tentes de consacrer une fonction à une action et une action à une fonction et ça c'est bien.
    Question ergonomie c'est un peu brouillon. Par exemple ici
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        	if (path>0)
    	    {
    	        printf("execl\n");
    	        execl (cmde.instruction, cmde.chemin, cmde.argument, NULL);
    	    }
     
    	    else
    	    {
    	        printf("execlp\n");
    	        execlp (cmde.instruction, cmde.argument, NULL);
    	    }
    	    exit(0);
    ton indentation des accolades est "intermédiaire" (moitié tabulation/moitié espaces). Et cette ligne vide au dessus du else !!!
    Un code bien tabulé et bien aéré se lit bien plus facilement...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	if (path > 0)
    	{
    		printf("execl\n");
    		execl(cmde.instruction, cmde.chemin, cmde.argument, NULL);
    	}
    	else
    	{
    		printf("execlp\n");
    		execlp(cmde.instruction, cmde.argument, NULL);
    	}

    Ou bien
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	if (path > 0) {
    		printf("execl\n");
    		execl(cmde.instruction, cmde.chemin, cmde.argument, NULL);
    	}
    	else {
    		printf("execlp\n");
    		execlp(cmde.instruction, cmde.argument, NULL);
    	}
    (moi avant j'écrivais comme la première version et maintenant je préfère la seconde ?!?).

    Et pour les aérations, moi je fais comme ceci
    • pas d'espace pour les affectations
    • pas d'espace entre le nom de la fonction et sa parenthèse ouvrante
    • un espace après un mot clef if/for/while et la parenthèse
    • un espace avant et après l'opérateur de comparaison
    • un espace après la virgule (dans les paramètres de la fonction)

    Ca a l'air compliqué à lire comme ça mais le plus compliqué a été surtout de l'expliquer dans ce post parce qu'au naturel ça vient facilement et ça donne if ((pt=strchr(saisie, '\n')) != NULL) *pt='\0';. Et question "affectation dans la comparaison" (style if ((x=fct(...)) != y)) généralement j'évite sauf si la fonction est vraiment petite à écrire (peu de paramètres) et donc à relire.

    Par ailleurs on ne quitte jamais une fonction via exit(). Si une fonction échoue et qu'on veut le signaler alors on renvoie une valeur spéciale à l'appelant qui la gèrera en conséquence (peut-être que lui-aussi considèrera que c'est majeur et alors lui-aussi renverra une valeur spéciale à son appelant et ainsi de suite jusqu'au main).


    Citation Envoyé par M3lm4n Voir le message
    P.S. : je cherche un moyen de debugger mon code (tout seul), mais ce que j'ai trouvé jusqu'à maintenant me paraît assez abscons, existe-t-il des outils un peu futés ?
    printf(). C'est comme ça que j'ai vu ton souci. J'en ai mis de partout jusqu'à isoler la ligne en erreur puis en affichant les valeurs de cette ligne...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    Pour rebondir sur ce qu'écrit Svear, le choix du style reste subjectif. Ce qui est important est surtout de rester homogène, constant dans l'écriture.

    Des outils comme indent et clang-format peuvent t'aider. J'utilise principalement le second, plus souple qu'indent mais plus complexe à configurer également.

  6. #6
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Sisi, il est utilisé dans le if qui suit sa définition. Généralement on met ça sur 2 lignes mais j'avais pas envie que mon post soit coupé.
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char *pt;
    if ((pt=strchr(saisie, '\n')) != NULL)
    	*pt='\0';
    Utilisé une seule fois peut-être mais ça oblige quand-même à le définir...
    heuuuu... oui mais ça sert a quoi ?

    c'est comme si j'ajoutais une variable x que j'incrémente jusqu'a un certain point sans m'en servir ailleurs

    sinon j'ai modifié mon code et je n'ai plus d'erreur (à part l'absence de prise en compte des paramètres) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
     
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
     
    typedef struct command
    {
        char chemin[256];
        char instruction[128];
        char argument[128];
     
    }command;
     
    void Execution(command cmde, int path)
    {
        pid_t fils;
        printf("\nentrée fonction Execution :\n");
        printf("cmde.instruction : %s\n", cmde.instruction);
        printf("cmde.chemin : %s\n", cmde.chemin);
        printf("cmde.argument : %s\n", cmde.argument);
     
        fils = fork();
        if (fils == 0)
        {
            if (path > 0)
            {
                printf("execl\n");
                execl(cmde.instruction, cmde.chemin, cmde.argument, NULL);
            }
     
            else
            {
                printf("execlp\n");
                execlp(cmde.instruction, cmde.argument, NULL);
            }
        }
    }
     
    void Interpretation(char* saisie)
    {
        int i = strlen(saisie) - 1, path=0, args=0;
        command cmde;
        cmde.argument[0] = '\0';
        char* temp = strtok(saisie, " ");
     
     
     
        strcpy(cmde.instruction, temp);
        printf("temp = %s\n", temp);
        printf("cmde.instruction : %s\n\n", cmde.instruction);
     
        while (i > 0)
        {
            if ((temp = strtok(0, " ")) == NULL)
            {
                i = 0;
            }
     
     
            else
            {
                printf("temp = %s\n", temp);
     
                if ((strchr(temp, '/') != NULL) || (strchr(temp, '.') != NULL))
                {
                    path = 1;
                    strcpy(cmde.chemin, temp);
                    printf("cmde.chemin : %s\n\n", cmde.chemin);
                }
                else
                {
                    if (args > 0)
                    {
                        strcat(cmde.argument, " ");
                    }
     
                    strcat(cmde.argument, temp);
                    args++;
                    printf("cmde.argument : %s\n\n", cmde.argument);
                }
     
                i -= strlen(temp);
            }
        }
     
        Execution(cmde, path);
    }
     
    int main()
    {
        char saisie[1500] = {'\0'};
        command cmde;
        char *pt;
     
        puts("Saisir une commande :");
        fgets(saisie, 300, stdin);
     
        if ((pt = strchr(saisie, '\n')) != NULL)
        {
            *pt = '\0';
        }
     
        strncpy(cmde.chemin, saisie, sizeof(cmde.chemin));
     
        Interpretation(saisie);
     
        return 0;
    }
    Je vais m'atteler à la présentation, par contre les tabulations et les espaces mélangés sont dûs à sublime text, je n'utilise que les tabulations.

    Citation Envoyé par Matt_Houston Voir le message
    Pour rebondir sur ce qu'écrit Svear, le choix du style reste subjectif. Ce qui est important est surtout de rester homogène, constant dans l'écriture.

    Des outils comme indent et clang-format peuvent t'aider. J'utilise principalement le second, plus souple qu'indent mais plus complexe à configurer également.
    Merci, je vais regarder le premier, le deuxième à l'air tendu...

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par M3lm4n Voir le message
    heuuuu... oui mais ça sert a quoi ?

    c'est comme si j'ajoutais une variable x que j'incrémente jusqu'a un certain point sans m'en servir ailleurs
    Tu n'as pas détaillé l'instruction
    1) je positionne un pointeur à un certain endroit
    2) je modifie l'élément pointé !!!
    J'ai donc bien incrémenté une variable et je m'en suis servie...

    Et pour répondre à ta première question, ça sert à supprimer le '\n' (représentant la touche <return> sur laquelle tu tapes pour valider ta saisie) récupéré et stocké par fgets(). C'est très bien d'utiliser fgets(), ça offre un verrouillage concret et efficace de la zone saisie. Mais ça a le petit inconvénient de tout stocker absolument tout ce qui est tapé...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Merci, ça m'a bien aidé.

    Je suis coincé un peu plus loin, j'essaie de faire un prompt un peu sympa, mais jai une erreur de bus sur une fonction strcat() (ligne 133) , je viens d'y passer l'après midi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
     
    typedef struct command
    {
    	char chemin[256];
    	char instruction[128];
    	char argument[128];
     
    }command;
     
    void 
    Execution(command cmde, int path)
    {
    	pid_t		fils;
    	printf("\nentrée fonction Execution :\n\n\n");
    	printf("cmde.instruction : %s\n\n", cmde.instruction);
    	printf("cmde.chemin : %s\n\n", cmde.chemin);
    	printf("cmde.argument : %s\n\n", cmde.argument);
     
    	fils=fork();
    	if (fils == 0)
    	{
    		if (path > 0)
    		{
    			printf("execl\n");
    			execl(cmde.chemin, cmde.instruction, cmde.argument, NULL);
    		}
    		else
    		{
    			printf("execlp\n\n\n");
    			execlp(cmde.instruction, cmde.instruction,cmde.argument, NULL);
    		}
    	}
    }
     
    void Interpretation(char* saisie)
    {
        int path=0, args=0,instruct=0;
        command cmde;
        cmde.argument[0]='\0';
        char* temp=strtok(saisie, " ");
        char* prog=temp;
        char* PID;
     
     
        if((PID=strchr(saisie,'&'))!=NULL)
        {
        	puts(PID);
        	printf("\n\nPid : %d\n\n",getpid());
        	*PID='\0';
        }
     
        do
        {
        	if((prog=strrchr(prog, '/')) != NULL)
    	 	{
    	 		prog++;
    	 		printf("instruction : %s\n",prog);
    	 		path=1;
    	 		instruct=1;
    	 		strcpy(cmde.chemin, temp);
    	        strcpy(cmde.instruction, prog);
    	 	}
    	 	else
    	 	{
    	 		printf("temp 5 : %s\n",temp);
    	 		if(instruct==0)
    		 	{
    		 		printf("temp 4 : %s\n",temp);
    		 		strcpy(cmde.instruction, temp);
    		    	printf("temp = %s\n", temp);
    		    	printf("cmde.instruction : %s\n\n", cmde.instruction);
    		    	instruct=1;
    		 	}
    		 	else
    		 	{
    		 		if (args > 0)
    		        {
    		        	printf("temp %d : %s\n",args+5,temp);
    		            strcat(cmde.argument, " ");
    		        }
     
    			   	strcat(cmde.argument, temp);
    			   	args++;	
    		 	}
    	 	}
     
        }
        while((temp=strtok(0, " ")) != NULL);
     
        printf("cmde.argument : %s\n\n", cmde.argument);
     
        Execution(cmde, path);
    }
     
    void Prompt(char* saisie)
    {
    	int i,j;
    	char *haut, *text, *bas, *tempH, *tempB;
    	char *lapinou[3];
     
    	lapinou[0]="		(\\__/) ||";
    	lapinou[1]="		(•ㅅ•) || ";
    	lapinou[2]="		/   づ";
     
    	i=strlen(saisie);
    	j=i+7;
     
    	haut=(char*) calloc(j, sizeof(char));
    	text=(char*) calloc(i+1, sizeof(char));
    	bas=(char*) calloc(j, sizeof(char));
    	tempH=(char*) calloc(i, sizeof(char));
    	tempB=(char*) calloc(i, sizeof(char));
     
    	haut="		| ̄ ̄";
    	text="		| ";
    	bas="		|__";
     
    	while(i>0)
    	{
    		strcat(tempH," ̄");
    		strcat(tempB,"_");
    		i--;
    	}
     
    puts("1");
    puts(haut);
    puts(tempH);
     
    		strcat(haut,tempH);
    puts("2");
    		strcat(haut, "|");
    		puts("3");
    		strcat(bas,tempB);
    		puts("4");
    		strcat(bas, "|");
    		puts("5");
    		strcat(text, saisie);
    		puts("6");
    		strcat(text, "|");
    		puts("7");
     
     
    	puts(haut);
    	puts(text);
    	puts(bas);
     
    	for(i=0;i<3;i++)
    	{
    		puts(lapinou[i]);
    	}
    }
     
    int 
    main()
    {
    	char saisie[1500] = {'\0'};
    	char *pt;
     
    	puts("Saisir une commande :\n");
    	fgets(saisie, 300, stdin);
     
    	if ((pt=strchr(saisie, '\n')) != NULL) 
    	{
    		*pt = '\0';
    	}
    	Prompt(saisie);
     
    	return 0;
    }

  9. #9
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    Ce motif, que tu utilises à plusieurs reprises, est erroné :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char *s = calloc(100);
    s = "const string";
    strcat(s, "another const string");
    Que penses-tu qu'il se passe ci-dessus ? D'où vient l'erreur ?


    Accessoirement, note qu'il est inutile de préciser sizeof(char) (qui vaut toujours 1) et qu'il ne faut pas cast la valeur de retour des fonctions d'allocation.

  10. #10
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    Accessoirement, note qu'il est inutile de préciser sizeof(char) (qui vaut toujours 1)
    Moi personnellement je le laisserais. Je trouve que ça donne une certaine homogénéité au code
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int *x=malloc(10 * sizeof(int));
    char *y=malloc(10 * sizeof(char));
    Pour le reste je suis d'accord ; surtout sur le cast qui a fait l'objet de nombreux débats avec de très bon arguments pour et d'autres tout aussi bons contre mais où ma préférence va quand-même contre le cast...

    Citation Envoyé par M3lm4n Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
        	if((prog=strrchr(prog, '/')) != NULL)
    	 	{
    	 		prog++;
    	 		printf("instruction : %s\n",prog);
    	 		path=1;
    	 		instruct=1;
    	 		strcpy(cmde.chemin, temp);
    	        strcpy(cmde.instruction, prog);
    	 	}
    	 	else
    	 	{
    	 		printf("temp 5 : %s\n",temp);
    	 		if(instruct==0)
    		 	{
    		 		printf("temp 4 : %s\n",temp);
    		 		strcpy(cmde.instruction, temp);
    		    	printf("temp = %s\n", temp);
    		    	printf("cmde.instruction : %s\n\n", cmde.instruction);
    		    	instruct=1;
    		 	}
    		 	else
    		 	{
    		 		if (args > 0)
    		        {
    		        	printf("temp %d : %s\n",args+5,temp);
    		            strcat(cmde.argument, " ");
    		        }
     
    			   	strcat(cmde.argument, temp);
    			   	args++;	
    		 	}
    	 	}
     
        }
        while((temp=strtok(0, " ")) != NULL);
    Non mais c'est quoi cette indentation de m !!! Comment tu peux te relire avec ça ? Comment tu veux que d'autres te lisent avec ça ??????
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char *s = calloc(100);
    s = "const string";
    strcat(s, "another const string");
    Que penses-tu qu'il se passe ci-dessus ? D'où vient l'erreur ?
    on déclare un pointeur sur une chaîne de caractères dont les 100 premiers éléments sont vides, on stocke une chaine dans le tableau de char et on la concatène avec une deuxième chaine...

    mais apparemment c'est pas bon...

  12. #12
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Non mais c'est quoi cette indentation de m !!! Comment tu peux te relire avec ça ? Comment tu veux que d'autres te lisent avec ça ??????
    ça ne donne pas ça chez moi

    Nom : Capture d’écran 2018-05-09 à 15.32.08.png
Affichages : 292
Taille : 529,9 Ko

  13. #13
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par M3lm4n Voir le message
    mais apparemment c'est pas bon...
    Ben dans la mesure où tu écris s=truc puis sur la ligne du dessous tu écris s=autre_truc tu devrais sentir tout seul (rien qu'avec le plus élémentaire "bon sens") qu'il y a quelque chose qui ne va pas...

    Citation Envoyé par M3lm4n Voir le message
    on déclare un pointeur sur une chaîne de caractères dont les 100 premiers éléments sont vides,
    Ils ne sont pas vides, ils sont remplis de "0". Or "0" c'est quand-même quelque chose.

    Plus généralement, en informatique une variable ne peut jamais être "vide".

    Mais bon, là c'est juste qu'une question de vocabulaire.

    Citation Envoyé par M3lm4n Voir le message
    on stocke une chaine dans le tableau de char
    Et c'est comme ça qu'on t'a appris à stocker une chaine dans un tableau de char en C ???
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  14. #14
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Ben dans la mesure où tu écris s=truc puis sur la ligne du dessous tu écris s=autre_truc tu derais sentir tout seul qu'il y a quelque chose qui ne va pas...
    Je ne suis pas encore bien à l'aise avec les pointeurs, mais il me semblait que *s et s étaient 2 choses différentes (adresse et contenu ?)


    Citation Envoyé par Sve@r Voir le message
    Ils ne sont pas vides, ils sont remplis de "0". Or "0" c'est quand-même quelque chose.

    Plus généralement, en informatique une variable ne peut jamais être "vide"
    Mea culpa, j'ai mal choisi mes mots

    Citation Envoyé par Sve@r Voir le message
    Et c'est comme ça qu'on t'a appris à stocker une chaine dans un tableau de char en C ???
    Heuuu non, mais comme un tableau est un pointeur... je me suis dis...

    Donc je dois déclarer un tableau avant et faire mon calloc ensuite ?

    Ce qui est bizarre, c'est que ça fonctionne pour haut, bas et text et c'est au moment de strcat que ça ne va plus

  15. #15
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par M3lm4n Voir le message
    Je ne suis pas encore bien à l'aise avec les pointeurs, mais il me semblait que *s et s étaient 2 choses différentes (adresse et contenu ?)
    Alors c'est vrai.
    Mais quand tu écris char *s=calloc(...) c'est comme si tu écrivais char *s; s=calloc(...). Bref quand tu déclares un pointeur en y rajoutant une affectation, l'affectation se fait sur le pointeur et non le pointé.


    Citation Envoyé par M3lm4n Voir le message
    Heuuu non, mais comme un tableau est un pointeur...
    Je pense que tu fais référence à l'instruction char tab[]="Bonjour". Il s'agit ici d'un raccourci syntaxique. La déclaration du tableau est la seule et unique occasion qui te permette de le remplir via le signe "=".
    Si maintenant tu écris char tab[10];, tu ne peux plus remplir "tab" avec "=". Il te faut le remplir élément par élément (tab[0]=...; tab[1]=...; tab[2]=...; etc).
    Et donc même si un tableau est assimilable à un pointeur, tu ne peux pas remplir ton pointeur avec "=" (enfin le remplir d'un coup je veux dire)

    Citation Envoyé par M3lm4n Voir le message
    Donc je dois déclarer un tableau avant et faire mon calloc ensuite ?
    Non, jusqu'au calloc c'était bien. C'est ta façon de stocker ta chaine dans la zone allouée qui n'est pas bonne. Il te suffit de considérer "s" comme un tableau de caractères et de te souvenir comment on remplis un tableau de caractères...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  16. #16
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Non, jusqu'au calloc c'était bien. C'est ta façon de stocker ta chaine dans la zone allouée qui n'est pas bonne. Il te suffit de considérer "s" comme un tableau de caractères et de te souvenir comment on remplis un tableau de caractères...
    Merci pour ton temps et désolé d'être balourd, mais je ne comprends pas.

    quand j'affiche les différentes variables, tout est bon :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    	haut=(char*) calloc(j, sizeof(char));
    	text=(char*) calloc(i+1, sizeof(char));
    	bas=(char*) calloc(j, sizeof(char));
    	tempH=(char*) calloc(i, sizeof(char));
    	tempB=(char*) calloc(i, sizeof(char));
     
    	haut="		| ̄ ̄";
    	text="		| ";
    	bas="		|__";
     
    	while(i>0)
    	{
    		strcat(tempH," ̄");
    		strcat(tempB,"_");
    		i--;
    	}
    c'est à partir de que ça ne fonctionne plus (et il n'y a pas de "=").

    Du coup, quelle est la différence entre mes chaines qui fonctionnent et celles qui ne fonctionnent pas ?

  17. #17
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par M3lm4n Voir le message
    Merci pour ton temps et désolé d'être balourd, mais je ne comprends pas.

    quand j'affiche les différentes variables, tout est bon :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	haut=(char*) calloc(j, sizeof(char));
    	haut="		| ̄ ̄";
    Si tu avais écrit
    Tu ne t'interrogerais pas sur ta logique ? Pourquoi y mettre "100" si on y met ensuite "200" ???

    Ben là c'est pareil. Tu remplis "haut" avec quelque chose puis tu le remplis avec autre chose. Fatalement ce que tu y as mis au début est perdu.
    Donc la première ligne (le calloc) est bonne. Si la première n'existait pas, la seconde serait tout aussi correcte mais en l'état, elle ne l'est plus. Donc elle ne convient pas et doit être changée. Reprend les bases et, en te souvenant que "haut" est assimilable à un tableau de caractères (ou une chaine si tu préfères). Comment on remplit une chaine ??? Je sais que tu connais l'instruction car je l'ai déjà vue dans ton code...

    Citation Envoyé par M3lm4n Voir le message
    c'est à partir de que ça ne fonctionne plus (et il n'y a pas de "=").
    Le "=" se trouve sur la ligne d'avant (celle que j'ai montrée)

    Citation Envoyé par M3lm4n Voir le message
    Du coup, quelle est la différence entre mes chaines qui fonctionnent et celles qui ne fonctionnent pas ?
    Quand tu auras corrigé, je t'expliquerai...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  18. #18
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    Je vais rebondir sur tes réponses et tâcher de détailler (et accessoirement corriger mon appel à calloc qui attend deux paramètres.. je n'utilise pratiquement jamais cette fonction). Il y a plusieurs erreurs distinctes parmi ces trois lignes.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char *s = calloc(100, 1);
    Citation Envoyé par M3lm4n Voir le message
    on déclare un pointeur sur une chaîne de caractères dont les 100 premiers éléments sont vides
    On va préciser tout cela car c'est un peu confus et en partie inexact.

    Une chaîne de caractères en C, c'est une et une seule chose : une séquence d'un ou plusieurs bytes (octets) terminée par (incluant, donc) (char)'\0'. En conséquence, il s'agit d'un état muable, pas d'un type figé. Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    char s[] = "str";
    // ici, s pointe sur une chaîne de caractères contenant 's', 't', 'r' et '\0'
    ++s[3]; // on modifie la valeur du marqueur de fin de chaîne
    // ici, s ne pointe PLUS sur une chaîne de caractères !
    s[0] = 0; // rappel : '\0' == 0
    // ici, s pointe à nouveau sur une chaîne de caractères contenant '\0'
    Bien entendu, on a tout le temps recours aux abus de langage lorsque l'on écrit que s est une chaîne de caractères, que l'on déclare une chaîne, que la fonction attend une chaîne.. Mais on ne peut utiliser ces raccourcis qu'à partir du moment où l'on sait de quoi on cause.


    Bref, ici on déclare un pointeur de type char * que l'on initialise à - sous réserve que calloc ne retourne pas NULL - l'adresse du premier byte d'une zone mémoire qui en contient cent. Du fait que calloc initialise à zéro la séquence dont elle renvoie l'adresse, il se trouve également que s pointe sur une chaîne de caractères dont le premier byte vaut zéro. Donc une chaîne vide, ou de longueur zéro. Attention : on ne compte pas le byte terminal lorsque l'on parle de longueur d'une chaîne de caractères, mais celui-ci fait toutefois bien partie de la chaîne puisqu'il conditionne son existence.


    Citation Envoyé par M3lm4n Voir le message
    on stocke une chaine dans le tableau de char
    Non, ne serait-ce que parce qu'on ne copie pas les chaînes de caractères de cette façon ! Et ça c'est dans le cours donc .

    Mais - et c'est un piège du C - cette ligne n'en est pas moins parfaitement valide. Il se passe quelque chose ici, même si ça ne correspond pas au comportement que tu souhaitais mettre en œuvre. L'adresse de la chaîne constante (string literal) "const string" est placée dans s. Cette adresse indique une zone située quelque part dans le segment de données de ton programme. Le contenu de la première zone mémoire de cent bytes pointée précédemment n'est pas modifié. Son adresse ayant été écrasée par l'affectation, cette zone allouée dynamiquement est perdue car elle ne peut plus être libérée via free ; il s'agit d'une fuite mémoire.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    strcat(s, "another const string");
    Citation Envoyé par M3lm4n Voir le message
    et on la concatène avec une deuxième chaine...
    C'est en effet ce que l'on tente de faire. strcat prend l'adresse de la chaîne non constante (adresse contenue dans s), l'adresse de la chaîne constante "another const string" et mouline. Et pourtant ça ne fonctionne pas, pour deux raisons principalement :

    • la zone mémoire indiquée par s dispose d'une taille insuffisante. Souviens-toi, cette zone qui contient "const string" est bien distincte de la zone de cent bytes allouée via calloc, et seulement aussi grande que nécessaire pour stocker "const string". Donc dès qu'on tente d'écrire quelque chose derrière, boum : comportement indéterminé.
    • mais surtout et bien plus sournois : s pointe en réalité sur une chaîne constante, au sens de « en dur » (literal en anglais). Souviens-toi, je l'ai écrit au-dessus ! Cette chaîne constante se situe dans le segment de données de ton programme et même si ce segment n'est pas forcément en lecture seule, le C interdit de modifier une telle chaîne. Passe par exemple l'adresse d'une chaîne constante en premier argument (non constant) de strcpy ou strcat et boum : comportement indéterminé.


    Une question reste en suspend : pourquoi le compilateur ne t'en a pas averti ? Parce qu'en C, pour des raisons obscures, le type des adresses de chaînes constantes est char * et pas const char *. Pour GCC et clang, il existe l'option -Wwrite-strings qui pallie cette singularité et permet de détecter ce genre d'erreur. Avec cette option, le compilateur nous aurait signalé que l'on demande à mettre une adresse de type const char * dans un pointeur de type char * à la ligne 2.


    Plus généralement, pour avoir moins de surprises et prendre de bonnes habitudes, demande à ton compilateur (ici GCC) :

    • un respect strict de la norme : -std=c11 -pedantic ;
    • la plupart des avertissements : -Wall -Wextra auxquel il convient pour toi d'ajouter -Wwrite-strings donc, et peut-être -Wconversion ;
    • le surclassement des avertissements en erreurs, pour que la compilation soit stoppée lorsqu'ils surviennent : -Werror, à employer judicieusement.

  19. #19
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Si tu avais écrit
    Tu ne t'interrogerais pas sur ta logique ? Pourquoi y mettre "100" si on y met ensuite "200" ???
    Je n'avais pas compris que malloc/calloc/realloc était considérés comme des affectations.
    Il me semblait qu'il s'agissait de la (re)définition de la taille d'un tableau.

    Citation Envoyé par Sve@r Voir le message
    Le "=" se trouve sur la ligne d'avant (celle que j'ai montrée)
    et je suis un idiot...

    ma tête est dure, désolé. du coup un strcat() devrait faire l'affaire...

    je me retrouve à nouveau avec un segmentation fault (ça fait 6 heure que je teste toutes les combinaisons possible et qui me paraîtraient logiques, mais apparement gcc n'a pas la même logique que moi

  20. #20
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2018
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2018
    Messages : 17
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    Une question reste en suspend : pourquoi le compilateur ne t'en a pas averti ?
    jusqu'a maintenant j'utilisais -Wall -Wextra -Werror --std=c99.

    Je ne comprends pas le principe de "const string", quelle difference entre une variable et une variable... constante

    (j'ai déjà croisé ça dans le manuel sans comprendre), tout comme const char *

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [Développement] besoin d'aide en shell
    Par kissakissa dans le forum AppleScript
    Réponses: 1
    Dernier message: 14/04/2016, 06h53
  2. Besoin d'aide commandes shell administration serveur linux
    Par SEIYA. dans le forum Shell et commandes GNU
    Réponses: 4
    Dernier message: 10/03/2015, 17h17
  3. Besoin d'aide : commande shell
    Par HDI103 dans le forum Shell et commandes GNU
    Réponses: 32
    Dernier message: 30/05/2013, 20h06
  4. Besoin d'aide au niveau de Shell
    Par Argael dans le forum Shell et commandes GNU
    Réponses: 1
    Dernier message: 01/08/2006, 11h04
  5. Besoin d'aide pour un script shell
    Par lecharcutierdelinux dans le forum Linux
    Réponses: 5
    Dernier message: 20/05/2006, 10h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo