2017-09-16 11 views
-1

J'ai écrit ce code qui lit chaque caractère de mon texte et le place dans mon tableau de caractères. Mon problème est que la fin du fichier n'est pas détectée et donc le fscanf() retourne après la fin du texte chaque fois que le dernier caractère jusqu'à ce que mon tableau est rempli. Comment puis-je empêcher cela? Je suis la programmation en C.Détection EOF d'un fichier txt en C

Mon code:

int main() { 
    char array[50][50]; 
    char buff; 
    FILE *cola = fopen("C:/Users/danie/Desktop/cola.txt", "r"); 

    for (int i = 0; i < 50; i++) { 
     for (int k = 0; k < 50; k++) { 
      fscanf(cola, "%c", &buff); 
      array[i][k] = buff; 
     } 
    } 

    fclose(cola); 

    for (int i = 0; i < 50; i++) { 
     for (int k = 0; k < 50; k++) { 
      printf("%c", array[i][k]); 
     } 
    } 
    return 0; 
} 

Merci pour votre aide.

Here is a Screenshot of my Code

+3

S'il vous plaît ne publiez pas les images de votre code. Au lieu de cela, créez un bloc de code qui inclut le code réel. –

+4

Vérifiez la valeur de retour de 'fscanf'. – BLUEPIXY

+0

J'ai édité maintenant mon message. –

Répondre

1

Remplacer:

for (int i = 0; i < 50; i++) { 
    for (int k = 0; k < 50; k++) { 
     fscanf(cola, "%c", &buff); 
     array[i][k] = buff; 
    } 
} 

avec:

for (int i = 0; i < 50; i++) { 
    for (int k = 0; k < 50; k++) { 
     int c = getc(cola); 
     if (c == EOF) 
      break; 
     array[i][k] = c; 
    } 
} 

Depuis buff est alors utilisé, ne définissent pas. Notez que le type de retour de getc() est un int, pas seulement un char. Vérifiez toujours la fonction d'E/S pour le succès/l'échec. Dans votre code d'origine, vous ne vérifiez même pas si l'opération d'E/S réussit, ce qui rend la détection d'EOF impossible.

Notez que ce code fait un certain nombre d'hypothèses qui peuvent ou ne peuvent pas être justifiables. Par exemple, vous supposez que chaque ligne du fichier comprend 49 caractères plus un saut de ligne; vous supposez également que vous n'aurez jamais besoin d'imprimer les informations sous la forme d'une 'chaîne' (votre code existant ne le fait pas, il imprime les caractères par caractère, donc c'est 'sûr').

Vous pouvez décrire l'entrée comme:

  • lire jusqu'à 50 lignes avec un maximum de 49 caractères plus un saut de ligne dans chaque ligne, stocker le résultat dans la array variable chaque ligne étant un caractère nul chaîne terminée.

Ceci résiste mieux aux problèmes courants (lignes courtes, longues lignes, lignes insuffisantes). Le code pour ce pourrait être:

enum { LINE_LEN = 50, NUM_LINES = 50 }; 
char array[NUM_LINES][LINE_LEN]; 
int i; 
for (i = 0; i < LINE_LEN; i++) 
{ 
    int c; 
    int k; 
    for (k = 0; k < LINE_LEN; k++) 
    { 
     c = getc(cola); 
     if (c == EOF || c == '\n') 
      break; 
     if (k == LINE_LEN - 1) 
     { 
      /* Too long - gobble excess */ 
      while ((c = getc(cola)) != EOF && c != '\n') 
       ; 
      break; 
     } 
     array[i][k] = c; 
    } 
    array[i][k] = '\0'; 
    if (c == EOF) 
     break; 
} 
int num_lines = i; // You have num_lines lines of data in your array 

J'ai trouvé une version de l'image de l'art ASCII Coca Cola ™ à https://www.ascii-code.com/ascii-art/logos/coca-cola.php qui ressemble à ce que vous avez dans vos images, mais il y a beaucoup d'autres sources et variantes:

  __        ___ __  .ama  , 
     ,d888a       ,d88888888888ba. ,88"I) d 
    a88']8i       a88".8"8) `"8888:88 " _a8' 
    .d8P' PP      .d8P'.8 d)  "8:88:baad8P' 
    ,d8P' ,ama, .aa, .ama.g ,mmm d8P' 8 .8'  88):888P' 
