TP1 - Correction

ppompeani_chain.c

#include <stdio.h>
#include <stdlib.h>

struct chain {
  int value;
  struct chain *next;
};

typedef struct chain chain_t;

chain_t *chain_new(int value, chain_t *next) {
  chain_t *ret = (chain_t *)malloc(sizeof(chain_t));
  ret->value = value;
  ret->next = next;
  return ret;
}

chain_t *chain_insert(chain_t *list, int value) {
  return chain_new(value, list);
}

// Les fonctions suivantes sont écrites en récursif
// Et en itératif avec `_iterate`

chain_t *chain_append(chain_t *list, int value) {
  // Le cas particulier est toujours quand la liste vaut NULL :
  // Ça veut dire qu'on est au bout de la liste chaînée.
  if (list == NULL) {
    return chain_new(value, NULL);
  }
  // On met à jour le next de notre structure.
  // Ce sera une opération inutile en général,
  // à part quand on est le dernier maillon de la chaine
  list->next = chain_append(list->next, value);
  return list;
}

chain_t *chain_append_iterate(chain_t *list, int value) {
  // On crée un nouveau bloc
  chain_t *new_item = chain_new(value, NULL);

  if (list == NULL) {
    return new_item;
  }

  // À la fin du while,
  // iter pointe vers le dernier bloc de la chaine
  chain_t *iter = list;
  while (iter->next != NULL) {
    iter = iter->next;
  }
  iter->next = new_item;

  return list;
}

chain_t *chain_find(chain_t *list, int value) {
  if (list == NULL) {
    return NULL;
  }
  if (list->value == value) {
    return list;
  }
  return chain_find(list->next, value);
}

chain_t *chain_find_iterate(chain_t *list, int value) {
  chain_t *iter = list;
  while (iter != NULL) {
    if (iter->value == value) {
      return iter;
    }
    iter = iter->next;
  }
  return NULL;
}

void chain_free(chain_t *list) {
  if (list != NULL) {
    chain_free(list->next);
    free(list);
  }
}

void chain_free_iterate(chain_t *list) {
  chain_t *iter = list;
  while (iter != NULL) {
    // On conserve d'abord un pointeur vers l'élément suivant
    chain_t *next = iter->next;
    // On peut maintenant libérer l'élément actuel
    free(iter);
    // On met à jour notre itérateur vers l'élément suivant
    iter = next;
  }
}

chain_t *chain_copy(chain_t *list) {
  if (list == NULL) {
    return NULL;
  }
  return chain_new(list->value, chain_copy(list->next));
}

chain_t *chain_copy_iterate(chain_t *list) {
  if (list == NULL) {
    return NULL;
  }
  // Itérateur sur la liste originale
  chain_t *iter = list->next;
  // Pointeur sur le premier élément de la nouvelle liste
  chain_t *new_list = chain_new(list->value, NULL);
  // Itérateur sur la nouvelle liste
  chain_t *iter_copy = new_list;

  while (iter != NULL) {
    // On crée un nouveau bloc
    chain_t *new_block = chain_new(iter->value, NULL);
    // On l'ajoute à la suite de notre nouvelle liste
    iter_copy->next = new_block;
    // On fait pointer notre itérateur sur le nouvel élément
    iter_copy = new_block;
    // On passe à l'élément suivant de la liste originale
    iter = iter->next;
  }
  // On retourne le pointeur sur le premier élément
  return new_list;
}

void chain_print(chain_t *list) {
  if (list != NULL) {
    // Sur le dernier élément, on affiche un retour à la ligne
    if (list->next == NULL) {
      printf("%d\n", list->value);
    // Sinon on affiche une virgule 
    // et on rappelle la fonction sur l'élément suivant
    } else {
      printf("%d, ", list->value);
      chain_print(list->next);
    }
  }
}

void chain_print_iterate(chain_t *list) {
  chain_t *iter = list;
  // Tant qu'on est pas sur le dernier élément,
  // on affiche une virgule
  while (iter->next != NULL) {
    printf("%d, ", iter->value);
    iter = iter->next;
  }
  // Sur le dernier élément, on affiche un retour à la ligne
  // On teste si l'élément n'est pas NULL,
  // pour le cas d'une liste vide
  if (iter != NULL) {
    printf("%d\n", iter->value);
  }
}

int main(int argc, char **argv) {
  chain_t *my_list =
    chain_new(1,
      chain_new(2,
        chain_new(3,
            chain_new(4, NULL)
        )
      )
    );

  chain_print(my_list);

  chain_t *new_list = chain_copy(my_list);

  chain_free(my_list);

  chain_print(new_list);

  chain_t *list_from_3 = chain_find(new_list, 3);

  chain_print(list_from_3);

  list_from_3 = chain_append(list_from_3, 5);

  chain_print(new_list);

  return EXIT_SUCCESS;
}

ppompeani_grep.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// file ne doit pas être NULL
// le char* retourné doit être libéré
// retourne NULL quand EOF est atteint
char *readline(FILE *file) {
  char *buffer = NULL;
  int size = 0;

  char c = fgetc(file);
  while (c != EOF && c != '\n') {
    size += 1;
    buffer = (char *)realloc(buffer, size * sizeof(char));
    buffer[size - 1] = c;
    c = fgetc(file);
  }

  if (c == EOF && size == 0) {
    return NULL;
  }

  buffer = (char *)realloc(buffer, size + 1 * sizeof(char));
  buffer[size] = '\0';
  return buffer;
}

// file ne doit pas être NULL
// needle ne doit pas être NULL
void grep(FILE *file, char *needle) {
  char *line;
  line = readline(file);
  while (line != NULL) {
    // man 3 strstr
    if (strstr(line, needle) != NULL) {
      printf("%s\n", line);
    }
    free(line);
    line = readline(file);
  }
}

// argv[1] : le texte qu'on cherche
// argv[2] : le fichier à ouvrir
int main(int argc, char **argv) {

  if (argc != 3) {
    printf("Je veux 2 arguments, pas %d.\n", argc - 1);
    return EXIT_FAILURE;
  }

  FILE *file = fopen(argv[2], "r");

  if (file == NULL) {
    printf("Erreur à l'ouverture du fichier\n");
    return EXIT_FAILURE;
  }

  grep(file, argv[1]);

  fclose(file);

  return EXIT_SUCCESS;
}