Partage
  • Partager sur Facebook
  • Partager sur Twitter

Créer une liste chainée static ?

Sujet résolu
    16 septembre 2022 à 19:04:54

    Bonjour, je me retrouve confronter à un problème. Je suis actuellement sur l'exercice get_next_line que vous avez sans doute du voir passer un nombre incalculable de fois mais voilà.. (Pour rappel, il faut lire x char selon la taille du buffer, et renvoyer la ligne suivante incluant le \n jusqu'à arriver à la fin du fichier et ce grâce à une variable statique)

    Je tiens à préciser que je l'ai fini et il fonctionne après être passer par tous les test. Mais voilà je veux aussi réaliser les bonus et c'est la que cela se complique un peu car je sais pas comment lui dire ce que je veux faire.

    En gros sans la partie bonus, je pouvais utiliser un truc du genre:

    static char	*line;

    Mais pour la partie bonus je dois pouvoir gérer plusieurs file descriptor, j'ai donc directement penser aux listes chainées et voici ma déclaration:

    typedef struct s_line
    {
    	char			*line;
    	int				fd;
    	struct s_line	*next;
    }	t_line;

    Ainsi que la déclaration

    static t_line	*line;

    Et je pensais simplement m'en servir comme ça

    t_line	*create_elem(int fd)
    {
    	t_line	*line;
    
    	line = malloc(sizeof(t_line));
    	if (line)
    	{
    		line->fd = fd;
    		line->next = NULL;
    	}
    	return (line);
    }
    
    t_line	*check_fd(t_line *line, int fd)
    {
    	t_line	*lst;
    
    	lst = line;
    	if (!lst)
    		return (create_elem(fd));
    	while (lst && lst->fd != fd)
    		lst = lst->next;
    	if (!lst)
    		lst = create_elem(fd);
    	return (lst);
    }

    Le problème est que, vous vous en doutez surement mais ce qu'il y a à l'intérieur de line n'est pas du tout static et c'est là que le soucis apparait, je perd le file. J'ai aussi essayer de déclarer directement à l'intérieur de ma liste mais là aussi j'ai une erreur de compil.

    error: type name does not allow storage class to be specified

    Finalement ma question est simple, comment puis-je contourner ce problème svp ? En gardant à l'esprit que je dois utiliser une seule variable statique.

    Merci bien !

    UPDATE:

    Finalement j'ai réussi, mais avec un double tableau !..

    Mais je suis obligé de le détruire puis de le recréer et je trouve ça plutôt chiant, donc je reste preneur s'il y a une solution avec une liste chainée, merci !

    -
    Edité par AlexDorian2 16 septembre 2022 à 19:51:23

    • Partager sur Facebook
    • Partager sur Twitter
      16 septembre 2022 à 19:51:21

      Je ne vois pas pourquoi tu as besoin de quelque chose de statique.
      Quand tu lis une ligne, tu as une dimension maximum pour le buffer? Tu réserves l'espace avec malloc je suppose.
      Tu le feras donc pour chacun des maillons de ta liste chaînée.
      Et pourquoi as-tu besoin d'une liste chaînée? Est-ce que tu ajoutes ou enllèves des descripteurs souvent?
      • Partager sur Facebook
      • Partager sur Twitter

      Le Tout est souvent plus grand que la somme de ses parties.

        16 septembre 2022 à 19:59:33

        Le code n'a pas l'air de produire le message indiqué

        J'ai l'impression que tu donnes au mot "static" un sens qu'il n'a pas en C, et je le demande si tu ne penses pas plutot à const ?

        > Finalement j'ai réussi, mais avec un double tableau !..

        > Mais je suis obligé de le détruire puis de le recréer et je trouve ça plutôt chiant, donc je reste preneur s'il y a une solution avec une liste chainée, merci

        Peut être que tu t'y prends mal avec ton "double tableau", et ça ne fait pas de la liste chaînée une bonne solution.

         A priori, un "tableau extensible" contenant des structures avec fd + chaine (nom de fichier ?) ca fait très bien l'affaire.

        -
        Edité par michelbillaud 16 septembre 2022 à 20:13:31

        • Partager sur Facebook
        • Partager sur Twitter
          16 septembre 2022 à 20:07:47

          Merci pour vos réponses.

          PierrotLeFou a écrit:

          Je ne vois pas pourquoi tu as besoin de quelque chose de statique.
          Quand tu lis une ligne, tu as une dimension maximum pour le buffer? Tu réserves l'espace avec malloc je suppose.
          Tu le feras donc pour chacun des maillons de ta liste chaînée.
          Et pourquoi as-tu besoin d'une liste chaînée? Est-ce que tu ajoutes ou enllèves des descripteurs souvent?

          Peut-être que je me suis mal exprimé. Le but de l'exercice est de:

          • Des appels successifs à votre fonction get_next_line() doivent vous permettre de lire l’intégralité du fichier texte référencé par le descripteur de fichier, une ligne à la fois.
          • Votre fonction doit retourner la ligne qui vient d’être lue. S’il n’y a plus rien à lire, ou en cas d’erreur, elle doit retourner NULL.
          • Assurez-vous que votre fonction se comporte correctement qu’elle lise un fichier ou qu’elle lise sur l’entrée standard.
          • Important : Vous devez toujours retourner la ligne qui a été lue suivie du \n la terminant, sauf dans le cas où vous avez atteint la fin du fichier le m
          Votre programme doit lire le moins possible à chaque appel à get_next_line(). Si vous rencontrez une nouvelle ligne, vous devez retourner la ligne précédente venant d’être lue. Ne lisez pas l’intégralité du fichier pour ensuite traiter chaque ligne.

          Et donc en gros, j'ai besoin d'un static pour garder le fil entre deux appels de la fonction. Et oui je souhaite ajouter les fd au fur et à mesure des appels si l'user décide de changer ou non de fichier et du coup de supprimer le maillon en question quand celui-ci est arrivé à la fin.

          michelbillaud a écrit:

          Le code n'a pas l'air de produire le message indiqué

          J'ai l'impression que tu donnes au mot "static" un sens qu'il n'a pas en C, et je le demande si tu ne penses pas plutot à const ?

          Oui c'est normal car essayer de cette façon:
          typedef struct s_line
          {
          	static char			*line;
          	int				fd;
          	struct s_line	*next;
          }	t_line;

          michelbillaud a écrit:

          > Mais je suis obligé de le détruire puis de le recréer et je trouve ça plutôt chiant, donc je reste preneur s'il y a une solution avec une liste chainée, merci

          Peut être que tu t'y prends mal avec ton "double tableau", et ça ne fait pas de la liste chaînée une bonne solution, si il s'agit d'obtenir une chaîne de caractères style C.

           Pour un ensemble de descripteurs, on utilise généralement un fd_set (qui est un masque binaire), voir page de manuel de select, par exemple.

          Oui mais je n'ai pas le droit d'utiliser de fonction externe



          -
          Edité par AlexDorian2 16 septembre 2022 à 20:10:31

          • Partager sur Facebook
          • Partager sur Twitter
            16 septembre 2022 à 20:09:13

            Quel est le numéro du plus grand fd?
            L'indice du tableau pourrait être le fd et il contiendrait des char *
            Si le fd ne sert plus, le pointeur sera mis à NULL.

            edit:

            Rien ne dit que tu dois lire sur plusieurs fichiers en même temps.

            -
            Edité par PierrotLeFou 16 septembre 2022 à 20:12:54

            • Partager sur Facebook
            • Partager sur Twitter

            Le Tout est souvent plus grand que la somme de ses parties.

              16 septembre 2022 à 20:11:48

              PierrotLeFou a écrit:

              Quel est le numéro du plus grand fd?
              L'indice du tableau pourrait être le fd et il contiendrait des char *
              Si le fd ne sert plus, le pointeur sera mis à NULL.


              Oui c'est exactement ce que j'ai fais et ça fonctionne mais je pensais que c'était pas le plus opti enfin, dans le sens où l'on pouvait utiliser de meilleur "outils"

              Voilà ce que j'ai fait

              void	freetab(char **tab)
              {
              	int	i;
              
              	i = 0;
              	while (tab[i])
              		free(tab[i++]);
              	free(tab);
              }
              
              char	**copyarray(char **tab, int *size)
              {
              	char	**res;
              	int		i;
              
              	i = 0;
              	while (tab[i])
              		i++;
              	res = malloc(sizeof(char *) * (i + 1));
              	*size = i;
              	if (!res)
              		return (res);
              	i = -1;
              	while (tab[++i])
              		res[i] = ft_strdup(tab[i]);
              	return (res);
              }
              
              char	*check_fd(char **tline, int fd)
              {
              	char	**tmp;
              	int		size;
              	int		pos;
              
              	if (!tline)
              	{
              		tline = malloc(sizeof(char *));
              		*tline = ft_strdup("");
              		return (*tline);
              	}
              	pos = 0;
              	if (fd != 0)
              		pos = fd - (fd - 1);
              	if (tline[pos])
              		return (tline[pos]);
              	tmp = copyarray(tline, &size);
              	freetab(tline);
              	tline = malloc((size + 1) * sizeof(char *));
              	if (!tline)
              		return (NULL);
              	tline = tmp;
              	tline[pos] = ft_strdup("");
              	return (tline[pos]);
              }

              PierrotLeFou a écrit:

              edit:

              Rien ne dit que tu dois lire sur plusieurs fichiers en même temps.

              Voici les bonus à réaliser :

              Faites get_next_line() avec une seule variable statique.

              • Complétez get_next_line() en lui permettant de gérer plusieurs fd. Par exemple, si les fd 3, 4 et 5 sont accessibles en lecture, alors il est possible de les lire chacun leur tour sans jamais perdre les contenus lus sur chacun des fd, et sans retourner la mauvaise ligne.
              • Vous devriez pouvoir appeler get_next_line() une fois avec le fd 3, puis le 4, le 5, puis à nouveau le 3, à nouveau le 4, etc.

              -
              Edité par AlexDorian2 16 septembre 2022 à 20:17:27

              • Partager sur Facebook
              • Partager sur Twitter
                16 septembre 2022 à 20:17:56

                Je pense que tu aurais intérêt à mieux expliquer ton problème plutôt que d'essayer de trouver des solutions
                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  16 septembre 2022 à 20:20:18

                  PierrotLeFou a écrit:

                  Je pense que tu aurais intérêt à mieux expliquer ton problème plutôt que d'essayer de trouver des solutions

                  En clair, la solution du double tableau fonctionne OK mais est-ce la meilleure façon de faire ? Je pensais qu'utiliser les listes chainées étaient de meilleur "outils" mais apparemment pas mais pourquoi dans ce cas ?

                  michelbillaud a écrit:

                   A priori, un "tableau extensible" contenant des structures avec fd + chaine (nom de fichier ?) ca fait très bien l'affaire.

                  Du coup pour toi le meilleur serait de créer un static tableau de struct ?

                  -
                  Edité par AlexDorian2 16 septembre 2022 à 20:25:21

                  • Partager sur Facebook
                  • Partager sur Twitter
                    16 septembre 2022 à 22:58:25

                    > Les listes chainees meilleurs outils.

                    Ah bon. Et qu'est ce qui ferait dire çà ?

                    > static tableau

                    Je n'ai pas dit d'utiliser quoi que ce soit de static, pour moi, du coup.

                    -
                    Edité par michelbillaud 16 septembre 2022 à 23:01:08

                    • Partager sur Facebook
                    • Partager sur Twitter
                      16 septembre 2022 à 23:41:36

                      michelbillaud a écrit:

                      > Les listes chainees meilleurs outils.

                      Ah bon. Et qu'est ce qui ferait dire çà ?

                      Rien, je pensais juste. Je pense mal pour le coup

                      michelbillaud a écrit:

                      > static tableau

                      Je n'ai pas dit d'utiliser quoi que ce soit de static, pour moi, du coup.

                       Alors svp expliquez moi comment c'est possible ??

                      Si j'ai "bonjour\na\nb" et que la taille de mon buffer est de 100, il va tout dire et tout stocker dans la chaine.

                      Maintenant il va traiter la chaine et dire qu'il récupère seulement "bonjour\n" et retourne donc "bonjour\n" mais qu'en est-il du reste de la chaine ?

                      Car au prochaine appel read lira 0 vu qu'il a déjà tout lu et line contiendra rien vu que c'est une variable non statique

                      Que veux-tu dire exactement ? Que j'ai loupé un épisode et qu'il est possible de faire sans variable statique ??

                      • Partager sur Facebook
                      • Partager sur Twitter
                        17 septembre 2022 à 0:36:00

                        Quand on fait ce genre de chose, on réserve l'espace pour un "buffer" de travail.
                        Ensuite on analyse et on recopie dans un auttre espace dont on connait la longueur.
                        Au prochain appel, on lit à nouveau dans le buffer et on recopie dans un nouvel espace., etc
                        Pas besoin de statiqque.
                        Est-ce que tu accumules toutes les lignes du fichier en mémoire?
                        Et pourquoi plusieurs fd? Ou je n'ai rien compris.
                        • Partager sur Facebook
                        • Partager sur Twitter

                        Le Tout est souvent plus grand que la somme de ses parties.

                          17 septembre 2022 à 0:45:17

                          PierrotLeFou a écrit:

                          Quand on fait ce genre de chose, on réserve l'espace pour un "buffer" de travail.
                          Ensuite on analyse et on recopie dans un auttre espace dont on connait la longueur.
                          Au prochain appel, on lit à nouveau dans le buffer et on recopie dans un nouvel espace., etc
                          Pas besoin de statiqque.
                          Est-ce que tu accumules toutes les lignes du fichier en mémoire?
                          Et pourquoi plusieurs fd? Ou je n'ai rien compris.

                          Non, je crois pas qu'on soit sur la même longueur d'onde, je pense que j'ai du mal m'exprimer car c'est clairement impossible sans variable statique, voici le vrai énoncé:

                          • Partager sur Facebook
                          • Partager sur Twitter
                            17 septembre 2022 à 1:05:10

                            Pas de chance pour toi. Je suis aveugle et je ne peux voir les images et/ou les saisies d'écran.

                            Peux-tu poster le code de ta fonction get_next_line(...) ?

                            Pourquoi utiliser un "file descriptor" au lieu d'un "file pointer" ?

                            Ça se ferait facilement avec fgets(), strlen(), malloc() et strcpy()

                            et pas besoin de static, le reste du fichier sera lu aux prochains appels.

                            -
                            Edité par PierrotLeFou 17 septembre 2022 à 1:22:42

                            • Partager sur Facebook
                            • Partager sur Twitter

                            Le Tout est souvent plus grand que la somme de ses parties.

                              17 septembre 2022 à 2:13:33

                              Ah mince, vous m'en voyez navré :(

                              Car pour l'exercice j'ai seulement droit à malloc, free et read comme fonction standard et rien d'autres. J'ai le droit de créer 2 fichiers contenant 5 fonctions chacune qui elles-mêmes ne doivent pas dépasser 25l.

                              Et du coup, voilà pourquoi j'ai besoin du mot clé static.

                              Voici mon code (très en bordel car je viens de régler un soucis et là il peut donc gérer plusieurs fd en même temps grâce au double tab)

                              char	**copyarray(char **tab)
                              {
                              	char	**res;
                              	int		size;
                              	int		i;
                              
                              	i = 0;
                              	while (tab[i])
                              		i++;
                              	res = malloc(sizeof(char *) * ((i + 1) + 1));
                              	size = i + 1;
                              	if (!res)
                              		return (res);
                              	i = -1;
                              	while (tab[++i])
                              		res[i] = ft_strdup(tab[i]);
                              	while (i < size)
                              		res[i++] = ft_strdup("");
                              	res[i] = 0;
                              	return (res);
                              }
                              
                              char	**check_fd(char **tline, int pos)
                              {
                              	char	**tmp;
                              	int		i;
                              
                              	if (!tline)
                              	{
                              		tline = malloc(sizeof(char *) * ((pos+1) + 1));
                              		i = -1;
                              		while (++i < pos + 1)
                              			tline[i] = ft_strdup("");
                              		tline[i] = 0;
                              		return (tline);
                              	}
                              	if (tline[pos])
                              		return (tline);
                              	tmp = copyarray(tline);
                              	freetab(tline);
                              	return (tmp);
                              }
                              
                              char	*newline_exist(char **line, int lastline)
                              {
                              	const char	*endl;
                              	char		*res;
                              	char		*tmp;
                              
                              	if (!*line)
                              		return (*line);
                              	tmp = NULL;
                              	endl = ft_strchr(*line, '\n');
                              	if (endl && !lastline)
                              	{
                              		tmp = ft_strdup(endl + 1);
                              		res = ft_strndup(*line, (endl - *line) + 1);
                              		free(*line);
                              		*line = tmp;
                              		return (res);
                              	}
                              	if (lastline && **line && !endl)
                              		tmp = ft_strdup(*line);
                              	if (tmp || (*line && !**line))
                              	{
                              		free(*line);
                              		*line = NULL;
                              	}
                              	return (tmp);
                              }
                              
                              char	*get_next_line(int fd)
                              {
                              	static char	**tline;
                              	char		*line;
                              	char		*res;
                              	char		buff[BUFFER_SIZE + 1];
                              	int			ret;
                              	int			pos;
                              
                              	if (fd < 3 && fd != 0)
                              		return (NULL);
                              	pos = fd;
                              	if (fd != 0)
                              		pos = fd - 2;
                              	tline = check_fd(tline, pos);
                              	if (!tline || !tline[pos])
                              		return (NULL);
                              	line = tline[pos];
                              	ret = 1;
                              	while (ret)
                              	{
                              		ret = read(fd, buff, BUFFER_SIZE);
                              		if (ret < 0)
                              			return (NULL);
                              		buff[ret] = 0;
                              		ft_strjoin(&tline[pos], buff, ret);
                              		res = newline_exist(&tline[pos], 0);
                              		if (res)
                              			return (res);
                              	}
                              	return (newline_exist(&tline[pos], 1));
                              }
                              
                              int		main(int ac, char **av)
                              {
                              	(void)ac;
                              	char	*res;
                              	int		fd = open(av[1], O_RDONLY);
                              	int		fd2 = open(av[2], O_RDONLY);
                              
                              	res = get_next_line(fd);
                              	printf("1: %s", res);
                              	res = get_next_line(fd2);
                              	printf("2: %s", res);
                              	res = get_next_line(fd);
                              	printf("3: %s", res);
                              	res = get_next_line(fd2);
                              	printf("4: %s", res);
                              	res = get_next_line(fd);
                              	printf("4: %s", res);
                              	res = get_next_line(fd2);
                              	printf("4: %s", res);
                              	res = get_next_line(fd);
                              	printf("4: %s", res);
                              	res = get_next_line(fd2);
                              	printf("4: %s", res);
                              
                              	close(fd);
                              	close(fd2);
                              	return (0);
                              }
                              • Partager sur Facebook
                              • Partager sur Twitter
                                17 septembre 2022 à 2:33:44

                                J'ai fait le code suivant sans static et il marche. Je pourrais lire de n'importe quel fd valide.
                                Tu pourras remplacer les fonctions invalides par tes fonctions.

                                Ce n'est pas la responsabilité de get_next_line que de gérer la liste des lignes.
                                -
                                #include <unistd.h>
                                #include <stdio.h>
                                #include <stdlib.h>
                                #include <string.h>
                                 
                                char *get_next_line(int fd) {
                                    char buffer[100];   // 98 caractères + '\n' + '\0'
                                    int nbc;
                                    int i = 0;
                                    char c;
                                    do {
                                        nbc = read(fd, &c, 1);
                                        if(nbc == 0) break;
                                        buffer[i] = c;
                                        if(i < 98) i++;
                                    } while(c != '\n');
                                    if(nbc == 0 && i == 0) return NULL;
                                    if(i == 98) i++;
                                    buffer[i] = '\0';
                                    size_t size = strlen(buffer) + 1;
                                    char *line = malloc(size);
                                    if(line ==NULL) {
                                        perror("malloc");
                                        fprintf(stderr, "Required: %d\n", size);
                                        exit(EXIT_FAILURE);
                                    }
                                    strcpy(line, buffer);
                                    return line;
                                }
                                 
                                int main(void) {
                                    char *ligne = get_next_line(0);
                                    printf("'%s'", ligne);
                                    free(ligne);
                                }

                                -
                                Edité par PierrotLeFou 17 septembre 2022 à 2:45:32

                                • Partager sur Facebook
                                • Partager sur Twitter

                                Le Tout est souvent plus grand que la somme de ses parties.

                                  17 septembre 2022 à 2:53:24

                                  Ah mais là c'est de la triche aha ! J'y avais pensé aussi mais malheureusement on doit lire BUFFER_SIZE caractères et non 1, d'où le static.

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    17 septembre 2022 à 3:01:27

                                    Tu diras à ton prof que c'est du mauvais design.
                                    L'autre alternative serait de lire tout le fichier d'un coup mais il faut savoir comment trouver sa longueur ...

                                    En fait c'est buffer qui devrait être le tableau statique, tu aurais un tableau statique pour chaque fd.

                                    Et si on faisait:
                                    typedef struct Buffer Buffer;
                                    struct Buffer {
                                        char *line;
                                        int fd;
                                    };
                                    et on déclare:
                                        static Buffer **buffer;

                                    -
                                    Edité par PierrotLeFou 17 septembre 2022 à 3:14:21

                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    Le Tout est souvent plus grand que la somme de ses parties.

                                      17 septembre 2022 à 6:43:34

                                      Bonjour,

                                      Il y a plusieurs points à aborder :

                                      • Les listes en static local

                                      Évidemment c'est possible. Si tu disposes d'une implémentation simple de liste (en gros ⇒ la liste vide est représentée par NULL, chaînage simple, ajout en tête, etc.) alors tu déclares une variable static local que tu initialises à NULL. Le souci avec cette approche dynamique est que cela génère des fuites mémoires à moins d'utiliser un fd spécial (genre -1 ou INTMIN) qui lorsqu'il est passé en paramètre signifie libération de la mémoire allouée pour la liste.
                                      Ce design et comportement est fortement archaïque.

                                      L'alternative est d'utiliser un tableau static local de taille statique MAXFD (≠static, =taille connue au moment de la compilation).La consommation mémoire peut être élevée et de l'ordre de MAXFD×BUFFER_SIZE, sauf si on alloue dynamiquement les éléments mais là on revient au problème de fuite mémoire du point précédent.

                                      • l'utilisation d'un buffer

                                      Un buffer ne doit se faire remplir que lorsqu'on en a besoin, c'est le but même d'une lecture bufferisée = limiter le nombre d'accès à une ressource externe dont l'usage peut être coûteux.

                                      L'algorithme de base, et sache que je suis désolé de faire quitter le monde du codage pour te faire entrer dans celui de la programmation, ressemble donc à :

                                      buffer = obtenir le buffer associé à fd
                                      chaine = ""
                                      
                                      faire
                                      
                                          si buffer est vide alors
                                              remplir buffer
                                          fin si
                                      
                                          tmp = extraire chaine de buffer
                                          concaténer tmp à la fin de chaine
                                      
                                      tant que chaine ne se termine pas par \n et pas d'erreur

                                      En gros il va te falloir :

                                      • une static local pour le couple buffer/fd, ce qui va représenter buffer sera également static ;
                                      • une gestion un peu avancée du buffer qui n'est plus un «simple tableau» mais une structure composée d'un tableau et d'un curseur indiquant la position du prochain caractère et de la position de la dernière donnée valide (car un buffer n'est pas forcément rempli au taquet) ;
                                      • la capacité d'ajouter une chaîne en fin de chaîne dynamiquement (apparemment à coup de malloc/free/malloc au lieu de realloc >_<) ;
                                      struct buffer {
                                          size_t cursor;
                                          size_t end_of_buffer;
                                          bool error;
                                          char data[BUFFERSIZE+1];
                                      };
                                      
                                      struct buffer *get_buffer_for_fd(int fd) {
                                          static struct buffer buffers[MAXFD];
                                          return fd>=0?buffers+fd:NULL;
                                      }
                                      
                                      bool buffer_is_empty(struct buffer *buffer) {
                                          return buffer->cursor==buffer->end_of_buffer;
                                      }
                                      
                                      bool buffer_fill_from_fd(struct buffer *buffer, int fd) {
                                          ssize_t rd=read(fd, buffer->data, BUFFERSIZE);
                                          if (rd==-1) {
                                              buffer->error = true;
                                          } else {
                                              buffer->error = false;
                                              buffer->cursor = 0;
                                              buffer->end_of_buffer = rd;
                                          }
                                          return rd>0;
                                      }

                                      C'est pour te donner une idée de code. La fonction buffer_fill_from_fd renvoie true si une lecture a réussie et que des données sont disponibles, false si une erreur est survenue ou si on atteint la fin de fichier …

                                      À toi de préhistoriser le code pour le rendre XLII-compatible.

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        17 septembre 2022 à 7:33:32

                                        Voici une première ébauche qui ne lit que sur le fd = 0 (stdin).
                                        J'ai délibérément mis une petite valeur pour la longueur du buffer pour tester si ça marchait.
                                        S'il y a trop de caractères sur une ligne, ils sont tronqués. Je garde la fin de ligne.
                                        -
                                        #define BUFFER_SIZE 10
                                        #define LINE_SIZE 60
                                         
                                        #include <unistd.h>
                                        #include <stdio.h>
                                        #include <stdlib.h>
                                        #include <string.h>
                                         
                                        typedef struct Buffer Buffer;
                                        struct Buffer {
                                            int fd;
                                            int pos;
                                            char *buff;
                                        };
                                         
                                        void *ft_malloc(size_t size) {
                                            void *memory = malloc(size);
                                            if(memory) return memory;
                                            perror("malloc");
                                            fprintf(stderr, "Required: %d\n", size);
                                            exit(EXIT_FAILURE);
                                        }
                                         
                                        char *get_next_line(Buffer **buffer, int fd) {
                                            while((*buffer)->fd != fd) buffer++;
                                            Buffer *array = *buffer;
                                            char *line = ft_malloc(LINE_SIZE+1);
                                            int i = -1;
                                            int nbc;
                                            do {
                                                if(array->pos == 0) {
                                                    nbc = read(fd, array->buff, BUFFER_SIZE);
                                                    if(nbc == 0) {
                                                        if(i < 0) {
                                                            free(line);
                                                            return NULL;
                                                        } else {
                                                            line[++i] ='\0';
                                                            return line;
                                                        }
                                                    }
                                                }
                                                if(i < LINE_SIZE-1) i++;
                                                line[i] = array->buff[array->pos];
                                                array->pos = (array->pos + 1) % nbc;
                                            } while(line[i] != '\n');
                                            line[++i] = '\0';
                                            return line;
                                        }
                                         
                                        int main(int argc, char argv[]) {
                                            argc++;
                                            Buffer **buffer = ft_malloc(sizeof(Buffer *) * argc);
                                            buffer[0] = ft_malloc(sizeof(Buffer));
                                            buffer[0]->fd = 0;
                                            buffer[0]->pos = 0;
                                            buffer[0]->buff = ft_malloc(BUFFER_SIZE);
                                            buffer[1] = NULL;
                                            char *ligne = get_next_line(buffer, 0);
                                            printf("'%s'", ligne);
                                            free(ligne);
                                        }

                                        -
                                        Edité par PierrotLeFou 17 septembre 2022 à 7:49:30

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Le Tout est souvent plus grand que la somme de ses parties.

                                          18 septembre 2022 à 7:42:09

                                          Il y a un bug dans ma version précédente. Il faut conserver le nombre de caractèeres lus lors de la dernièere lecture pour chaque fd.
                                          Cette version peut lire sur plusieurs fichiers en changeant de fichier pour chaque ligne.
                                          -
                                          #define BUFFER_SIZE 1000
                                          #define LINE_SIZE 100
                                           
                                          #include <unistd.h>
                                          #include <fcntl.h>
                                          #include <stdio.h>
                                          #include <stdlib.h>
                                           
                                          typedef struct Buffer Buffer;
                                          struct Buffer {
                                              int fd;
                                              int pos;
                                              int nbc;
                                              char *buff;
                                          };
                                           
                                          void *ft_malloc(size_t size) {
                                              void *memory = malloc(size);
                                              if(memory) return memory;
                                              perror("malloc");
                                              fprintf(stderr, "Required: %d\n", size);
                                              exit(EXIT_FAILURE);
                                          }
                                           
                                          Buffer *ft_open(char *name) {
                                              int fd;
                                              if(name == NULL) {
                                                  fd = 0;
                                              } else {
                                                  fd = open(name, O_RDONLY);
                                                  if(fd < 0) {
                                                      perror("open");
                                                      fprintf(stderr, "File '%s'\n", name);
                                                      exit(EXIT_FAILURE);
                                                  }
                                              }
                                              Buffer *buffer = ft_malloc(sizeof(Buffer));
                                              buffer->fd = fd;
                                              buffer->pos = 0;
                                              buffer->nbc = BUFFER_SIZE;
                                              buffer->buff = ft_malloc(BUFFER_SIZE);
                                              return buffer;
                                          }
                                           
                                          void ft_free(Buffer **buffer) {
                                              Buffer **array = buffer;
                                              while(array) {
                                                  free((*array)->buff);
                                                  free(*array);
                                                  array++;
                                              }
                                              free(buffer);
                                          }
                                           
                                          char *get_next_line(Buffer **buffer, int fd) {
                                              while((*buffer)->fd != fd) buffer++;
                                              Buffer *array = *buffer;
                                              if(array->nbc == 0) return NULL;
                                              char *line = ft_malloc(LINE_SIZE+1);
                                              int i = -1;
                                              do {
                                                  if(array->pos == 0) {
                                                      array->nbc = read(fd, array->buff, BUFFER_SIZE);
                                                      if(array->nbc == 0) {
                                                          if(i < 0) {
                                                              free(line);
                                                              return NULL;
                                                          } else {
                                                              line[++i] ='\0';
                                                              return line;
                                                          }
                                                      }
                                                  }
                                                  if(i < LINE_SIZE-1) i++;
                                                  line[i] = array->buff[array->pos];
                                                  array->pos = (array->pos + 1) % array->nbc;
                                              } while(line[i] != '\n');
                                              line[++i] = '\0';
                                              return line;
                                          }
                                           
                                          int main(int argc, char *argv[]) {
                                              Buffer **buffer = ft_malloc(sizeof(Buffer *) * (argc + 1));
                                              if(argc == 1) {
                                                  buffer[0] = ft_open(NULL);
                                              } else {
                                                  argc--;
                                                  argv++;
                                                  for(int nf = 0; nf < argc; nf++) {
                                                      buffer[nf] = ft_open(argv[nf]);
                                                  }
                                              }
                                              buffer[argc] = NULL;
                                              for(int nl = 1; nl <= 5; nl++) {
                                                  for(int nf = 0; buffer[nf]; nf++) {
                                                      int fd = buffer[nf]->fd;
                                                      char *ligne = get_next_line(buffer, fd);
                                                      if(ligne != NULL) printf("fd=%d, ligne %d, '%s'\n", fd, nl, ligne);
                                                      free(ligne);
                                                  }
                                              }
                                              ft_free(buffer);
                                              return 0;
                                          }
                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Le Tout est souvent plus grand que la somme de ses parties.

                                            18 septembre 2022 à 12:09:24

                                            Je crois que si le mot clé "static" figure dans l'énoncé, c'est parce que l'auteur du sujet a en tête une implémentation dans laquelle la fonction get_next_line agit sur un buffer qui lui appartient, et qui est déclaré comme variable statique.

                                            char * get_next_line() 
                                            {
                                                 static char * line = NULL;
                                                 static int length = 0;
                                                 static int capacity = 0;
                                            
                                                 // pour tout caractère tant que c'est pas fin de ligne
                                                 //     si length = capacity:
                                                 //           reallouer la ligne avec une capacité plus grande
                                                 //     mettre le caractère dans line[size++]
                                                 // mettre \0 dans line[size]
                                                 
                                                 return line;
                                            }
                                            
                                            
                                            

                                            Le genre de programmation qui se faisait en C dans les années 70, mais qui est complètement foireux : la fonction cause une fuite mémoire, elle n'est pas réentrante, etc.


                                            Dans une approche plus propre, on définirait un type représentant un "lecteur ligne par ligne", avec une fonction pour chaque opération qu'on veut faire dessus : l'initialiser (en ouvrant un fichier), demander à lire une ligne, le fermer.

                                            -
                                            Edité par michelbillaud 18 septembre 2022 à 12:13:21

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              18 septembre 2022 à 14:50:38

                                              Je devais être fatigué quand j'ai écrit mes codes. J'ai oublié ma fonction ft_close() qui fermerait tous les fichiers.
                                              Et pas de statique dans mon code. Pis ça marche. :)

                                              Les "ft_" c'est une satire des écoles XLII ...

                                              -
                                              Edité par PierrotLeFou 18 septembre 2022 à 14:51:45

                                              • Partager sur Facebook
                                              • Partager sur Twitter

                                              Le Tout est souvent plus grand que la somme de ses parties.

                                                21 septembre 2022 à 17:55:09

                                                Merci pour vos réponses.
                                                PierrotLeFou, merci de l'aide que tu fournis seulement tu fais l'exercice à ta sauce et non comme le veut l'énoncé du coup ça n'a pas grande utilité pour moi ^^

                                                Comme l'a dit michelbillaud,

                                                michelbillaud a écrit:

                                                la fonction get_next_line agit sur un buffer qui lui appartient, et qui est déclaré comme variable statique.

                                                 Aussi en essayant de compléter l'exo grâce à vos dires, je me suis rendu compte d'un truc.

                                                PierrotLeFou, tu as considéré que argc était le nombre de fichiers à ouvrir or on ne connait pas la taille justement ; Combien de fichiers allons-nous ouvrir ? C'est seulement en rappelant la fonction get_nextline avec un fd différent qu'on se rendra compte que c'est un fichier différent, et ça, ça fait une grande différence dans le code, enfin pour moi, car je dois rajouter à chaque fois une case dans le tableau si le fd n'est pas trouvé.
                                                Et du coup, que ce soit à la sauce de White Crow ou bien PierrotLeFou, le problème y est quand même.

                                                Admettons que j'ai deux fichiers à ouvrir et que l'un deux se finit avant l'autre, je free le fd en question dans le tableau et le passe à NULL

                                                free(tab[pos])
                                                tab[pos] = NULL;

                                                Il y aura un problème.

                                                Si le fd que je viens de fermer est le fd 3 et que le fichier non terminer est le fd 4, je ne peux pas accéder à cette élément puisque celui d'avant est NULL et donc en parcourant mon tableau, logiquement je m'arrête au premier NULL rencontré. Et c'est là que tout se complique.

                                                Alors j'ai eu une idée " deguelasse " il faut le dire c'est qu'au lieu de le mettre à NULL je lui met un \0 au premier caractère.

                                                Seulement si je fais ça, je dois aussi m'assurer qu'est-ce que ce \0 signifie ?

                                                Signifie-t-il la fin du fichier lu ou la fin du buffer ?

                                                Pour ça j'ai une fonction qui va parcourir tout mon tableau et vérifier s'il toutes les premières cases sont == \0 si oui alors je peux tout free mais avant de faire ça il faut vérifier que ce n'est pas simplement la fin de mon buffer, parce-que si cela se trouve je peux lire encore dans le fichier.
                                                Et franchement, rien que vous racontez tout cela devient très fastidieux et du n'importe quoi.

                                                Résultat des courses: fuite de mémoire et même avec leaks (permet detecter les fuites de mémoire) qui me montre où sont mes fuites, j'y arrive pas.

                                                J'arrive pas à corriger mes fuites de mémoire. Et comme vous proposez chacun de vous, d'utiliser un tableau je présume que c'est la meilleure solution, que ce soit un tableau de char * ou un tableau de struct cela revient au même.


                                                Voici ce que cela donne, pour un fichier contenant

                                                a\n
                                                b\n
                                                c\n
                                                d\n
                                                e\n
                                                EOF
                                                leaks Report Version: 3.0
                                                Process 11066: 176 nodes malloced for 13 KB
                                                Process 11066: 6 leaks for 96 total leaked bytes.
                                                
                                                Leak: 0x7f93aac05b00  size=16  zone: DefaultMallocZone_0x10fd11000   length: 2  "d
                                                "
                                                        Call stack: 0x7fff204fdf3d (libdyld.dylib) start | 0x10fcedeb5 (a.out) main  main.c:10 | 0x10fcedbcb (a.out) get_next_line  get_next_line_bonus.c:144 | 0x7fff2040ebdb (libsystem_c.dylib) strndup | 0x7fff20323fb7 (libsystem_malloc.dylib) _malloc_zone_malloc 
                                                
                                                Leak: 0x7f93aac05b10  size=16  zone: DefaultMallocZone_0x10fd11000   length: 2  "e
                                                "
                                                        Call stack: 0x7fff204fdf3d (libdyld.dylib) start | 0x10fcedeb5 (a.out) main  main.c:10 | 0x10fcedbcb (a.out) get_next_line  get_next_line_bonus.c:144 | 0x7fff2040ebdb (libsystem_c.dylib) strndup | 0x7fff20323fb7 (libsystem_malloc.dylib) _malloc_zone_malloc 
                                                
                                                Leak: 0x7f93aac05bd0  size=16  zone: DefaultMallocZone_0x10fd11000
                                                        Call stack: 0x7fff204fdf3d (libdyld.dylib) start | 0x10fcedeb5 (a.out) main  main.c:10 | 0x10fceda95 (a.out) get_next_line  get_next_line_bonus.c:129 | 0x10fced881 (a.out) get_line_by_fd  get_next_line_bonus.c:83 | 0x7fff20323fb7 (libsystem_malloc.dylib) _malloc_zone_malloc 
                                                
                                                Leak: 0x7f93aac05c20  size=16  zone: DefaultMallocZone_0x10fd11000   length: 2  "b
                                                "
                                                        Call stack: 0x7fff204fdf3d (libdyld.dylib) start | 0x10fcedeb5 (a.out) main  main.c:10 | 0x10fcedbcb (a.out) get_next_line  get_next_line_bonus.c:144 | 0x7fff2040ebdb (libsystem_c.dylib) strndup | 0x7fff20323fb7 (libsystem_malloc.dylib) _malloc_zone_malloc 
                                                
                                                Leak: 0x7f93aac05c30  size=16  zone: DefaultMallocZone_0x10fd11000   length: 2  "a
                                                "
                                                        Call stack: 0x7fff204fdf3d (libdyld.dylib) start | 0x10fcedeb5 (a.out) main  main.c:10 | 0x10fcedbcb (a.out) get_next_line  get_next_line_bonus.c:144 | 0x7fff2040ebdb (libsystem_c.dylib) strndup | 0x7fff20323fb7 (libsystem_malloc.dylib) _malloc_zone_malloc 
                                                
                                                Leak: 0x7f93aac05c40  size=16  zone: DefaultMallocZone_0x10fd11000   length: 2  "c
                                                "
                                                        Call stack: 0x7fff204fdf3d (libdyld.dylib) start | 0x10fcedeb5 (a.out) main  main.c:10 | 0x10fcedbcb (a.out) get_next_line  get_next_line_bonus.c:144 | 0x7fff2040ebdb (libsystem_c.dylib) strndup | 0x7fff20323fb7 (libsystem_malloc.dylib) _malloc_zone_malloc 

                                                Et mon code, j'ai viré tous les ft_ sauf ft_strjoin

                                                #include "get_next_line_bonus.h"
                                                
                                                void	*freetab(char **buffer, int current)
                                                {
                                                	int		count;
                                                	int		i;
                                                
                                                	i = 0;
                                                	count = 0;
                                                	while (buffer[i])
                                                	{
                                                		if (buffer[i][0] != 0)
                                                			count++;
                                                		i++;
                                                	}
                                                	if (count == 0)
                                                	{
                                                		i = -1;
                                                		while (buffer[++i])
                                                			free(buffer[i]);
                                                		free(buffer);
                                                		buffer = NULL;
                                                	}
                                                	else
                                                	{
                                                		free(buffer[current]);
                                                		buffer[current] = malloc(1);
                                                		buffer[current][0] = 0;
                                                	}
                                                	return (buffer);
                                                }
                                                
                                                char	**arraydup(char **src)
                                                {
                                                	char	**dst;
                                                	int		i;
                                                
                                                	if (!src)
                                                		return (src);
                                                	i = 0;
                                                	while (src[i])
                                                		i++;
                                                	i++;
                                                	dst = malloc(sizeof(char *) * (i + 1));
                                                	if (!dst)
                                                		return (dst);
                                                	dst[i] = 0;
                                                	dst[--i] = malloc(1);
                                                	dst[i][0] = '\0';
                                                	while (--i >= 0)
                                                		dst[i] = strdup(src[i]);
                                                	return (dst);
                                                }
                                                
                                                char	**get_line_by_fd(int fd, char **buffer)
                                                {
                                                	char	**res;
                                                	int		size;
                                                
                                                	if (!buffer)
                                                	{
                                                		size = fd;
                                                		if (fd == 0)
                                                			size = 2;
                                                		buffer = malloc(sizeof(char *) * size);
                                                		if (buffer)
                                                		{
                                                			buffer[--size] = 0;
                                                			while (--size >= 0)
                                                			{
                                                				buffer[size] = malloc(1);
                                                				if (!buffer[size])
                                                					return (freetab(buffer, 0));
                                                				buffer[size][0] = '\0';
                                                			}
                                                		}
                                                		return (buffer);
                                                	}
                                                	if (buffer[fd == 0 ? fd : fd - 2])
                                                		return (buffer);
                                                	res = arraydup(buffer);
                                                	freetab(buffer, 0);
                                                	return (res);
                                                }
                                                
                                                int		readuntil(int fd, char **bufferline)
                                                {
                                                	char	buff[BUFFER_SIZE + 1];
                                                	int		byteread;
                                                
                                                	byteread = 1;
                                                	while (byteread)
                                                	{
                                                		byteread = read(fd, buff, BUFFER_SIZE);
                                                		if (byteread < 0)
                                                			return (0);
                                                		buff[byteread] = 0;
                                                		if (byteread == 0)
                                                			break ;
                                                		ft_strjoin(bufferline, buff, byteread);
                                                		if (strchr(buff, '\n'))
                                                			break ;
                                                	}
                                                	return (1);
                                                }
                                                
                                                char	*get_next_line(int fd)
                                                {
                                                	static char	**buffer;
                                                	char		*temp;
                                                	char		*tmp;
                                                	char		*endl;
                                                	int			pos;
                                                
                                                	if (fd < 3 && fd != 0)
                                                		return (freetab(buffer, 0));
                                                	buffer = get_line_by_fd(fd, buffer);
                                                	pos = (fd == 0 ? fd : fd - 2);
                                                	if (!buffer || !buffer[pos])
                                                		return (NULL);
                                                	if (!readuntil(fd, buffer + pos))
                                                		return (NULL);
                                                	endl = strchr(buffer[pos], '\n');
                                                	if (!endl)
                                                	{
                                                		tmp = NULL;
                                                		if (buffer[pos][0])
                                                			tmp = strdup(buffer[pos]);
                                                		freetab(buffer, pos);
                                                		return (tmp);
                                                	}
                                                	temp = strndup(buffer[pos], endl - buffer[pos] + 1);
                                                	if (temp)
                                                	{
                                                		tmp = strdup(endl + 1);
                                                		free(buffer[pos]);
                                                		buffer[pos] = tmp;
                                                	}
                                                	return (temp);
                                                }
                                                

                                                Si vous pouvez m'aider encore un peu svp, je vous en remercie!

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  21 septembre 2022 à 18:47:06

                                                  @AlexDorian2:
                                                  > PierrotLeFou, merci de l'aide que tu fournis seulement tu fais l'exercice à ta sauce et non comme le veut l'énoncé du coup ça n'a pas grande utilité pour moi
                                                  Comme je l'ai dit, l'énoncé n'a pas beaucoup de sens.
                                                  Si tu atteints la fin de fichier pour tous les fichiers, comment le sais-tu?
                                                  Est-ce que tu vas tester si tous les fichiers sont lus à chaque lecture demandée?
                                                  > PierrotLeFou, tu as considéré que argc était le nombre de fichiers à ouvrir or on ne connait pas la taille justement ; Combien de fichiers allons-nous
                                                  > ouvrir ?
                                                  Si tu ne prends pas le nombre de fichiers dans argc, où les prends-tu?
                                                  Ou je n'ai encore rien compris ... Le fichier fournit en entrée donne les noms des fichiers à traiter?
                                                  Dans mon code, je testais des fichiers de moins de 5 lignes.
                                                  Le point important est d'initialiser le nombre de mots lus (nbc dans mon code) à la valeur maximum (BUFFER_SIZE).
                                                  Quand on atteint la fin du fichier, le champs  nbc  doit être à 0 et y rester.
                                                  Je ne libère aucune structure avant la fin.
                                                  Tu n'as qu'à tester si le pointeur vers la ligne reçue est NULL pour savoir s'il y a une ligne.
                                                  Quand à savoir s'il faut utiliser un tableau ou lune liste chaînée, auras-tu vraiment beaucoup de fichiers à lire en même temps?

                                                  Si tu choisis un tableau, tu devras également garder en statique le nombre de structures que tu as réservées.

                                                  -
                                                  Edité par PierrotLeFou 21 septembre 2022 à 19:06:04

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter

                                                  Le Tout est souvent plus grand que la somme de ses parties.

                                                    21 septembre 2022 à 20:07:46

                                                     PierrotLeFou a écrit:

                                                    Si tu atteints la fin de fichier pour tous les fichiers, comment le sais-tu?

                                                     Je ne peux pas le savoir.. C'est bien toute la difficulté de mon code

                                                    PierrotLeFou a écrit:

                                                    Est-ce que tu vas tester si tous les fichiers sont lus à chaque lecture demandée?

                                                     Non mais justement je cherche une idée comme celle-là qui demande pas trop de complications.

                                                    PierrotLeFou a écrit:

                                                    Si tu ne prends pas le nombre de fichiers dans argc, où les prends-tu?

                                                     C'est en rappelant la fonction get_next_line qu'on doit déterminer sur quel fichier on est et allouer la place nécessaire si ce n'est pas le cas.

                                                    Voici un main de test basic que j'utilise:

                                                    #include "get_next_line.h"
                                                    #include <stdio.h>
                                                    int		main(int ac, char **av)
                                                    {
                                                    	(void)ac;
                                                    	char	*res;
                                                    	int		fd = open(av[1], O_RDONLY);
                                                    	int		fd2 = open(av[2], O_RDONLY);
                                                    	int		fd3 = open(av[3], O_RDONLY);
                                                    
                                                    	res = get_next_line(fd);
                                                    	printf("1: %s", res);
                                                    	res = get_next_line(fd2);
                                                    	printf("2: %s", res);
                                                    	res = get_next_line(fd3);
                                                    	printf("3: %s", res);
                                                    	res = get_next_line(fd);
                                                    	printf("4: %s", res);
                                                    	res = get_next_line(fd2);
                                                    	printf("5: %s", res);
                                                    	res = get_next_line(fd3);
                                                    	printf("6: %s", res);
                                                    	res = get_next_line(fd);
                                                    	printf("7: %s", res);
                                                    	res = get_next_line(fd2);
                                                    	printf("8: %s", res);
                                                    	res = get_next_line(fd3);
                                                    	printf("9: %s", res);
                                                    	res = get_next_line(fd);
                                                    	printf("10: %s", res);
                                                    	res = get_next_line(fd2);
                                                    	printf("11: %s", res);
                                                    	res = get_next_line(fd3);
                                                    	printf("12: %s", res);
                                                    	res = get_next_line(fd);
                                                    	printf("13: %s", res);
                                                    	res = get_next_line(fd2);
                                                    	printf("14: %s", res);
                                                    	res = get_next_line(fd3);
                                                    	printf("15: %s", res);
                                                    	res = get_next_line(fd);
                                                    	printf("16: %s", res);
                                                    	res = get_next_line(fd2);
                                                    	printf("17: %s", res);
                                                    	res = get_next_line(fd3);
                                                    	printf("18: %s", res);
                                                    
                                                    	close(fd);
                                                    	close(fd2);
                                                    	close(fd3);
                                                    	return (0);
                                                    }

                                                    Et ça fonctionne plutôt bien seulement j'ai des leaks..

                                                    Et donc en gros, à chaque fois qu'il rentre dans la fonction il check si fd position existe sinon il sauvegarde buffer et le delete puis le recréer avec une case en plus grace a arraydup (nom pas très explicite, je sais).

                                                    PierrotLeFou a écrit:

                                                    Tu n'as qu'à tester si le pointeur vers la ligne reçue est NULL pour savoir s'il y a une ligne. 

                                                     j'avoue ne pas bien comprendre étant donné le problème exposé plus tôt.

                                                    PierrotLeFou a écrit:

                                                    Quand à savoir s'il faut utiliser un tableau ou lune liste chaînée, auras-tu vraiment beaucoup de fichiers à lire en même temps?

                                                     Honnêtement non, c'est juste pour l'exercice.

                                                    PierrotLeFou a écrit:

                                                    Si tu choisis un tableau, tu devras également garder en statique le nombre de structures que tu as réservées.

                                                    Pour le coup, j'ai choisi un tableau de chaine de caractère et je ne comprend pas pourquoi dis-tu ça ?

                                                    Seul le double tableau est en static et non les char * à l'intérieur.

                                                    Merci encore de ton aide !

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      22 septembre 2022 à 0:17:42

                                                      Je lis ceci:
                                                          int     fd = open(av[1], O_RDONLY);
                                                          int     fd2 = open(av[2], O_RDONLY);
                                                          int     fd3 = open(av[3], O_RDONLY);
                                                      Si je suis sadique et que je ne met qu'un nom sur la commande d'appel, ça va planter. :)
                                                      Tu dis que argc ne te donne pas le nombre de fichiers. C'est pourtant le cas.
                                                      >  C'est en rappelant la fonction get_next_line qu'on doit déterminer sur quel fichier on est et allouer la place nécessaire si ce n'est pas le cas.
                                                      Pas de problème pour ça. Mais ça ne dit pas combien de fichiers tu auras.
                                                      Si le programme est stupide et lit toujours sur le même fichier, tu ne sauras jamais combien de fichiers tu as.

                                                      Ensuite:
                                                          res = get_next_line(fd3);
                                                          printf("18: %s", res);
                                                      Ça suppose que j'ai au moins 6 lignes pour chaque fichier. Qu'est-ce que la fonction va retourner s'il y en a moins?
                                                      Dans mon code, je teste si nbc est 0 après la lecture. Ça devrait indiquer la fin du fichier (on peut tester un peu plus pour voir si ce n'est pas une erreur).
                                                      C'est sans doute à ce moment qu'on pourrait tester si tous les fichiers sont rendus à la fin et tout libbérer

                                                      Quelle longueur réserveras-tu pour ton tableau de structures si tu ne sais pas le nombre de fichiers??

                                                      Tu fais un malloc pour le premier et le pointeur NULL ensuite.

                                                      Ensuite tu fais un realloc pour augmenter. C'est bien ¸¸ca?

                                                      Tu n'as effectivement pas besoin de sauver la longueur du tableau.

                                                      Si tu as peu de fichiers, le truc est correct. Sinon tu auras des problèmes de mémoire encore une fois. :)

                                                      edit:
                                                      Dans arraydup:
                                                              dst[i] = strdup(src[i]);
                                                      Pourquoi? Tu es censé recopier des pointeurs, pas autre chose.
                                                      Le premier leak est justement parce que tu ne libères pas ces chaînes.
                                                      Ensuite, tu dois libérer src si tu n'en a plus besoin.
                                                      C'est une façon compliquée de faire un  realloc() ...

                                                      char    **arraydup(char **src) {
                                                          if(! src) return src;
                                                          char **tmp = src;
                                                          while(*tmp++);   // Pointera après le NULL
                                                          int i = tmp - src;   // Ancienne longueur.
                                                          char **dst = realloc(src, sizeof(char *) * (i+1));
                                                          if(! dst) return dst;
                                                          dst[i] = NULL;
                                                          dst[--i] = malloc(1);   // On réserve un seul espace pour le buffer ??
                                                          dst[i][0] = '\0';
                                                          return dst;
                                                      }

                                                      Une autre difficulté que tu n'as sans doute pas vue:
                                                          static char **buffer = NULL;    // Tu n'as pas le choix, tu n'as rien éservé.
                                                          // Plus tard:
                                                          char **buffer = malloc(sizeof(char *));    // Un seul pointeur.
                                                          buffer[0] = NULL;    // tableau existant mais vide.
                                                          // ou bien:
                                                          *buffer = NULL;
                                                      Sauras-tu faire la différence entre un tableau inexistant et un tableau vide?

                                                      De toute façon, si c'est la fonction qui contrôle la mémoire dynamique et que le main ne lit pas toutes les lignes de tous les fichiers, ce dernier ne pourra pas libérer la mémoire à la fin.

                                                      -
                                                      Edité par PierrotLeFou 22 septembre 2022 à 4:50:37

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter

                                                      Le Tout est souvent plus grand que la somme de ses parties.

                                                        22 septembre 2022 à 8:24:47

                                                        Ah, aussi dans le sujet 

                                                        > UNE SEULE variable statique

                                                        Si il y en a plusieurs, les mettre dans une structure,..

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          24 septembre 2022 à 1:54:34

                                                          Merci pour votre aide précieuse.

                                                          J'ai maintenant pu résoudre tous mes soucis d'allocations et autres.. je n'ai plus un seul leak et il passe tous les tests au checker de l'école, il me reste plus que la refacto et c'est carré !

                                                          Merci encore et bonne soirée à vous !

                                                          PierrotLeFou a écrit:

                                                          Je lis ceci:
                                                              int     fd = open(av[1], O_RDONLY);
                                                              int     fd2 = open(av[2], O_RDONLY);
                                                              int     fd3 = open(av[3], O_RDONLY);
                                                          Si je suis sadique et que je ne met qu'un nom sur la commande d'appel, ça va planter. :)
                                                          Tu dis que argc ne te donne pas le nombre de fichiers. C'est pourtant le cas.

                                                          > Oui enfin c'est mon main de test à l'arrache ^^

                                                          > Non, ok ici c'est un très mauvais exemple mais je peux rentrer directement le nom du fichier sans passer par la paramètres du main

                                                          PierrotLeFou a écrit:

                                                          >  C'est en rappelant la fonction get_next_line qu'on doit déterminer sur quel fichier on est et allouer la place nécessaire si ce n'est pas le cas.
                                                          Pas de problème pour ça. Mais ça ne dit pas combien de fichiers tu auras.
                                                          Si le programme est stupide et lit toujours sur le même fichier, tu ne sauras jamais combien de fichiers tu as. 

                                                          > Si, enfin encore une fois je m'exprime mal. C'est surtout le fd qui déterminera dans mon static buffer combien de fichiers(place) j'aurais.
                                                          > Impossible encore une fois, car c'est le fd qui détermine cela et donc si j'ouvre plusieurs fichier et lui envoie il saura(read) que c'est un fd différent.

                                                          PierrotLeFou a écrit:

                                                          Ensuite:

                                                              res = get_next_line(fd3);
                                                              printf("18: %s", res);
                                                          Ça suppose que j'ai au moins 6 lignes pour chaque fichier. Qu'est-ce que la fonction va retourner s'il y en a moins?
                                                          Dans mon code, je teste si nbc est 0 après la lecture. Ça devrait indiquer la fin du fichier (on peut tester un peu plus pour voir si ce n'est pas une erreur).

                                                          Encore encore une fois ^^ c'est ma faute et mes tests maison bidon que tu arrives pas y voir clair, c'est vraiment aléatoire le nombre d'appel à gnl que j'ai fait ici 18 en l'occurrence. Et s'il y en a moins, elle retourne NULL. Et effectivement, c'est comme ça que j'ai procédais pour vérifier la fin du fichier.

                                                          PierrotLeFou a écrit:

                                                          Tu fais un malloc pour le premier et le pointeur NULL ensuite.

                                                          Ensuite tu fais un realloc pour augmenter. C'est bien ¸¸ca?

                                                          Oui c'est ça enfin pour être exact seulement si fd == 0 car si le fd != 0, ce qui signifie qu'il commence à 1 vu qu'on peut pas prendre la place du stdin et donc là y aura [0] = "" [1] = "" [2] = NULL et ainsi de suite pour un plus grand fd

                                                          Et oui je realloc

                                                          Et si je l'ai fait de cette façon, la version finale:

                                                          char	**popmem(char **src, int msize)
                                                          {
                                                          	char	**res;
                                                          	int		i;
                                                          	int		k;
                                                          
                                                          	i = 0;
                                                          	res = malloc(sizeof(char *) * msize);
                                                          	if (res)
                                                          	{
                                                          		k = -1;
                                                          		while (src[++k])
                                                          			res[k] = strdup(src[k]);
                                                          		while (k < msize - 1)
                                                          		{
                                                          			res[k] = strdup("");
                                                          			k++;
                                                          		}
                                                          		res[k] = NULL;
                                                          	}
                                                          	ft_freetab(src, msize);
                                                          	return (res);
                                                          }

                                                          C'est pour save tous ce qu'il y a dans src puis ajouter malloc(1) et [0] = '\0' à tous les autres avec strdup("")

                                                          Merci encore !

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter

                                                          Créer une liste chainée static ?

                                                          × 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.
                                                          • Editeur
                                                          • Markdown