2017-07-17 2 views
0

J'essaie de lire des doubles à partir d'un fichier en C mais cela s'avère être un cauchemar. Quand je veux lire des ints ou des caractères, je ne semble pas rencontrer de problème, cependant les doubles semblent difficiles à travailler. Donc, disons que j'ai un fichier avec deux colonnes et quatre lignes de nombres doubles et je veux que deux vecteurs conservent toutes les données dans chaque colonne. Mon code serait:La lecture des doubles forme un fichier en C

int main(void){ 

    double v1[4],v2[4]; 
    FILE *f; 
    int i; 

    f=fopen("hola.rtf","r"); 
    if(f==NULL){ 
      printf("Error fitxer!\n"); 
      exit(1); 
    } 
    for(i=0;i<4;i++){ 
      fscanf(f,"%le",&v1[i]); 
      fscanf(f,"%le",&v2[i]); 
      printf("%le %le\n",v1[i],v2[i]); 
    } 
    fclose(f); 
    return 0; 

Mais toutes les valeurs affichées sont 0 ... Des idées/conseils?

Merci :)

+3

Est-ce un fichier RTF ?? (Format de texte enrichi). Alors cela ne fonctionnera pas car vous devez analyser le RTF. Vider/afficher le fichier en binaire pour déterminer son format. –

+2

S'il vous plaît montrer les 3-4 premières lignes de 'hola.rtf'. –

+1

Et vérifiez la valeur de retour de 'scanf' pour déterminer si elle a réussi à lire le double. –

Répondre

0

vous ne cochez pas la valeur de retour de la fscanf(), de sorte que vous ne savez pas si elle convertie (et lire) les données ou non.

