je cherche à faire une boucle récursive qui liste le contenu des répertoires et des sous-répertoires et qui écrit la liste des fichiers (nom complet avec le chemin) dans un fichier texte.
Le fichier texte est créé mais rien n'est écrit dedans. Je manque de maitrise des pointer et je suppose que c'en est la cause...
Le main.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/stat.h>
#include "fonctions.h"
#ifndef WIN32
#include <sys/types.h>
#endif
int main(void)
{
// selectionner le répertoire et enregistrer son chemin dans file :
char file[256] = "E:\Test";
// Parcourir les repertoires et recuperer le chemin complet du repertoire en cours d'analyse
int loopCount = 0;
char nameDirImageFiles[10000];
handling(file, loopCount, nameDirImageFiles);
return 0;
}
Le fonctions.h
void handling(char *file, int loopCount, char *nameDirImageFiles);
int is_dir(char *file);
Le fonctions.c
#include <stdlib.h> // Pour exit()
#include <stdio.h> // Pour puts()
#include <string.h> // Pour les fonctions sur les chaines
#include <stdbool.h>
#include <dirent.h> // Pour l'utilisation des dossiers
#include <unistd.h>
#include <sys/stat.h>
#include "fonctions.h"
// Si ce n'est pas un systeme windows:
#ifndef WIN32
#include <sys/types.h>
#endif
// Fonction qui boucle sur les répertoires et fais une liste des fichiers qu'ils contiennent
void handling(char *file, int loopCount, char *nameDirImageFiles)
{
struct dirent *lecture;
DIR* openedDirectory = NULL;
openedDirectory = opendir(file); // Ouverture d'un dossier
if (openedDirectory == NULL)// Si le dossier n'a pas pu être ouvert
{
printf("Le dossier %s n'existe pas\n", file);
perror(""); // perror() va nous écrire l'erreur.
exit(1);
}
//puts("Le dossier a ete ouvert avec succes\n");
lecture = readdir(openedDirectory);
char chemin_temp[500] = "";
/* On effectue une boucle sur l'ensemble des éléments du dossier en cours
sauf si le premier élément était un fichier (on a alors mis un drapeau à 1)*/
while ((lecture = readdir(openedDirectory)) != NULL)
{
// On écarte les deux premiers éléments d'un dossier Windows
if (strcmp(lecture->d_name, "." ) != 0 && strcmp(lecture->d_name, ".." ) != 0)
{
sprintf(chemin_temp, "%s\\%s", file, lecture->d_name);
// Si l'élément est un dossier, on effectue une boucle récursive
if( is_dir(chemin_temp) == 1)
{
loopCount++; // Avant d'entrer dans la boucle, j'incrémente le compteur
handling(chemin_temp, loopCount, nameDirImageFiles);
loopCount--; // En sortant de la boucle, je décrémente? le compteur
}
else
{
// Enregistrer le nom complet (dossier + chemin) dans un tableau de chaine avec le numéro de la boucle comme indice
nameDirImageFiles[loopCount] = *file;
//printf("nameDirImageFiles%d = %s\n", loopCount, nameDirImageFiles[loopCount]); // Console : warning: format '%s' expects argument of type 'char *', but argument 3 has type 'int' [-Wformat=]|
printf("nameDirImageFiles%d = %s\n", loopCount, &nameDirImageFiles[loopCount]); // affiche : nameDirImageFiles3 = E
// On enregistre le nom + chemin dans un journal
// Ouvrir le fichier log
FILE *f;
//char fichierDest[256] = "E:\\Test";
f = fopen("E:\\Test\\log.txt", "a");
if(f == NULL){
printf("Erreur lors de l'ouverture du fichier");
exit(1);
}
// Ecrire nameDirImageFiles[loopCount] dans le fichier log
fputs(nameDirImageFiles[loopCount],f); // Console : warning: passing argument 1 of 'fputs' makes pointer from integer without a cast [-Wint-conversion]|
fputc('\n', f);
fclose(f);
}
}
}
}
// Fonction qui vérifie si l'élément est un dossier
int is_dir(char *file)
{
DIR *is_folder = NULL;
is_folder = opendir(file);
if (is_folder != NULL)
{
// C'est un dossier
closedir(is_folder);
return 1;
}
else
{
// Ce n'est pas un dossier
return 0;
}
}
Qui voit où ça coince ? Les messages d'erreur de la console "Build messages" sont lignes 54 et 68.
Le résultat du printf ligne 55 affiche nameDirImageFiles3 = E Pourquoi "E" ? c'est le premier caractère du chemin, le deuxième est ":". J'ai pensé que c'était un caractère spécial qu'il fallait échapper, j'ai essayé, ça n'a rien donné...
Je précise que ce code est une partie que j'ai réécrite en supprimant des éléments qui fonctionnent correctement pour ne garder que l'essentiel qui pose problème et j'ai besoin de compter les boucles pour utiliser le reste...
nameDirImageFiles est un pointeur sur un tableau de char, donc nameDirImageFiles[n] est un char, or fputs attends l'adresse d'une chaîne de caractère soit l'adresse d'un tableau de char (char*) or toi, tu lui envois un char !
Non. A ma connaissance, au niveau des chaines de caractères, seuls \ et " doivent être échappés pour que ça produise \ ou " . Et pour tester le caractère ' , il faut écrire '\''.
- Edité par edgarjacobs 28 mars 2021 à 22:52:37
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
tu essayes de faire tomber ton programme en marche ?
Si tu changes le type d'un argument alors il faut évidemment changer le type du paramètre dans la fonction …
Ta fonction attend un char* et tu lui files un char *[] → normal que le compilo râle.
Du plus, si j'étais toi, j'éviterai d'ouvrir un stream dans la fonction, je le passerai en paramètre. Si tu comptes faire des appels récursifs, comment vas-tu savoir où écrire dans le tableau de chaînes ?
Ne serait-il pas plus judicieux dans un premier temps d'implémenter ou une liste de chaîne ou un tableau de chaîne à croissance dynamique. D'ailleurs quel est l'intérêt d'avoir et la liste et le fichier comme paramètres ?
De plus la ligne 68 me laisse penser que tu cherches plus à créer une structure d'arbre qu'une structure de liste … me trompe-je ?
Que veux-tu faire exactement ? Ta fonction doit-elle à partir d'un partir d'un paramètre chemin :
écrire dans un fichier chaque chemin complet des fichiers rencontrés sur un ligne ;
écrire dans un fichier chaque nom de fichier rencontré en les regroupant par répertoire (genre ls -lR);
créer un tableau contenant chaque chemin de fichiers ?
créer une structure reflétant fidèlement la structure des répertoires et des fichiers ?
seras-tu amené à faire des tris (par exemple) pour avoir différentes sorties ?
Plus ça va, plus j'ai essayé des trucs et je m'embrouille, j'ai l'impression de ne plus rien comprendre aux pointeurs...
Que veux tu dire par "j'éviterai d'ouvrir un stream dans la fonction" ? Tu parles de l'opendir() ? de readdir() ? de fopen() ? des trois ? J'ai essayé un moment donné de mettre opendir() à part dans une autre fonction, mais je n'ai pas réussi à le faire fonctionner.
"Ne serait-il pas plus judicieux dans un premier temps d'implémenter ou une liste de chaîne ou un tableau de chaîne à croissance dynamique." Je ne sais pas. Je suis à la moitié du cours "apprenez à programmer en C", je fais avec les connaissances acquises jusque là. Je ne sais pas ce que c'est qu'une liste de chaine ni un tableau de chaine à croissance dynamique...
Je cherche à : explorer dossiers et sous dossiers, à chaque fois que j'ouvre un nouveau dossier, par une boucle récursive, je compte le nombre de boucle et j'enregistre dans un tableau de chaine le numéro de la boucle et le nom du dossier correspondant (le nom complet avec son chemin). Après avoir parcouru tous les éléments du dossier, je le ferme et je remonte dans la boucle de niveau supérieur, je décompte donc le numéro de boucle.
Peut importe que cela ne serve à rien, c'est un défi que je me lance, je mets en pratique ce que j'apprends, dans mon propre exercice, et lorsque je patine, ça m'éclaire sur ce que je n'ai pas compris. Ça me permet de progresser efficacement.
Je ne suis pas professionnel, l'objectif n'est donc pas de faire fonctionner le code, mais de comprendre pourquoi le code que j'ai produit ne fonctionne pas, ce qui doit aboutir au même résultat : un code qui fonctionne... Comme dit le sage, l'important n'est pas la destination mais le chemin que l'on prend pour s'y rendre !
c'est censé être mon tableau de chaines que j'ai déclaré et dimensionné juste avant, et je l'envoie en entier comme paramètre à la fonction handling(). Que dois-je mettre entre ces fuc[....] crochets capitaine ?
Tu n'as pas assimilé tout ces concept tableaux, pointeurs, chaînes de caractère ! Tu devrais revoir tout cela !
Quand on envois un tableau à une fonction en fait on envois son adresse, car on ne peut pas envoyer un tableau à une fonction ! Et dans ce cas on ne met que le nom du tableau, les crochets n'on rien à faire là (on a à faire à un appel de fonction). Si tu veux envoyer un élément du tableau tu met les crochets, mais avec l'indice de l'élément.
Tu fais de multiples essais sans vraiment savoir ce que tu fais, tu pourrais arriver à force d'essais à un code qui compile, mais nous revenir avec une erreur de segmentation qui sera encore plus difficile à cerner !
Pour en revenir à ton tableau que tu déclares actuellement comme ceci :
char *nameDirImageFiles[10000];
C'est un tableau de pointeur sur char. il contient donc 10000 pointeur sur char non initialisé. Il peux servir à pointer de simple char, ou des tableaux de char, ou des chaînes de caractère.
Ton but, est de faire pointer tout ses pointeurs sur des chaînes de caractère, il va donc falloir créer ces chaînes de caractère les remplir et faire pointer tes pointeurs dessus !
c'est censé être mon tableau de chaines que j'ai déclaré et dimensionné juste avant, et je l'envoie en entier comme paramètre à la fonction handling(). Que dois-je mettre entre ces fuc[....] crochets capitaine ?
Si tu envoies tout le tableau dans la fonction, il faut juste indiquer son nom, sans les crochets. On met des crochets pour indiquer un élément du tableau. (Du coup ça m'a trompé, et je crois que ça a trompé aussi le compilateur )
Tu disais au début ne pas bien maîtriser les pointeurs. Dans ce cas, fais comme moi, ne les utilise pas si ce n'est pas indispensable. Par exemple tu lis des noms de fichiers. Ces noms ont-ils une taille maximale ? Il me semble que sous Unix, oui : c'est 255 caractères maxi y compris avec le chemin, ou quelque chose de ce genre (on doit trouver l'information facilement). Sous Windows je ne sais pas, mais je ne serais pas étonné qu'il y ait une limite.
Si oui, ça simplifierait les choses : tu déclares un type 'nom_de_fichier' (nom à adapter), qui est un char[256] (si le maximum est bien 255), et ensuite tu déclares un tableau de 10000 'nom_de_fichier'. Un peu comme ce que tu as fait au tout début :
char nameDirImageFiles[10000];
mais en remplaçant 'char' par le bon type ('nom_de_fichier'). Pas besoin de pointeurs, ce sont des tableaux statiques tout bêtes.
"Tu disais au début ne pas bien maîtriser les pointeurs. Dans ce cas, fais comme moi, ne les utilise pas si ce n'est pas indispensable."
Le but étant d'apprendre à les utiliser, on peut considérer que c'est indispensable, je vais donc continuer à m'entêter...
char *nameDirImageFiles[10000];
"C'est un tableau de pointeur sur char. il contient donc 10000 pointeur sur char non initialisé. Il peux servir à pointer de simple char, ou des tableaux de char, ou des chaînes de caractère."
Bon, vu que je veux pointer un tableau de chaines, est-ce que je peux en conclure que cette ligne-ci est ok ?
Il faut, je pense, procéder dans l'autre sens, c'est-à-dire ne pas essayer de trouver par tâtonnements ce qui pourrait convenir.
Tu veux quoi ?
Un tableau qui contient comme éléments des chaînes de caractères. La mémoire pour ces chaînes de caractères sera allouée dynamiquement car leur longueur (donc leur taille mais ce n'est pas la même chose) est variable.
Tu ne sais pas a priori combien de chaînes tu auras. Ici pour simplifier on va faire un tableau surdimensionné. Le souci est qu'il va falloir un mécanisme pour indiquer où se trouve le dernier élément.
Ici tu remarques que pour ce que tu veux faire tu vas avoir besoin d'un peu plus que d'un tableau : il te faut en plus un indicateur de fin.
Mais comme ces deux objets sont indissociables l'un de l'autre on va les agréger, les agglutiner dans un seul type → on va faire une struct !
Ce type représente une liste de chaînes, on pourrait donc imaginer quelque chose comme :
Maintenant que tu as un type de donné tu peux commencer à créer les primitives de ce type. Ce sont les fonctions qui permettent d'initialiser, construire, détruire, manipuler et interroger les objets de ce type. On pourra très classiquement avoir :
// création de liste vide
t_string_list *string_list_new(void);
// destruction de la liste
void string_)list_delete( t_string_list * );
// interrogation sur la sdd
size_t string_list_capacity( t_string_list * );
size_t string_list_size( t_string_list * );
const char *string_list_index( t_string_list *, size_t );
// modifications
t_string_list *string_list_append( t_string_list *, const char * );
t_string_list *string_list_delete_last( t_string_list * );
//
...
...
Et voilà, une fois cela fait, tu auras tout ce qu'il faut pour gérer une liste de strings. Ce qui rendra le code que tu veux faire non seulement plus lisible mais également plus facilement maintenable et évolutif.
Et là, c'est top comme premier petit projet pour essayer de voir si tu as compris les pointeurs, ou pour en comprendre les subtilités.
OK, tu ne cherches pas la facilité, mais c'est vrai que c'est souvent une bonne façon de progresser. Puisque tu as un tableau de chaînes de caractères, il faut utiliser les fonctions de <string.h>. Exemple :
// Enregistrer le nom complet (dossier + chemin) dans un tableau de chaine avec le numéro de la boucle comme indice
nameDirImageFiles[loopCount] = *file;
ne fais pas ce que, normalement, tu souhaites faire (*). Il est possible que la bonne méthode soit :
strcpy(nameDirImageFiles[loopCount], file);
(Je dis « il est possible » parce que je ne suis pas sûr que 'file' soit le nom du fichier. Le nom de la variable m'a l'air trompeur.)
--------------------
(*) Décodage : si comme je le soupçonne file est une chaîne de caractères contenant le nom d'un fichier, alors :
file contient une adresse, celle du début de la chaîne, et *file la valeur contenue à cette adresse, c'est-à-dire le premier caractère de la chaîne. Par exemple si le fichier s'appelle "machin.txt", *file vaut 109 (le code ASCII de 'm').
nameDirImageFiles est un tableau de pointeurs, et nameDirImageFiles[loopCount] est un élément de ce tableau, donc un pointeur, c'est-à-dire une variable qui contient une adresse.
Ainsi, l'affectation que tu as écrite se lit : mettre l'adresse 109 dans le pointeur.
C'est horrible, n'est-ce pas ? (On se demande comment le compilateur se contente d'afficher un warning. Ah, c'est le langage C... Au moins tu as eu le réflexe de soupçonner qu'il s'agissait bien d'une erreur.)
rouloude, "Avec ce tableau, tu peux pointer sur 10000 chaînes de caractère." C'est ce que j'ai cru comprendre et il me semble que mon erreur ne vient pas de la compréhension de la déclaration du tableau. Reste, le prototype de la fonction, l'appel de la fonction avec le passage de paramètre, et l'initialisation de chaque chaîne...
White Crow, merci pour ton effort, mais je ne comprends pas ton code.
bruno, "(Je dis « il est possible » parce que je ne suis pas sûr que 'file' soit le nom du fichier. Le nom de la variable m'a l'air trompeur.)" file contient bien le nom (avec le path) du fichier. C'est ce nom là que je veux enregistrer en tant que chaîne dans le tableau.
"file contient une adresse, celle du début de la chaîne, et *file la valeur contenue à cette adresse, c'est-à-dire le premier caractère de la chaîne. Par exemple si le fichier s'appelle "machin.txt", *file vaut 109 (le code ASCII de 'm')." Aaaaahhhh !!! Voilà le joint (ou du moins, un des joints...) J'avais compris que file contenait l'adresse de la chaîne et que *file contenait la valeur de la chaîne, ce qui est complètement différent de l'adresse du premier caractère de la chaine et la valeur du premier caractère de la chaîne. Du coup, comme dans mon exemple, ma chaine commence par E:\Test... ça explique : "Le résultat du printf ligne 55 affiche nameDirImageFiles3 = E Pourquoi "E" ? c'est le premier caractère du chemin, le deuxième est ":"."
Tu viens de m'aider sacrément à comprendre ça ! Merci !
Par conséquent j'entrevois que je vais galérer pour initialiser toutes mes chaînes dans mon tableau sans connaître la taille des chaînes à l'avance et je vais devoir me pencher plus rapidement que prévu sur la solution que propose White Crow, sauf si je considère que le nom d'un dossier est limité à 256 caractères (je ne sais pas quelle est la limite sur windows mais j'ai déjà été confronté à des noms de fichiers trop longs... Qu'en penses-tu ?
strcpy(nameDirImageFiles[loopCount], file);
Ca, je l'ai déjà essayé mais ça me provoquait un message d'erreur, je ne me souviens plus lequel (je crois que loopcount n'est pas un int tel qu'attendu et lorsque je le remplace par *loopCount, je fais un "char à partir d'un int without cast" il me semble... Je vérifierai ça demain...
Ça donne l'erreur : warning: passing argument 1 of 'strcpy' makes pointer from integer without a cast [-Wint-conversion]
J'ai l'impression que tu n'adoptes pas la bonne démarche : soit tu essaies différentes choses jusqu'à ce que ça marche, soit tu essaies d'adapter des codes existants. Bref, tu tâtonnes...
Partons du tableau de chaînes de caractères, c'est-à-dire de pointeurs sur 'char'. Chaque élément du tableau devra pointer sur une zone mémoire que tu dois créer avec 'malloc'. White Crow a proposé de faire une structure, mais si tu veux il y aller doucement tu peux peut-être t'en passer (encore que la difficulté n'est pas dans la structure, mais dans les pointeurs) ?
Partons de ta première déclaration :
char nameDirImageFiles[10000];
En fait on ne veut pas un tableau de 'char' mais un tableau de pointeurs de 'char', donc :
char* nameDirImageFiles[10000]; // tu peux remplacer 10000 par un #define
D'aileurs tu as fait la correction plus loin, mais peut-être n'était-ce pas le cas lorsque tu avais utilisé 'strcpy', d'où le message d'erreur. Si tu tiens à initialiser ce tableau, je ferais :
char* nameDirImageFiles[10000] = {0};
Il me semble qu'ainsi les pointeurs seront initialisés à NULL (à vérifier). Ça peut d'ailleurs être un moyen de ne pas avoir besoin du nombre total d'éléments du tableau.
Justement, White Crow disait que tu as besoin de savoir combien d'éléments figurent dans le tableau (combien de pointeurs sur 'char'), et pour ça il faut une variable numérique (celle que White Crow appelle 'size'). Ça servira pour exploiter le tableau quand il sera rempli : on boucle de 0 à 'size' (non compris). Ou bien on s'en passe et on boucle tant que ce n'est pas NULL, si on a initialisé à NULL.
Dans ton algorithme, je pense qu'il n'y a essentiellement qu'une chose à modifier, c'est la ligne 52 (de la première version) :
nameDirImageFiles[loopCount] = *file;
Non, il faut utiliser 'strcpy'. Mais d'abord, il faut allouer de la mémoire pour placer la chaîne de caractères. Donc :
Ajouter un 'malloc' pour réserver N+1 octets, où N = longueur de la chaîne 'file'.
nameDirImageFiles[loopCount] doit pointer vers cette zone mémoire.
Puis faire le 'strcpy'.
Quand tu voudras afficher l'élément i du tableau, il suffira d'écrire :
printf("Fichier : %s\n", nameDirImageFiles[i]);
Comme c'est un pointeur de 'char', le format %s ira chercher la chaîne pointée.
À la fin de la boucle, n'oublie pas de compter combien de noms de fichiers ont été entrés dans le tableau (si tu utilises ce nombre), ça servira pour exploiter ce tableau.
Bref, je crois que tu peux réussir ce projet en adaptant peu de choses de ton code initial. (Sachant qu'il y a peut-être aussi des choses à revoir dans la récursivité, je crois que des intervenants l'avaient signalé.)
On a bien un tableau de chaine que l'on peut initialiser directement avec les indices...
Oui, ce code fonctionne !
char *arr3[256] = { "" };
Non, ce n'est pas un tableau de chaîne, ni un tableau d'indice (comme tu le dit plus loin) mais un tableau de pointeur sur char. Ou chaque pointeur peut pointer sur un tableau de char ou sur des chaîne de caractère.
quand tu écris :
arr3[9] = "hello there";
Tu mets l'adresse de la chaîne littérale "hello there" dans la case d'indice 9 de ton tableau de pointeur sur char !
rouloude, tu dis qu'elle affecte l'adresse de la chaine "hello there" à l'indice [9] du tableau de pointeur sur char. Ce ne serait pas plutôt qu'elle affecte la chaine ( et non pas son adresse, sinon, où le programme la récupère-t-il ?) "hello there" à l'adresse de l'indice [9] du tableau de pointeur sur char ?
Quelqu'un sait-il répondre à cette question : Est-il possible de passer arr3 en paramètre à une fonction et d'affecter les chaînes de caractère ensuite dans cette fonction ? Si la réponse est oui, est-ce que ceci serait correct :
La déclaration :
char *arr3[10000] = { "" };// Un tableau de pointeur vers char, tous les char initialisés à NULL
L'appel à la fonction :
laFonction (arr3);
Le prototype :
void laFonction(char *arr3); // *arr3 = un pointeur vers le tableau de pointeur vers char
rouloude, tu dis qu'elle affecte l'adresse de la chaine "hello there" à l'indice [9] du tableau de pointeur sur char. Ce ne serait pas plutôt qu'elle affecte la chaine ( et non pas son adresse, sinon, où le programme la récupère-t-il ?) "hello there" à l'adresse de l'indice [9] du tableau de pointeur sur char ?
Hé non ! Pour affecter le chaîne à l'élément n°9, il faut faire :
strcpy(arr3[9], "hello there");
en supposant que l'élément n°9 pointe vers un certain espace mémoire (auparavant alloué par 'malloc', probablement).
L'opérateur d'affectation = agit sur la variable directement, pas sur la variable qu'elle pointe. Et c'est logique. Quand on écrit « float x = 3.14 », c'est la variable 'x' qui est affectée, pas la variable pointée par x. Encore heureux puisque x n'est pas un pointeur ! Et quand on écrit « char* p = <l'adresse de quelque chose> », c'est le pointeur p qui est affecté directement, pas la variable pointée. Parce que c'est pareil qu'avec x.
Et dans ton exemple, arr3[9] est un pointeur, l'opérateur = va donc lui affecter quelque chose qui, normalement, est une adresse. Mais il ne va rien affecter à la variable pointée.
touvenant a écrit:
je crois avoir bien compris à présent que la bonne façon de déclarer mon tableau (de pointeur sur char) c'est :
char *nameDirImageFiles[10000] = { "" };
je crois que ça au revient au même que :
char* nameDirImageFiles[10000] = {0};
Dans les deux cas, les 10000 char seront initiallisés à NULL.
Mouais...
1) On déclare un tableau de pointeurs. Donc on doit l'initialiser avec des adresses. 0 est une adresse valide, équivalente à NULL. Ça a du sens.
2) OK, tu initialises à "", c'est-à-dire à l'adresse où la chaîne nulle est stockée en mémoire. Je doute que cette adresse soit 0. Peut-être ai-je mal compris quelque chose, mais je crois que tu trompes (si tu as essayé et que ça fait bien 0, je dois m'incliner, mais je ne comprends pas).
Pour ta dernière question, il me semble que la réponse est oui, mais si 'arr3' est bien un tableau de pointeurs sur 'char', comme l'était nameDirImageFiles, il y a des erreurs.
touvenant a écrit:
La déclaration :
char *arr3[10000] = { "" };// Un tableau de pointeur vers char, tous les char initialisés à NULL
Je ferais plutôt :
char *arr3[10000] = { 0 };// Un tableau de pointeurs vers char, tous les pointeurs initialisés à NULL
Ce ne sont pas les 'char' mais les pointeurs qu'on initialise. Puisque c'est un tableau de pointeurs.
touvenant a écrit:
L'appel à la fonction :
laFonction (arr3);
Le prototype :
void laFonction(char *arr3); // *arr3 = un pointeur vers le tableau de pointeur vers char
OK pour l'appel. 'arr3' étant un tableau, pas besoin en effet de passer un pointeur vers 'arr3'.
Du coup, pour le prototype, il faut juste donner le type exact de 'arr3' (là tu utilise un pointeur sur 'char' au lieu d'un tableau de pointeurs sur 'char'...) :
void laFonction(char *arr3[10000]); // arr3 = le tableau de pointeurs vers char
je crois avoir bien compris à présent que la bonne façon de déclarer mon tableau (de pointeur sur char) c'est :
char *nameDirImageFiles[10000] = { "" };
je crois que ça au revient au même que :
char* nameDirImageFiles[10000] = {0};
Dans les deux cas, les 10000 char seront initiallisés à NULL.
Non ! pour la première la case d'indice 0 est affecté avec l'adresse d'une chaîne vide ! les cases suivante à NULL ! pour la deuxième oui toutes les cases sont initialisé à NULL !
touvenant a écrit:
a propos de cette ligne
arr3[9] = "hello there";
rouloude, tu dis qu'elle affecte l'adresse de la chaine "hello there" à l'indice [9] du tableau de pointeur sur char. Ce ne serait pas plutôt qu'elle affecte la chaine ( et non pas son adresse, sinon, où le programme la récupère-t-il ?) "hello there" à l'adresse de l'indice [9] du tableau de pointeur sur char ?
Non, c'est bien l'adresse de la chaîne (tu devrais savoir que l'on ne peux pas affecter directement des tableaux donc des chaînes de caractère puisque ce sont des tableaux). Le programme la récupère dans la mémoire, c'est ce qu'on appelle une chaîne littérale, elle est crée dès le chargement du programme en mémoire.
EDIT : pour ta dernière question, il faut donner le bon prototype à ta fonction : il te faut un pointeur sur un tableau de pointeur sur char :
"Non ! pour la première la case d'indice 0 est affecté avec l'adresse d'une chaîne vide ! les cases suivante à NULL ! pour la deuxième oui toutes les cases sont initialisé à NULL ! "
Ok, j'ai compris la différence. Je peux faire aussi :
char *arr3[10] = {NULL};
Pour le prototype :
void fonction(char* arr3);
Si je passe un pointeur sur un tableau et
void fonction(char* arr3[])
Si je passe un pointeur sur un tableau de pointeurs c'est exact ?
Enfin, dans tous les cas, j'appelle la fonction avec le nom du pointeur :
fonction(arr3);
Bon, maintenant que je crois avoir compris comment ça fonctionne, je vais tenter de mettre en pratique sur mon programme avec la boucle.
Merci à tous pour vos contributions et surtout pour votre patience !
Belle fin de journée !
PS:
"(si tu as essayé et que ça fait bien 0, je dois m'incliner, mais je ne comprends pas)."
J'ai essayé et ça ne fait pas NULL.
Bon, j'ai corrigé ce qui n'allait pas et le passage du pointeur de tableau de pointeur fonctionne ainsi que l'affectation des chaines... Le résultat n'est pas ce que j'attendais mais ce n'est plus un problème de syntaxe, ça vient d'un problème de logique, il faut que je réfléchisse de nouveau à mon code.
Le main.c :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/stat.h>
#include "fonctions.h"
#ifndef WIN32
#include <sys/types.h>
#endif
int main(void)
{
// selectionner le répertoire et enregistrer son chemin dans file :
char file[256] = "E:\\Test";
// Parcourir les repertoires et recuperer le chemin complet du repertoire en cours d'analyse
int loopCount = 0;
char *nameDirImageFiles[100] = {NULL};
handling(file, loopCount, nameDirImageFiles);
return 0;
}
Le fonctions.h :
void handling(char *file, int loopCount, char *nameDirImageFiles[]);
int is_dir(char *file);
Le fonctions.c :
#include <stdlib.h> // Pour exit()
#include <stdio.h> // Pour puts()
#include <string.h> // Pour les fonctions sur les chaines
#include <stdbool.h>
#include <dirent.h> // Pour l'utilisation des dossiers
#include <unistd.h>
#include <sys/stat.h>
#include "fonctions.h"
// Si ce n'est pas un systeme windows:
#ifndef WIN32
#include <sys/types.h>
#endif
// Fonction qui boucle sur les répertoires et fais une liste des fichiers qu'ils contiennent
void handling(char *file, int loopCount, char *nameDirImageFiles[])
{
struct dirent *lecture;
DIR* openedDirectory = NULL;
openedDirectory = opendir(file); // Ouverture d'un dossier
if (openedDirectory == NULL)// Si le dossier n'a pas pu être ouvert
{
printf("Le dossier %s n'existe pas\n", file);
perror(""); // perror() va nous écrire l'erreur.
exit(1);
}
//puts("Le dossier a ete ouvert avec succes\n");
lecture = readdir(openedDirectory);
char chemin_temp[500] = "";
/* On effectue une boucle sur l'ensemble des éléments du dossier en cours
sauf si le premier élément était un fichier (on a alors mis un drapeau à 1)*/
while ((lecture = readdir(openedDirectory)) != NULL)
{
// On écarte les deux premiers éléments d'un dossier Windows
if (strcmp(lecture->d_name, "." ) != 0 && strcmp(lecture->d_name, ".." ) != 0)
{
sprintf(chemin_temp, "%s\\%s", file, lecture->d_name);
// Si l'élément est un dossier, on effectue une boucle récursive
if( is_dir(chemin_temp) == 1)
{
//printf("file = %s\n", file);
loopCount++; // Avant d'entrer dans la boucle, j'incrémente le compteur
handling(chemin_temp, loopCount, nameDirImageFiles);
loopCount--; // En sortant de la boucle, je décrémente? le compteur
}
else
{
// Enregistrer le nom complet (dossier + chemin) dans un tableau de chaine avec le numéro de la boucle comme indice
nameDirImageFiles[loopCount] = chemin_temp;
int i = 0;
for(i = 0 ; i <= 99 ; i++)
{
printf("nameDirImageFiles%d = %s\n", i, nameDirImageFiles[i]);
}
// On enregistre le nom + chemin dans un journal
// Ouvrir le fichier log
FILE *f;
//char fichierDest[256] = "E:\\Test";
f = fopen("E:\\Test\\log.txt", "a");
if(f == NULL){
printf("Erreur lors de l'ouverture du fichier");
exit(1);
}
// Ecrire nameDirImageFiles[loopCount] dans le fichier log
fputs(nameDirImageFiles[loopCount], f); // Console : warning: passing argument 1 of 'fputs' makes pointer from integer without a cast [-Wint-conversion]|
fputc('\n', f);
fclose(f);
}
}
}
}
// Fonction qui vérifie si l'élément est un dossier
int is_dir(char *file)
{
DIR *is_folder = NULL;
is_folder = opendir(file);
if (is_folder != NULL)
{
// C'est un dossier
closedir(is_folder);
return 1;
}
else
{
// Ce n'est pas un dossier
return 0;
}
}
Ok, Comme c'est un pointeur de pointeur de char, il peux s'utiliser pour pointer sur un tableau de pointeur de char. En fait qu'il pointe sur un seul pointeur de char ou sur un tableau de pointeur de char le type est le même.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent