2 votes

Pourquoi ce programme n'affiche-t-il pas sans cesse la première ligne ?

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

char *readLine(FILE *inFile)  //Simply reads line in a text file till "\n"
{
    char *line = realloc(NULL, 1);
    char c;
    int i=0;
    while (!feof(inFile))
    {
        c = fgetc(inFile);
        if (ferror(inFile)) printf("Error reading");
        if (c == 10)
            {
                realloc(line,i+1);
                line[i]= 10;
                break;
            }
        realloc(line, i+1);
        line[i++] = c;
    }
    return line;
}

int main(int argc,char **argv)
{
    FILE *inFile;
    inFile = fopen("testFile","r");
    printf("%s",readLine(inFile));
    printf("%s",readLine(inFile));
    printf("%s",readLine(inFile));
    return 0;
}

Si le contenu de testFile est:-

abc
def
ghi

Les trois instructions printf devraient montrer "abc" trois fois Mais la sortie est :-

abc
def
ghi

Je sais que je me trompe quelque part dans le concept. Aidez-moi, s'il vous plaît.

6voto

Alex B Points 34304

Utilisation de realloc() est incorrect.

realloc(line,i+1); // wrong

// OK
void *new_line = realloc(line,i+1);
if (!new_line)
{
    free(line);
    return NULL;
}
line = new_line;

Porque line est passée par valeur, elle n'est pas modifiée. La mémoire réaffectée est dans la valeur de retour. Par conséquent, line reste la même encore et encore, et vous voyez la même ligne encore et encore. Editar: Je viens de réaliser que même si c'est un bug, ce n'est pas ce qui causerait la répétition des lignes. Les autres points sont toujours valables.

Ce qui est pire :

  1. Vous avez une fuite de mémoire en perdant le pointeur nouvellement réalloué à chaque fois.
  2. Vous accédez potentiellement à de la mémoire libérée, parce que les vieilles line peut devenir invalide après la réallocation, si elle a été réallouée dans une partie différente du tas.
  3. Vous réallouez la mémoire à chaque caractère, ce qui est une opération potentiellement coûteuse.

4voto

aib Points 18608

fgetc() avance le pointeur de fichier (qui est "l'endroit où se trouve le prochain caractère à lire"). C'est ainsi que vous pouvez l'appeler dans une boucle et lire une ligne entière de caractères.

Après avoir dépassé le caractère de nouvelle ligne, il passe naturellement au caractère suivant, qui est le début de la ligne suivante.

Vous pouvez modifier le pointeur de fichier avec la commande fseek() fonction. Par exemple, l'appel fseek(inFile, 0, SEEK_SET) la réinitialiserait au début du fichier, ce qui entraînerait le prochain fgetc() pour recommencer à partir du premier caractère du fichier.

4voto

R Samuel Klatchko Points 44549

Mais je passe le pointeur de fichier par valeur. Donc je devrais obtenir la sortie "abc" encore et encore.

Ah, je comprends votre confusion.

Un dossier pointeur ne pointe que vers la structure réelle du fichier. Des données telles que le décalage actuel ne font pas partie du pointeur mais de la structure interne.

Une autre façon de voir les choses est que l'objet réel représentant le fichier est FILE. Pour obtenir la sémantique pass-by-reference, vous passez un pointeur sur l'objet. Puisque vous passez par référence, chaque ligne reprend là où la précédente s'est arrêtée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X