,d88' d8[ "8..a8"88 ,8I"88[ I88' d88 ]IaI"  d8[   
a88' dP "bm8mP8'(8'.8I 8[  d88' `"   .88   
,88I ]8' .d'.8  88' ,8' I[ ,88P ,ama ,ama, d8[ .ama.g 
[88' I8, .d' ]8, ,88B ,d8 aI (88',88"8) d8[ "8. 88 ,8I"88[ 
]88 `888P' `8888" "88P"8m" I88 88[ 8[ dP "bm8m88[.8I 8[ 
]88,   _,,aaaaaa,_  I88 8" 8 ]P' .d' 88 88' ,8' I[ 
`888a,. ,aadd88888888888bma. )88, ,]I I8, .d')88a8B ,d8 aI 
    "888888PP"'  `8""""""8 "888PP' `888P' `88P"88P"8m" 

La plus longue ligne de ce fichier est la première à 67 caractères plus le retour à la ligne; le plus court est de 61 caractères plus newline. Le fichier n'a que 13 lignes et 845 caractères (fins de ligne LF) au total. Ainsi, votre programme est mal équipé pour traiter ce fichier de données particulier. Il cherche 2 500 caractères et ne les obtiendra pas.

Mon code de test complet a été configuré pour lire à partir de l'entrée standard, plutôt que d'un nom de fichier fixe.

#include <stdio.h> 

int main(void) 
{ 
    FILE *cola = stdin; 

    enum { LINE_LEN = 80, NUM_LINES = 50 }; 
    char array[NUM_LINES][LINE_LEN]; 
    int i;  // Need value of i after loop 
    for (i = 0; i < NUM_LINES; i++) 
    { 
     int c; // Need value of c after loop 
     int k; 
     for (k = 0; k < LINE_LEN; k++) 
     { 
      c = getc(cola); 
      if (c == EOF || c == '\n') 
       break; 
      if (k == LINE_LEN - 1) 
      { 
       /* Too long - gobble excess */ 
       while ((c = getc(cola)) != EOF && c != '\n') 
        ; 
       break; 
      } 
      array[i][k] = c; 
     } 
     array[i][k] = '\0'; 
     if (c == EOF) 
      break; 
    } 
    int num_lines = i; // You have num_lines lines of data in your array 

    for (i = 0; i < num_lines; i++) 
     puts(array[i]); 

    return 0; 
} 

Je l'ai testé sur le fichier de données représenté, avec une ligne vide à la fin, et avec quelques lignes contenant plus de 79 caractères après la ligne blanche. Il a correctement géré tous ces cas spéciaux. Notez que la gestion des entrées utilisateur est difficile; La gestion de l'entrée perverse de l'utilisateur est plus difficile. Le code est moins compact. Vous pouvez modifier les règles, puis modifier le code pour correspondre. Je ne suis pas sûr que ce soit la manière la plus minime de coder ceci; ça marche, cependant.Il pourrait être préférable d'avoir une fonction pour gérer la boucle d'entrée interne; la boucle externe pourrait tester la valeur de retour de cette fonction. Cela permettrait de réduire la manipulation de cas spéciaux.

#include <assert.h> 
#include <limits.h> 
#include <stdio.h> 

static int read_line(FILE *fp, size_t buflen, char *buffer) 
{ 
    assert(buflen < INT_MAX); 
    int c;  // Need value of c after loop 
    size_t k; // Need value of k after loop 
    for (k = 0; k < buflen; k++) 
    { 
     if ((c = getc(fp)) == EOF || c == '\n') 
      break; 
     if (k == buflen - 1) 
     { 
      /* Too long - gobble excess */ 
      while ((c = getc(fp)) != EOF && c != '\n') 
       ; 
      break; 
     } 
     buffer[k] = c; 
    } 
    buffer[k] = '\0'; 
    return (k == 0 && c == EOF) ? EOF : (int)k; 
} 

