Baca baris dari file di C dan ekstrak jumlah input
Saya memiliki file input.dat . Di file ini, ada 3 baris:
1 2 3
5 7 10 12
8 9 14 13 15 17
Saya akan membaca salah satu dari tiga baris menggunakan C, dan mengembalikan jumlah elemen. Misalnya, saya ingin membaca baris 5 7 10 12
ke -2 ke dalam memori, dan juga mengembalikan jumlah nilai di baris ke-2, yaitu 4
. Kode saya ada di bawah ...
#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);
}
Ketika saya menjalankan kode ini, tidak pernah berhenti seperti loop mati. Apa masalah yang terjadi di sini?
Jawaban
loop while (sscanf(line, "%d ", &number))
terus mem-parsing angka pertama dalam baris.
Anda harus menggunakan strtol
sebagai gantinya:
#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;
}
Anda berpikir di sepanjang jalan yang benar dengan penggunaan Anda sscanf()
, satu-satunya bagian dari teka-teki yang Anda lewatkan adalah bagaimana menerapkan offset line
sehingga Anda membaca nilai berikutnya di baris dengan panggilan berikutnya ke sscanf()
. Anda melakukannya dengan melacak jumlah karakter yang digunakan pada setiap panggilan untuk sscanf()
menggunakan "%n"
konversi (ini tidak menambah jumlah konversi Anda yang dikembalikan oleh sscanf()
) Misalnya membaca baris dari open file-stream fp
, Anda dapat melakukan:
#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 */
}
( Catatan: strtol()
memberikan pelaporan kesalahan yang lebih baik daripada sscanf()
pada konversi yang gagal)
Jika Anda menggabungkannya dengan contoh yang membaca dari nama file yang diberikan sebagai argumen pertama untuk program (atau membaca dari stdin
secara default jika tidak ada argumen yang diberikan), Anda dapat melakukan:
#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);
}
Contoh Penggunaan / Output
Dengan data yang Anda tampilkan di nama file, dat/nvals.txt
Anda akan mendapatkan:
$ ./bin/fgetsnvals dat/nvals.txt
1 2 3 - 3 values
5 7 10 12 - 4 values
8 9 14 13 15 17 - 6 values
Periksa semuanya dan beri tahu saya jika Anda memiliki pertanyaan lebih lanjut.
Versi jawaban chqrlie yang sedikit lebih bersih . Dimulai dengan string karena itulah pertanyaan sebenarnya tentang setelahnya fgets()
.
sscanf()
tidak akan melewati string, itu selalu membaca dari awal.
strtol()
mencari a long int
di awal string, mengabaikan ruang kosong awal. Memberikan kembali alamat tempat berhenti memindai.
Manual strtol()
mengatakan errno yang harus diperiksa untuk setiap kesalahan konversi.
#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;
}