Bonjour, j'ai actuellement un soucis avec un programme en c que j'essaie de coder. Le but de ce programme dans l'état actuel est de récupérer une chaine de chaine de caractère puis de l'afficher
Voici le code en question :
int main () {
int ret, cpt=0, cpt2=0;
char c;
char *demande="Veuillez saisir la commande à exécuter : ";
char mot[20];
char *commande[10];
write(1, demande, strlen(demande));
ret=read(0, &c,1);
while (ret == 1) {
if (c == ' ') {
mot[cpt]='\0';
strcpy(commande[cpt2],mot);
cpt=0;
cpt2++;
}
else {
mot[cpt]=c;
cpt++;
}
ret=read(0, &c,1); }
write (1, commande[0], strlen (commande[0]));
exit (0);
}
Donc voila quant j'essaie de l'éxécuter, j'obtient une belle boucle infini. Je pense que le problème doit être tout bête mais je vois vraiment pas d'où il pourrait venir.
Je vous remercie d'avance pour votre aide et vous souhaite une bonne journée. ![]()
Explique nous ce qu'est censé faire ton programme au moins?
Il ne suffit pas de mettre un bout de code avec "ca ne amrche pas " pour avoir des réponses pertinente...
On fait ca seulement si le programme est très bien commenté et que les variables sont explicite ce qui n'est pas trop le cas ici.
Eclaire moi pour que je puisse t'eclaire ![]()
Oups désolé, ma phrase peut être mal interprete.
Quand je disais :Explique nous ce qu'est censé faire ton programme au moins? je voulais dire, explique nous les mécanismes du programme, les fonctions que tu as le droit d'utiliser et celle que tu n'as pas le droit d'utiliser.
Parce que dans le fond, c'est assez simple de recuperer une chaine de caractere et de l'afficher.
Le but de mon programme est de réaliser un mini shell.
Donc voici mon résonnement :
Je demande à l'utilisateur de saisir une commande simple (du style ls -l). Le programme lit ensuite la saisie de l'utilisateur caractère par caractère. Dès lors qu'un nouveau mot est rencontré (le caractère lu est alors un espace), on envoit le mot stocké dans mon tableau 1D dans mon tableau de string.
Voila en gros. ![]()
A la fin du traitement j'essaie ensuite d'afficher le tableau de string. ![]()
A première vue c'est normal qu'il y ai une boucle infinie puisque tu lit sur STDIN_FILENO, essaie de faire un Ctrl-D pour lui indiquer un symbole EOF.
Et ta variable commande m'a l'air bien suspecte, tu l'utilise comme un tableau de tableau mais seule commande[0] est utilisable car les autres cases ne sont pas allouées, et si un mot de plus de 9 lettres est entrées ça va faire des trucs étranges.
As-tu certaines bibliothèque interdites ou peut-tu utiliser ce que tu veux, voire du C++? Je t'aiderai bien mais faut que je connaisse tes outils.
Euh non je ne peux pas utiliser de c++ dans ce programme. En ce qui concerne les librairies, je peux utiliser les librairies de base offertes par un système linux. ![]()
Pourquoi déclare tu ton tableau comme ceci : char *commande[10]; sans allouer l'espace mémoire ?
Soit tu fais comme ca :"char* commande[10][20] par exemple (10 mots de 20 caractères) soit tu alloues pour chaque case un espace memoire :
comme ceci : int i = 0 ; for(i=0; i<9;i++) commande[i] = malloc(SIZE*sizeof(char)) ;
Bon maintenant que j'ai un peu plus compris ce que tu désire faire, je vais jetter un oeil. En tout cas, à première vu sur le code, tu te prends beaucoup la tête :P
C'est bon j'ai reussi à régler mon problème. Je te remercie de ton aide et te souhaite une bonne soirée. ![]()
Si tu peux utiliser la lib C, tu devrai:
1)arrêter d'utiliser write pour écrire sur stdout et utiliser printf
2)utiliser malloc pour allouer dynamiquement tes chaines de caractères, le mieux est que tu te code une bibliothèque de listes chainées et de chaines variables mais si veux rester simple et que tu considères que l'utilisateur ne dépassera jamais 5 mots de 9 lettres par exemple, déclare commande comme ça:
char commande[5][10];
Un nouveau problème se présente : la phase exec.
Donc voici mon code :
int main () {
int ret, cpt=0, cpt2=0, cpt3=0;
char c;
pid_t idproc;
char *demande="Veuillez saisir la commande à exécuter : ";
char *err="Erreur ! Fork échoué \n";
char *err2="Erreur ! Exec échoué \n";
char commande[20][20];
write(1, demande, strlen(demande));
ret=read(0, &c,1);
while (ret == 1) {
if (c == ' ') {
commande[cpt][cpt2]='\0';
cpt=cpt++;
cpt2=0;
}
else {
commande[cpt][cpt2]=c;
cpt2++;
}
ret=read(0, &c,1); }
cpt++;
commande[cpt][0]='N';
commande[cpt][1]='U';
commande[cpt][2]='L';
commande[cpt][3]='L';
commande[cpt][4]='\0';
write (1, "\n", 1);
while (cpt3<=cpt) {
write (1, commande[cpt3], strlen (commande[cpt3]));
write (1, "\n", 1);
cpt3++;
}
idproc=fork();
if (idproc == -1) {
write(2, err, strlen(err));
exit (1);
}
if (idproc == 0) {
execv (commande[0], commande);
write(2, err2, strlen(err2));
exit (2);
}
wait(NULL);
exit (0);
}
J'explique ce mon programme est sensé faire maintenant. Le programme demande à l'utilisateur de saisir une commande. Des lors que la fin de la saisie est annoncée par l'utilisateur(via ctrl-d), le programme lit la commande caractère par caractère afin de pouvoir l'exploiter plus tard dans un execv. Pour cela, je crée un tableau de string qui met dans chaque ligne un mot de la commande. Après avoir lu la commande dans sa totalité, j'ajoute une dernière ligne à mon tableau : NULL afin de lancer correctement le execv qui suit.
Seulement le execv n'accepte pas ma synthaxe et lors de la compilation, j'obtiens le message d'erreur suivant :
mini_shell.c: In function ‘main’:
mini_shell.c:72:1: warning: passing argument 2 of ‘execv’ from incompatible pointer type
/usr/include/unistd.h:560:12: note: expected ‘char * const*’ but argument is of type ‘char (*)[20]’
Je vous remercie de votre aide et vous souhaite une bonne journée. ![]()
Très simple, il suffit de regarder le prototype de execv :
int execv(const char *path, char *const argv[]);
Premier paramètre, un pointeur sur char, tu l'as bien respecté.
Deuxième paramètre, un tableau de pointeur.
Or commande n'est pas un tableau de pointeur mais un tableau 2D.
Il aurait fallut déclarer commande comme ca :
char *commande[20];
for(i=0 ; i<20 ; i++) { commande[i] = malloc(sizeof(char)) ; }
Pour que ca compile.
Ne pas oublier de mettre la taille de chaque pointeur en facteur de sizeof(char), chose que je n'ai pas fait.
Et un petit conseil, quand tu utilises des fork(), mieux vaut structurer ton programme à l'aide de switch.
Beaucoup plus lisible que des if.
Egalement, pout tester les codes d'erreur, utilise perror mince alors !
Tu as des outils, c'est pour les utiliser. La variable ernno initialise automatique le message d'erreur, et la cible de facon fiable à la place d'utiliser toujours la même erreur "exec a echoué" et ensuite, pour debugger, tu te met à mettre des printfs partout pour localiser l'endroit où ca a planté...
Je te remercie de ton aide. Je vais tenir compte de tes conseils. ![]()
Très heureux de t'avoir aidé.
Up ce topic si tu as d'autres problèmes. J'essaierai de passer pour voir de temps en temps ![]()
J'ai une nouvelle fois besoin de ton aide.
Voici la dernière version de mon code :
int main () {
int ret, cpt=0, cpt2=0, cpt3=0, i;
char c;
pid_t idproc;
char *demande="Veuillez saisir la commande à exécuter : ";
char *err="Erreur ! Fork échoué \n";
char *err2="Erreur ! Exec échoué \n";
char *commande[20];
char mot[20];
for( i=0 ; i<20 ; i++)
commande[i] = malloc(sizeof(20));
write(1, demande, strlen(demande));
ret=read(0, &c,1);
while (ret == 1) {
if (c == ' ') {
mot[cpt2]='\0';
strcpy(commande[cpt], mot);
cpt++;
cpt2=0;
}
else {
mot[cpt2]=c;
cpt2++;
}
ret=read(0, &c,1); }
if (c != ' ') {
mot[cpt2]='\0';
strcpy(commande[cpt], mot);
}
while (cpt3<=cpt) {
write (1, commande[cpt3], strlen (commande[cpt3]));
write (1, "\n", 1);
cpt3++;
}
idproc=fork();
if (idproc == -1) {
write(2, err, strlen(err));
exit (1);
}
if (idproc == 0) {
execvp (commande[0], commande);
write(2, err2, strlen(err2));
exit (2);
}
wait(NULL);
exit (0);
}
Tout passe correctement sauf les paramètres !
Par exemple j'essaie de tapper la commande suivante : gedit test.c et bien la commande est bien réalisée mais elle tente également de m'ouvrir mon répertoire personnel. La commande ls me dit que mes paramètres sont inconnus (ls -l par exemple) ou que le répertoire demandé n'a pas été trouvé (ls / par exemple).
J'avais placé un NULL dans la dernière ligne de mon tableau mais gedit m'ouvrait un fichier appelé NULL en plus donc je l'ai enlevé pour le moment. ![]()
En fait tu dois donner le nom du fichier contenant le programme à exécuter et pas juste la commande, par exemple si ls est dans /bin/ls alors ton tableau doit être {"/bin/ls", "args1", NULL}.
Il faut donc que tu résolves les noms des programmes que l'utilisateur te demande en utilisant les variables d'environnement (getenv il me semble...) ou, plus bourrin, en la donnant en dur(strcpy(commande[0], chemin_binaires) au début puis strcpy(commande[0], mot) au moment où tu le copies).
Et remet le NULL à la fin du tableau, il y en a besoin.
Je me suis rendu compte du problème lié à NULL. Je le posais en chaine de caractère dans mon tableau ce qui n'est pas du tout son but.
Sinon hyrulink2, j'utilise avec la commande execvp le path donc je n'ai pas besoin de mettre le chemin complet non ? ![]()