C'deki dosyadan bir satır okuyun ve girdi sayısını çıkarın
Bir dosya var input.dat . Bu dosyada 3 satır vardır:
1 2 3
5 7 10 12
8 9 14 13 15 17
C'yi kullanarak üç satırdan birini okuyacağım ve elemanların sayısını döndüreceğim. Örneğin, 2. satırı 5 7 10 12hafızaya okumak ve 2. satırdaki değerlerin sayısını da döndürmek istiyorum 4. Kodum aşağıda ...
#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);
}
Bu kodu çalıştırdığımda, asla bir ölü döngü gibi durmuyor. Buradaki sorun nedir?
Yanıtlar
döngü while (sscanf(line, "%d ", &number)), satırdaki ilk sayıyı çözümlemeye devam eder.
Bunun strtolyerine şunu kullanmalısınız :
#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;
}
Doğru yolda düşünüyordunuz sscanf(), bulmacanın eksik olan tek parçası, bir linesonraki aramanızla satırdaki bir sonraki değeri okuyabilmeniz için bir ofsetin nasıl uygulanacağıdır sscanf(). Bunu sscanf(), "%n"dönüşümü kullanmak için her çağrıda tüketilen karakterlerin sayısını takip ederek yaparsınız (bu, tarafından döndürülen dönüşüm sayınıza eklenmez sscanf()) Örneğin, açık dosya akışından satır okumak fp, şunları yapabilirsiniz:
#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 */
}
( Not: başarısız bir dönüştürmeden strtol()daha iyi hata raporlama sağlar sscanf())
Bunu, programa ilk argüman olarak sağlanan dosya adından okuyan (veya stdinherhangi bir argüman verilmemişse varsayılan olarak okuyan) bir örnekle bir araya getirirseniz, şunları yapabilirsiniz:
#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);
}
Örnek Kullanım / Çıktı
Dosya adında gösterdiğiniz verilerle şunları dat/nvals.txtelde edersiniz:
$ ./bin/fgetsnvals dat/nvals.txt
1 2 3 - 3 values
5 7 10 12 - 4 values
8 9 14 13 15 17 - 6 values
Her şeyi gözden geçirin ve başka sorunuz olursa bana bildirin.
Chqrlie'nin cevabının biraz daha temiz bir versiyonu . Bir dizeyle başladı, çünkü soru aslında bundan sonra fgets().
sscanf() dizede adım atmaz, her zaman baştan okur.
strtol()long intdizenin başında, başlangıçtaki beyaz boşluğu yok sayarak bir a arar . Taramayı durdurduğu yerin adresini geri verir.
El kitabı, strtol()errno'nun herhangi bir dönüştürme hatası için kontrol edilmesi gerektiğini söylüyor.
#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;
}