web-dev-qa-db-fra.com

Lecture d'un fichier caractère par caractère en C

Salut tout le monde, j'écris un interpréteur BF en C et j'ai rencontré un problème de lecture des fichiers. J'avais l'habitude d'utiliser scanf pour lire la première chaîne, mais vous ne pouviez pas avoir d'espaces ou de commentaires dans votre code BF.

Voici maintenant ce que j'ai.

char *readFile(char *fileName)
{
  FILE *file;
  char *code = malloc(1000 * sizeof(char));
  file = fopen(fileName, "r");
  do 
  {
    *code++ = (char)fgetc(file);

  } while(*code != EOF);
  return code;
}

Je sais que le problème se pose dans la façon dont j'attribue le caractère suivant dans le fichier au pointeur de code, mais je ne suis tout simplement pas sûr de ce que c'est.
Ma connaissance du pointeur fait défaut, ce qui est le point de cet exercice. L'interprète fonctionne très bien, tous utilisant des pointeurs, j'ai juste un problème pour y lire des fichiers.

(Je vais implémenter uniquement la lecture "+ -> <[].") Dans le fichier plus tard, bien que si quelqu'un a un bon moyen de le faire, ce serait bien si vous me le fais savoir!)

Merci d'avance

27
Devan Buggay

Il y a un certain nombre de problèmes avec votre code:

char *readFile(char *fileName)
{
    FILE *file;
    char *code = malloc(1000 * sizeof(char));
    file = fopen(fileName, "r");
    do 
    {
      *code++ = (char)fgetc(file);

    } while(*code != EOF);
    return code;
}
  1. Que faire si le fichier dépasse 1 000 octets?
  2. Vous augmentez code chaque fois que vous lisez un caractère et vous renvoyez code à l'appelant (même s'il ne pointe plus vers le premier octet du bloc de mémoire tel qu'il a été renvoyé par malloc).
  3. Vous transformez le résultat de fgetc(file) en char. Vous devez vérifier EOF avant de transtyper le résultat en char.

Il est important de conserver le pointeur d'origine renvoyé par malloc afin de pouvoir le libérer plus tard. Si nous ignorons la taille du fichier, nous pouvons toujours y parvenir avec les éléments suivants:

char *readFile(char *fileName)
{
    FILE *file = fopen(fileName, "r");
    char *code;
    size_t n = 0;
    int c;

    if (file == NULL)
        return NULL; //could not open file

    code = malloc(1000);

    while ((c = fgetc(file)) != EOF)
    {
        code[n++] = (char) c;
    }

    // don't forget to terminate with the null character
    code[n] = '\0';        

    return code;
}

Il existe différents appels système qui vous donneront la taille d'un fichier; un exemple courant est stat .

35
dreamlax

Développer le code ci-dessus de @dreamlax

char *readFile(char *fileName) {
    FILE *file = fopen(fileName, "r");
    char *code;
    size_t n = 0;
    int c;

    if (file == NULL) return NULL; //could not open file
    fseek(file, 0, SEEK_END);
    long f_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    code = malloc(f_size);

    while ((c = fgetc(file)) != EOF) {
        code[n++] = (char)c;
    }

    code[n] = '\0';        

    return code;
}

Cela vous donne la longueur du fichier, puis procède à sa lecture caractère par caractère.

8
Justin

Voici un moyen simple d'ignorer tout, sauf les personnages de brainfuck valides:

#define BF_VALID "+-><[].,"

if (strchr(BF_VALID, c))
    code[n++] = c;
2
caf

le fichier est ouvert et non fermé pour chaque appel à la fonction également

2
Mandrake

Je pense que le problème le plus important est que vous incrémentez code pendant que vous lisez des trucs, puis que vous retournez la valeur finale de code, c'est-à-dire que vous retournerez un pointeur vers le fin de la chaîne. Vous voudrez probablement faire une copie de code avant la boucle, et la retourner à la place.

De plus, les chaînes C doivent être terminées par null. Vous devez vous assurer que vous placez un '\0' Directement après le dernier caractère que vous lisez.

Remarque: Vous pouvez simplement utiliser fgets() pour obtenir la ligne entière en une seule fois.

2
Oliver Charlesworth

L'un ou l'autre devrait faire l'affaire -

char *readFile(char *fileName)
{
  FILE *file;
  char *code = malloc(1000 * sizeof(char));
  char *p = code;
  file = fopen(fileName, "r");
  do 
  {
    *p++ = (char)fgetc(file);
  } while(*p != EOF);
  *p = '\0';
  return code;
}

char *readFile(char *fileName)
{
  FILE *file;
  int i = 0;
  char *code = malloc(1000 * sizeof(char));
  file = fopen(fileName, "r");
  do 
  {
    code[i++] = (char)fgetc(file);
  } while(code[i-1] != EOF);
  code[i] = '\0'
  return code;
}

Comme les autres affiches l'ont souligné, vous devez vous assurer que la taille du fichier ne dépasse pas 1000 caractères. N'oubliez pas non plus de libérer la mémoire lorsque vous avez fini de l'utiliser.

1
Prav

Le problème est double: a) vous incrémentez le pointeur avant de vérifier la valeur lue, et b) vous ignorez le fait que fgetc () renvoie un int au lieu d'un char.

Le premier est facilement réparable:

char *orig = code; // the beginning of the array
// ...
do {
  *code = fgetc(file);
} while(*code++ != EOF);
*code = '\0'; // nul-terminate the string
return orig; // don't return a pointer to the end

Le deuxième problème est plus subtil - fgetc retourne un int qui que la valeur EOF peut être distinguée de toute valeur chsr possible. La correction utilise un int temporaire pour EOF = check et probablement une boucle while régulière au lieu de do/while.

1
Chris Lutz