En outre, le prescripteur pour double pour printf() est %e (ou %f ou %g, selon le format que vous voulez); %le n'est pas un spécificateur valide en C, donc si votre programme imprime quelque chose, c'est parce que votre compilateur ou votre bibliothèque C accepte %le. (Quel que soit le format qu'il comprend comme, est probablement pas double, cependant.)


Voici comment vous devriez lire les doubles:

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

#define COUNT 4 

int main(void) 
{ 
    const char *filename = "hola.rtf"; 
    FILE *input; 
    double v1[COUNT], v2[COUNT]; 
    int i; 

    input = fopen(filename, "r"); 
    if (!input) { 
     fprintf(stderr, "Cannot open %s: %s.\n", filename, strerror(errno)); 
     return EXIT_FAILURE; 
    } 

    for (i = 0; i < COUNT; i++) { 
     if (fscanf(input, " %le %le", &(v1[i]), &(v2[i])) != 2) { 
      fprintf(stderr, "Invalid data in %s.\n", filename); 
      fclose(input); 
      return EXIT_FAILURE; 
     } 

     printf("Read %e and %e from %s.\n", v1[i], v2[i], filename); 
    } 

    if (ferror(input)) { 
     fclose(input); 
     fprintf(stderr, "Error reading %s.\n", filename); 
     return EXIT_FAILURE; 
    } 
    if (fclose(input)) { 
     fprintf(stderr, "Error closing %s.\n", filename); 
     return EXIT_FAILURE; 
    } 

    printf("All %d pairs of doubles read successfully.\n"); 

    return EXIT_SUCCESS; 
} 

De nombreux programmeurs croient qu'ils peuvent ajouter la vérification des erreurs plus tard de retour Ce n'est pas pratique. ce qu'ils se retrouvent normalement avec, c'est du code sans ou très peu de contrôles d'erreurs en place. Cependant, en tant qu'utilisateur, ne voudriez-vous pas savoir quand le programme fonctionne mal et produire des déchets plutôt que des résultats sensés? Je le fais définitivement, et tous ceux que je connais utilisent le code pour faire un travail réel. C'est une habitude importante à prendre, car si vous apprenez à ne pas le faire, il est très difficile d'apprendre à le faire par la suite.

Le niveau de contrôle d'erreur peut bien sûr être discuté. Je suis sûr que beaucoup de membres ici considèrent le ferror() vérifier et vérifier le résultat de fclose() comme "inutile". Il est vrai qu'ils n'échouent pas en fonctionnement normal normal. Il est possible pour un programmeur de ne jamais voir l'un ou l'autre échouer, jamais. Cependant, quand ils échouent - par exemple, quelqu'un finit par exécuter votre code sur un système de fichiers FUSE qui peut signaler une erreur à la fermeture -, les contrôles peuvent faire la différence entre des tonnes d'ordures et un avertissement précoce que quelque chose ne va pas. Si vous êtes d'accord avec mon sentiment (à propos des contrôles d'erreurs semi-paranoïaques étant bénignes, et parfois très utiles aux utilisateurs), considérez la variante suivante de votre code, qui lit toutes les paires doubles d'un fichier spécifié sur la commande ligne à un tableau alloué dynamiquement:

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

typedef struct { 
    double x; 
    double y; 
} vec2d; 

/* Read all 2D vectors from stream 'input', 
    into a dynamically allocated array. 
    (Similar to POSIX.1 getline(), but with double vectors.) 
    If *dataptr is not NULL, and *sizeptr > 0, 
    it will initially be used (but reallocated if needed). 
    Returns the number of vectors read, 
    or 0 with errno set if an error occurs. 
*/ 
size_t vec2d_readall(FILE *input, vec2d **dataptr, size_t *sizeptr) 
{ 
    vec2d *data; 
    size_t size; 
    size_t used = 0; 

    if (!input || !dataptr || !sizeptr) { 
     /* At least one of the parameters is NULL. */ 
     errno = EINVAL; 
     return 0; 
    } 

    if (ferror(input)) { 
     /* input stream is already in error state. */ 
     errno = EIO; 
     return 0; 
    } 

    if (!*dataptr || !*sizeptr) { 
     /* *dataptr is NULL, or *sizeptr == 0, 
      so we initialize them to empty. */ 
     *dataptr = NULL; 
     *sizeptr = 0; 
    } 
    data = *dataptr; 
    size = *sizeptr; 

    while (1) { 

     if (used >= size) { 
      /* We need to grow the data array. */ 

      /* Simple allocation policy: 
       allocate in sets of roughly 1024 vectors. */ 
      size = (used | 1023) + 1021; 
      data = realloc(data, size * sizeof *data); 
      if (!data) { 
       /* Realloc failed! */ 
       errno = ENOMEM; 
       return 0; 
      } 

      *dataptr = data; 
      *sizeptr = size; 
     } 

     if (fscanf(input, " %lf %lf", &(data[used].x), &(data[used].y)) != 2) 
      break; 

     /* One more vector read successfully. */ 
     used++; 
    } 

    /* If there was an actual I/O error, or 
     the file contains unread data, set errno 
     to EIO, otherwise set it to 0. */ 
    if (ferror(input) || !feof(input)) 
     errno = EIO; 
    else 
     errno = 0; 

    return used; 
} 

comme la fonction vec2d_readall() définit toujours errno0 si aucune erreur), en utilisant la fonction ci-dessus pour lire toutes les doubles paires depuis l'entrée standard en tant que vecteurs 2D est très simple:

int main(void) 
{ 
    vec2d  *vectors = NULL; 
    size_t num_vectors = 0; 
    size_t max_vectors = 0; 

    size_t i; 

    num_vectors = vec2d_readall(stdin, &vectors, &max_vectors); 
    if (errno) { 
     fprintf(stderr, "Standard input: %s.\n", strerror(errno)); 
     return EXIT_FAILURE; 
    } 

    printf("Read %zu vectors from standard input,\n", num_vectors); 
    printf("with memory allocated for up to %zu vectors.\n", max_vectors); 

    for (i = 0u; i < num_vectors; i++) 
     printf("%f %f\n", vectors[i].x, vectors[i].y); 

    return EXIT_SUCCESS; 
} 

Un peu d'effort supplémentaire passé en écriture vec2d_readall() a beaucoup simplifié notre main().De plus, si jamais nous trouvons que nous avons besoin d'une fonction similaire pour lire les vecteurs 3D, nous avons seulement besoin d'ajouter un typedef struct { double x; double y; double z } vec3d;, et de faire de très petits changements au vec2d_readall() pour le transformer en vec3d_readall(). Plus important encore, nous pouvons compter sur vec2d_readall() à échouer s'il y a n'importe quel type de problème avec les données. Nous pourrions ajouter des rapports d'erreurs, au lieu de simplement signaler les erreurs.

Si vous vous posez des questions sur le getline() mentionné dans un commentaire, il s'agit d'une fonction standard POSIX.1-2008, qui permet aux programmeurs C des systèmes POSIXy de lire des lignes d'entrée de longueur illimitée. Il est similaire à fgets(), mais avec gestion dynamique de la mémoire.

+0

C'est génial! Merci beaucoup! – Ubstudent