2010-02-03 11 views
6

je besoin de lire un fichier d'entrée comme:lecture nombre inconnu de nombres entiers de stdin (C)

1 
19 20 41 23 
2 
41 52 43 
3 
90 91 941 
4 
512 
5 

6 
51 61 

Chaque ligne est un nombre entier impair. Chaque ligne paire est un nombre inconnu d'entiers.

Il est très facile en C++

while(cin >> k){ 
............ 
} 

Je ne suis pas habitué à C, donc je ne pourrais pas le faire en C. Toutes les façons de le faire?

+1

Avez-vous prêter attention aux lignes, ou est-ce juste une série d'entiers qui viennent? Dans votre exemple, il semble que les lignes impaires sont des numéros de séquence et les lignes paires représentent quelque chose d'autre. –

+0

david Je dois faire attention aux lignes. C'est pourquoi je ne pouvais pas le faire. Je dois arrêter d'obtenir de nouvelles valeurs à la fin de chaque ligne paire. Parce que j'ai une structure avec les attributs id et list. chaque ligne impaire est un identifiant et chaque ligne paire est une liste. Je veux remplir une structure avec 2 lignes de données et passer à une autre structure et le remplir avec 2 autres lignes de données etc ... – huhuhuuu

+0

Lire dans une ligne entière à la fois, puis juste l'analyser comme une chaîne –

Répondre

9

La façon dont je le ferais est de le casser en deux opérations: lire une ligne, puis lire les entiers dans cette ligne. Voici une implémentation paresseuse en utilisant la bibliothèque standard C:

char line[1024], *p, *e; 
long v; 
while (fgets(line, sizeof(line), stdin)) { 
    p = line; 
    for (p = line; ; p = e) { 
     v = strtol(p, &e, 10); 
     if (p == e) 
      break; 
     // process v here 
    } 
} 
+2

Merci beaucoup. Je vais l'essayer maintenant. Mais que se passe-t-il si je ne peux pas supposer une longueur de ligne maximale fixe? – huhuhuuu

+2

Que faire si le flux d'entrée contient plus de 1024 - 2 caractères et 'fgets()' scinde le flux d'entrée à un littéral numérique? Vous allez vous retrouver avec deux valeurs numériques au lieu d'une. Par exemple, à partir de 12345, vous pouvez obtenir 123 dans la dernière itération de la boucle for et 45 dans la première itération de la boucle for après l'appel suivant de 'fgets()'. Par conséquent, je préfère 'scanf()' et 'fscanf()' pour cette tâche, comme indiqué par Sean. –

+1

@RobinKlose: La solution 'scanf()' affichée par Sean ne résout pas le problème, car elle ne distingue pas les sauts de ligne des autres espaces. –

11

Exécution de votre fichier d'entrée par:

#include <stdio.h> 

int main() { 
     int k; 
     while (scanf("%d", &k) == 1) { 
       printf("read number: %d\n", k); 
     } 
     return 0; 
} 

Résultats dans:

 
read number: 1 
read number: 19 
read number: 20 
read number: 41 
read number: 23 
read number: 2 
read number: 41 
read number: 52 
read number: 43 
read number: 3 
read number: 90 
read number: 91 
read number: 941 
read number: 4 
read number: 512 
read number: 5 
read number: 6 
read number: 51 
read number: 61 

Ceci est l'analogue C du code que vous faites référence dans votre question initiale.

+0

Je peux lire la ligne correctement mais la boucle scanf imprime infiniment le premier nombre pour moi. – tarabyte

0

un coup d'oeil à getc (3) ou scanf (3)

1

je ferais une des:

  • fgetc() pour lire les caractères individuels et les analyser vous-même (accumuler chiffres jusqu'à ce que vous frappez des espaces et des vous avez un nombre entier à convertir avec atoi(), si l'espace est un saut de ligne, alors il termine une liste d'entiers)

  • fgets() pour lire une ligne à la fois, puis analyser la chaîne (encore une fois, chercher des espaces séparant les valeurs) qu'il renvoie.

3

Je casserais le programme dans différentes tâches.

La première étape consiste à être capable de lire une paire de lignes, la première ligne qui vous indique le nombre de nombres à lire, puis la seconde ligne pour lire les nombres réels. Pour cela, une fonction appelée quelque chose comme read_set pourrait être utile. Il devrait être capable de renvoyer les numéros lus, et signaler la fin du fichier ainsi que les erreurs. Pour cela, nous pouvons définir une structure de données telles que:

struct numbers { 
    long *data; /* or choose a type depending upon your needs */ 
    size_t len; 
}; 

et nous pouvons déclarer notre fonction avec le prototype:

int read_set(FILE *fp, struct numbers *num); 

La fonction allouer de la mémoire pour num->data et mettre num->len à la valeur correcte. Il renvoie 0 pour le succès, et un ensemble de conditions d'erreur sinon. Nous pourrions avoir envie et utiliser un enum pour les statuts de retour plus tard. Pour l'instant, disons que 0 = succès, 1 = fin du fichier, et tout le reste est une erreur.

L'appelant appelle alors read_set() dans une boucle:

struct numbers numbers; 
int status; 
while ((status = read_set(fp, &numbers)) == 0) { 
    /* process numbers->data, and then free it */ 
} 
if (status == 1) { 
    /* hit end of file, everything is OK */ 
} else { 
    /* handle error */ 
} 

Pour la mise en œuvre read_set(): il doit lire deux lignes. Il ya beaucoup de implementations of reading a full line in C, donc vous pouvez utiliser l'un d'entre eux, et lire une ligne d'abord, puis sscanf()/strtoul() pour un nombre (vérifier sa valeur de retour!). Une fois que vous avez le nombre de numéros, n, vous pouvez lire la ligne suivante dans la mémoire, et à faire:

num->data = malloc(n * sizeof *num->data); 
num->len = n; 

Vous pouvez ensuite appeler à plusieurs reprises sscanf() ou strtol() pour enregistrer les numéros dans num->data. Vous devriez mettre en vérifications pour vous assurer que les numéros n sont exactement sur cette ligne.

Notez que vous pouvez également écrire read_set() d'une autre manière: lisez une ligne caractère par caractère et analysez les nombres au fur et à mesure que vous les lisez. Cela a l'avantage de ne parcourir qu'une seule fois les données et de ne pas avoir besoin d'un gros tampon pour stocker toute la ligne d'entrée en mémoire, mais l'inconvénient est de faire des choses de bas niveau et de lire les données caractère par caractère.

0

je suis venu avec une solution comme ceci:

while(scanf("%d%c", &n, &ch)!=EOF) 
{ 
    if(ch=='\n') break; 
    /* rest of your code */ 
} 
+0

/* reste de votre code */devrait être après la boucle. –