Lire une ligne du fichier en C et extraire le nombre d'entrée
J'ai un fichier input.dat . Dans ce fichier, il y a 3 lignes:
1 2 3
5 7 10 12
8 9 14 13 15 17
Je vais lire l'une des trois lignes en utilisant C et renvoyer le nombre d'éléments. Par exemple, je veux lire la 2ème ligne 5 7 10 12
en mémoire et également renvoyer le nombre de valeurs dans la 2ème ligne, qui est 4
. Mon code est ci-dessous ...
#include <stdio.h>
#include <stdlib.h>
#define STRING_SIZE 2000
int main() {
FILE *fp = fopen("in.dat", "r");
char line[STRING_SIZE];
int lcount = 0, nline = 1, sum = 0, number;
if (fp != NULL) {
while (fgets(line, STRING_SIZE, fp) != NULL) {
if (lcount == nline) {
while (sscanf(line, "%d ", &number)) {
sum++;
}
break;
} else {
lcount++;
}
}
fclose(fp);
}
exit(0);
}
Lorsque j'exécute ce code, il ne s'arrête jamais comme une boucle morte. Quel est le problème ici?
Réponses
la boucle while (sscanf(line, "%d ", &number))
continue d'analyser le premier nombre de la ligne.
Vous devriez utiliser à la strtol
place:
#include <stdio.h>
#include <stdlib.h>
#define STRING_SIZE 2000
int main() {
FILE *fp = fopen("in.dat", "r");
char line[STRING_SIZE];
int lcount = 0, nline = 1;
if (fp != NULL) {
while (fgets(line, STRING_SIZE, fp) != NULL) {
if (lcount == nline) {
char *p = line, *q;
int count = 0;
for (;;) {
long val = strtol(p, &q, 0); // parse an integer
if (q == p) {
// end of string or not a number
break;
}
// value was read into val. You can use it for whatever purpose
count++;
p = q;
}
printf("%d\n", count);
break;
} else {
lcount++;
}
}
fclose(fp);
}
return 0;
}
Vous pensiez sur la bonne voie avec votre utilisation de sscanf()
, la seule pièce du puzzle qui vous manquait est de savoir comment appliquer un décalage line
afin que vous lisiez la valeur suivante dans la ligne avec votre prochain appel à sscanf()
. Vous faites cela en gardant une trace du nombre de caractères consommés à chaque appel à l' sscanf()
utilisation de la "%n"
conversion (cela ne s'ajoute pas à votre compte de conversion renvoyé par sscanf()
) Par exemple, en lisant des lignes à partir du flux de fichiers ouvert fp
, vous pouvez faire:
#define MAXC 1024 /* if you need a constant, #define one (or more) */
...
char line[MAXC] = ""; /* buffer to hold each line */
...
while (fgets (line, MAXC, fp)) { /* reach each line in file */
int offset = 0, /* offset in line for next sscanf() read */
nchr = 0, /* number of char consumed by last read */
val, /* integer value read with sscanf() */
nval = 0; /* number of values read in line */
/* conververt each integer at line + offset, saving no. of chars consumed */
while (sscanf (line + offset, "%d%n", &val, &nchr) == 1) {
printf (" %d", val); /* output value read */
offset += nchr; /* update offset with no. chars consumend */
nval++; /* increment value count */
}
printf (" - %d values\n", nval); /* output no. values in line */
}
( Remarque: strtol()
fournit un meilleur rapport d'erreur que sscanf()
sur une conversion ayant échoué)
Si vous l'associez à un exemple qui lit le nom de fichier fourni comme premier argument du programme (ou lit stdin
par défaut si aucun argument n'est donné), vous pouvez faire:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
char line[MAXC] = ""; /* buffer to hold each line */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (line, MAXC, fp)) { /* reach each line in file */
int offset = 0, /* offset in line for next sscanf() read */
nchr = 0, /* number of char consumed by last read */
val, /* integer value read with sscanf() */
nval = 0; /* number of values read in line */
/* conververt each integer at line + offset, saving no. of chars consumed */
while (sscanf (line + offset, "%d%n", &val, &nchr) == 1) {
printf (" %d", val); /* output value read */
offset += nchr; /* update offset with no. chars consumend */
nval++; /* increment value count */
}
printf (" - %d values\n", nval); /* output no. values in line */
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
Exemple d'utilisation / sortie
Avec les données que vous affichez dans le nom de fichier, dat/nvals.txt
vous obtiendrez:
$ ./bin/fgetsnvals dat/nvals.txt
1 2 3 - 3 values
5 7 10 12 - 4 values
8 9 14 13 15 17 - 6 values
Regardez les choses et faites-moi savoir si vous avez d'autres questions.
Une version un peu plus propre de la réponse de chqrlie . Commencé avec une chaîne car c'est ce dont la question est vraiment après fgets()
.
sscanf()
ne parcourra pas la chaîne, il lit toujours depuis le début.
strtol()
recherche un long int
au début de la chaîne, en ignorant l'espace blanc initial. Renvoie l'adresse de l'endroit où il arrête la numérisation.
Le manuel de strtol()
indique que errno doit être vérifié pour toute erreur de conversion.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define STRING_SIZE 2000
int main(void)
{
char line[STRING_SIZE] = "5 7 10 12";
char* start = line;
char* end;
int count = 0;
while(1)
{
/**
* strtol() look for long int in beginning of the string
* Ignores beginning whitespace
*
* start: where to strtol() start looking for long int
* end: where strtol() stops scanning for long int
*/
errno = 0; // As strol() manual says
strtol(start, &end, 0);
if (errno != 0)
{
printf("Error in strtol() conversion.\n");
exit(0);
}
if (start == end) break; // Quit loop
start = end;
count++;
}
printf("count: %d\n", count);
return 0;
}