int main(void) 
{ 
    enum { LINE_LEN = 80, NUM_LINES = 50 }; 
    char array[NUM_LINES][LINE_LEN]; 
    int i; 
    for (i = 0; i < NUM_LINES; i++) 
    { 
     if (read_line(stdin, LINE_LEN, array[i]) == EOF) 
      break; 
    } 
    int num_lines = i; 

    for (i = 0; i < num_lines; i++) 
     puts(array[i]); 

    return 0; 
} 

Ceci produit la même sortie à partir de la même entrée que la version précédente.

+0

Ceci modifier seul ne résout pas le problème, la boucle d'impression accédera à une partie non initialisée du tableau, invoquant un comportement indéfini. – chqrlie

+0

@chqrlie - Vous avez probablement raison. J'ai seulement adressé la question de titre (sur ne pas détecter EOF); Je n'ai regardé aucun des autres codes. Je n'ai même rien compilé. Je n'ai pas non plus de protection contre les débordements, etc. –

+0

Effort impressionnant et bon aperçu, tout le monde a raté le problème de longueur de ligne. Je suppose que le 'assert (buflen chqrlie

-1
int main() { 
//char array[50][50]; 
char buff; 
int t; 
FILE *cola = fopen("C:/Users/danie/Desktop/cola.txt", "r"); 

if (cola == NULL) 
{ 
    printf("Cannot open file \n"); 
    exit(0); 
} 
while (1) { 
    t = fgetc(cola); 
    if (t == EOF) 
     break; 
    buff = t; 
    printf("%c", buff); 
} 


fclose(cola); 

return 0; 
} 
+1

Vous devriez tester 'EOF' ** avant ** d'imprimer le caractère avec' printf ("% c", buff); '. De plus, comme vous utilisez 'fgetc (cola)' pour lire le flux, vous devez ** définir 'buff' avec le type' int' pour que 'EOF' soit correctement détecté, et vous pouvez également utiliser' putchar (buff) 'pour la sortie. – chqrlie

+0

@chqrlie 'fgetc()' renvoie un int mais lorsque nous stockons la valeur de retour dans le type de données char, il stocke automatiquement le caractère équivalent de retour ASCII. c'est implicitement typecasted. – Aashish

+1

Le problème est que si vous sauvegardez la valeur de 'getc()' et ses parents dans un 'char' avant de le tester, vous jetez l'indication EOF. Si le caractère 'char' est un type signé, vous identifierez un caractère valide comme EOF; S'il s'agit d'un type non signé, vous ne détecterez jamais EOF. Les deux sont mauvais. –

2

fscanf() renvoie le nombre de conversions réussies. Vous devez tester la valeur de retour et de traiter également des sauts de ligne spécifiquement:

#include <stdio.h> 

int main(void) { 
    char array[50][50]; 
    char buff; 
    FILE *cola = fopen("C:/Users/danie/Desktop/cola.txt", "r"); 

    if (cola == NULL) { 
     return 1; 
    } 
    for (int i = 0; i < 50; i++) { 
     for (int k = 0; k < 50; k++) { 
      if (fscanf(cola, "%c", &buff) != 1 || buff == '\n') { 
       array[i][k] = '\0'; 
       break; 
      } 
      array[i][k] = buff; 
     } 
    } 
    fclose(cola); 

    for (int i = 0; i < 50; i++) { 
     for (int k = 0; k < 50 && array[i][k] != '\0'; k++) { 
      printf("%c", array[i][k]); 
     } 
     printf("\n"); 
    } 
    return 0; 
} 

Le code peut être simplifiée si vous utilisez getc() au lieu de fscanf() pour lire des octets du fichier:

#include <stdio.h> 

int main(void) { 
    char array[50][51]; 
    int c, i, k, n; 
    FILE *cola = fopen("C:/Users/danie/Desktop/cola.txt", "r"); 

    if (cola == NULL) { 
     return 1; 
    } 
    for (n = 0; n < 50; n++) { 
     for (k = 0; k < 50; k++) { 
      if ((c = getc(cola)) == EOF || c == '\n') { 
       break; 
      } 
      array[n][k] = c; 
     } 
     array[n][k] = '\0'; 
     if (c == EOF && k == 0) 
      break; 
    } 
    fclose(cola); 

    for (i = 0; i < n; i++) { 
     puts(array[i]); 
    } 
    return 0; 
} 
+0

Vous avez raison - je ne l'ai pas vu au début. – chux