J'ai un problème un peu compliqué a résoudre, ca fait quelques semaines que je suis dessus.
Voilà, j'ai dans les eaux de 1000 fichiers .csv dans un repertoire qu'il faut que je charge en mémoire pour pouvoir faire des traitements dessus.
Les données sont conservees dans chaque fichier sous la forme
char[10] char[10] int float float float float
char[10] char[10] int float float float float
char[10] char[10] int float float float float, etc.
La solution que j'ai trouvé était de créer une structure pour pouvoir faire des traitements dessus. Mais j'ai beaucoup de problèmes pour arriver à effectuer des traitements dessus depuis une fonction. Voici un bout de code. Il ne résoud que très partiellement le problème :
#include <stdio.h>
struct entree {
char date[10], time[10];
int v;
float a,b,c,d;
}
main () {
struct entree data[1000] ; # 1000 lignes pour le fichier
int i=0;
FILE *fp;
fp = fopen("1.csv", "r");
while(!(feof(fp))) {
fscanf(fp, "%s %s %d %f %f %f %f", &date, &time, &v, &a, &b, &c, &d);
strcpy(data[i].date, date);
strcpy(data[i].time, time);
data[i].v = v);
data[i].a = a);
data[i].b = b);
i++;
}
}
J'ai 3 problèmes :
- j'arrive pas à creer une fonction distincte de main, qui mette les données dans la structure
- je sais pas comment gérer plusieurs fichiers
- je sais pas comment gérer un fichier de x lignes (x étant susceptible d'être supérieur à 200.000).
Je sais, ca fait beaucoup de mémoire vive qu'il va falloir acheter, mais c'est pas un problème ;-)
# base de la programmation
Posté par NeoX . Évalué à 1.
ca fait longtemps que j'ai pas codé en C, il pourrait donc y avoir des erreurs...
apres pour gerer plusieurs fichiers, ca va dependre si tu veux les mettre dans ta structure separement ou dans une seule (concatenation)
et pour les fichiers de taille T, il faut surement recupere d'abord la longueur du fichier et la passer en parametre à ma_fonction(mon_fichier, sa_taille), ou tester dans ma_fonction la taille du fichier.
[^] # Re: base de la programmation
Posté par zedis . Évalué à 1.
Dans ta solution par contre, est-ce qu'on peut accéder à la structure depuis main ?
Merci !
[^] # Re: base de la programmation
Posté par NeoX . Évalué à 1.
et pour concatenation,
il faudrait simplement faire un data[X+Y+Z]
X, Y et Z etant les tailles des trois fichiers que tu veux traiter.
une solution avant de coder, consiste à decrire en francais ce que tu veux faire (algorythmie),
et ensuite transposer dans le langage en question.
[^] # Re: base de la programmation
Posté par Guillaume Rossignol . Évalué à 2.
[^] # Aaaaie, mes yeux !
Posté par imalip . Évalué à 5.
[^] # Re: Aaaaie, mes yeux !
Posté par Guillaume Rossignol . Évalué à 2.
[^] # Re: Aaaaie, mes yeux !
Posté par mrlem (site web personnel) . Évalué à 3.
[^] # Re: base de la programmation
Posté par imalip . Évalué à 2.
Sur ce, apres l'apero, un verre de vin et pas loin d'une demi bouteille de champagne, au lit. L'air de rien, je bosse demain... Enfin dans 8 heures. En principe.
Et pour zedis :
-passer le tableau en parametre en tant que pointeur a la fonction de remplissage, ou que la fonction en question alloue de la memoire a coup de malloc().
-si tu travailles avec malloc, realloc() est ton ami.
-a part la memoire qui risque d'exploser, il y a plein de methodes possible plus ou (surtout) moins efficaces.
En fait, ca depend vraiment de ce que tu veux faire comme traitement sur tes donnees ; mais *tout* charger en memoire me semble un peu lourd...
Bon, au dodo !
[^] # Re: base de la programmation
Posté par zedis . Évalué à 1.
La solution proposée par imalip, j'ai essayé aussi, mais sans résultat.
L'idée était de passer en argument à la fonction qui récupère les données un pointeur sur la structure de sorte que la fonction la remplisse. Etant relativement débutant en C, je me suis cassé la tete (notamment ;-) a essayer de faire en sorte que ça fonctionne ; impossible. Voici le code...
Si quelqu'un peut me sortir de ce mauvais pas je lui paye une biere !
#include <stdio.h>
struct enreg {
char date[20], heure[20];
int v;
float a,b,c,d;
};
/*
* Lit le fichier et enregistre les elements dans une structure data accessible globalement
*
*/
void fct(struct enreg *s) {
char chaine[256], date[20], heure[20];
int v;
float a,b,c,d;
int i=0;
FILE *fp = fopen("1.txt", "r");
while(fgets(chaine, sizeof(chaine), fp)) {
sscanf(chaine, "%s %s %d %f %f", date, heure, &v, &a, &b );
(s+i)->v = v;
printf("%d \n", i);
i++;
}
fclose(fp);
}
/*
* Main
*
*/
main() {
struct enreg x[1000000]; // cree la structure x
// ? ? ? void fct(struct enreg *y);
fct(&x[1000000]);
}
[^] # Re: base de la programmation
Posté par imalip . Évalué à 2.
Remplacer "(s+i)->v = v;" par "s[i].v = v;"
s+i ajoute l'entier i a l'adresse s, donc pas du tout ce que tu veux faire. Ca m'étonne presque que le compilo ne te jette pas...
et "fct(&x[1000000]);" par "fct(x);"
&x[1000000] est l'adresse du 1000001eme élément de ton tableau qui en fait 1000000, donc tu tappes en-dehors. il faut que tu passes l'adresse du premier, donc &x[0] (qui est equivalent a x).
[^] # Re: base de la programmation
Posté par zedis . Évalué à 1.
Il me reste 2 erreurs que j'essaye de résoudre :
- sous Linux, impossible de compiler en apportant les modifications conseillées, gcc me retourne "tow or more data types in declaration of fct"... l'erreur étant à la ligne de la déclaration de la fonction fct
- Je passe sous visual C++ et là ca compile, mais ca plante lorsque le tableau dépasse 10000 lignes... j'augmentes logiquement le nombre de lignes 30000 et ca plante sans raison valable.
Grrrr..
Pour le "(s+i)->v = v " j'avais lu quelque part qu'il fallait utiliser cette notation pour travailler sur des pointeurs de trableaux de structures. En utilisant s[x].heure je croyais qu'on travaillait sur les valeurs directement et non sur l'adresse de la variable.
Il me reste encore du taf pour maitriser les pointeurs (ne me jettez pas la pierre j'ai lu pas mal de bouquins sur le passage de pointeurs de tablaux de structures dans une fonction, et c'est dur de trouver des infos a ce sujet).
[^] # Re: base de la programmation
Posté par alf . Évalué à 2.
Comme je l'ai dit plus bas, la raison valable est que 30000 lignes, ça fait environ 1,5 Mo (en supposant une cinquantaine d'octets par structure), et que tu alloues tes scructures sur la pile. Une implémentation est libre de refuser un tel code (de tête, la limite minimale imposée par la norme doit être autour de 65 Ko, à moins que je mélange avec autre chose). Passe par malloc quand tu as besoin d'autant de mémoire.
[^] # Re: base de la programmation
Posté par Thomas Douillard . Évalué à 4.
Euh non, si je ne m'abuse c'est de l'arithmétique des pointeurs. En particulier quand tu ajoutes 1 à un pointeur ça passe à l'adresse suivante (donnée par la taille du type en mémoire)
@zedis : il te manque plein de base pour coder en C on dirait. C'est un langage relativement bas niveau avec pleins de pièges niveau gestion mémoire, pointeur tout ça. Tu devrais lire une bon tuto un peu complet ou mieux un bon bouquin de C avant d'essayer de coder, sinon tu vas te jeter dans tous les pitèges un par un ... Ou passer à un langage un peu plus haut niveau qui gère tout seul la mémoire.
[^] # Re: base de la programmation
Posté par Thomas Douillard . Évalué à 3.
[^] # Re: base de la programmation
Posté par alf . Évalué à 2.
[^] # Re: base de la programmation
Posté par totof2000 . Évalué à 1.
- fais le traitement sur une ligne avec une fonction qui lit une ligne et remplit la structure adéquate
- apprend à gérer les listes chainées, ou utilise une lib qui les implémente (glib, me semble-t-il, a tout ce qu'il faut pour le faire).
- ensuite, une fois que tu as la fonction qui te remplit une structure avec une ligne, tu passe a la lecture de tout le fichier.
[^] # Re: base de la programmation
Posté par zedis . Évalué à 1.
Bon, j'ai résolu en partie mon problème : pour la mémoire, l'allocation d'un tableau de 100000 lignes est effectivement beaucoup trop gros. En passant par malloc, ca marche nettement mieux.
Par contre pour la structure personne n'a vraiment répondu à la question : comment on fait pour passer un pointeur sur une structure à une fonction, de sorte qu'on puisse l'utiliser au sein de la fonction (comme ça idéalement je pourrais remplir ma structure depuis une fonction ce qui simplifirai pas mal mon code...).
Sinon quelqu'un a une idée de comment on crée un tableau dans lequel je pourrai mettre mes structures (rappel : pour l'instant une structure = 1 fichier, et il me reste 998 fichiers à lire et a charger en mémoire)...
Merci !
Zed
[^] # Re: base de la programmation
Posté par zedis . Évalué à 1.
Dans mes fichiers, les données sont toujours exactement les memes. Donc pour fgets ca ne doit pas poser de problemes pratiques normalement, idem pour sscanf (ceci dit merci d'avoir soulevé le probleme potentiel).
Merci également d'avoir d'expliqué pourquoi
struct enreg x[1000000]
posait problème ; j'ai trouvé la solution hier soir, mais j'ai pas vraiment compris pourquoi ; ton explication éclaire tout maintenant.
fct(&x[100000]) est effectivement faux, mais si je fais fct(x), j'envoie une copie de la structure et non un pointeur non ?
Il y a quelque chose qui m'échappe là (sur comment faire pour envoyer un pointeur dans une fonction et travailler avec).
Merci !
Zed.
[^] # Re: base de la programmation
Posté par alf . Évalué à 2.
Note que, dans g, tu peux toujours utiliser la notation tableau sur le pointeur p, pour accéder à d'autres éléments : Comme on ne peut passer vraiment un tableau en paramètre à une fonction (à cause de la conversion implicite en pointeur), il faut passer à la fonction g la taille du tableau, i.e. le nombre d'éléments accessibles à partir de *p. Ainsi g sait jusqu'où elle peut aller (dans mon exemple, le test "s > 0" est inutile, vue la construction de la boucle, mais dans le cas général il est bon de faire le test).
Pour ton problème, si tu veux avoir un seul tableau pour toutes les données de tous les fichiers, je pense que tu peux faire quelque chose comme ça :
Je te passe les contrôles d'erreur habituels, c'est juste une idée d'algo que tu peux utiliser, à ajuster en fonction de tes besoins.
# question con :
Posté par gaaaaaAab . Évalué à 2.
Je demande ça parce que les langages de script sont particulièrement adaptés au traitement de données dans des fichiers (c'est limite pour ça qu'ils ont été conçus). Je pense à Perl, Python, ... voire même avec les commandes de shell usuelles ...
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.