C의 파일에서 라인을 읽고 입력 수를 추출하십시오.
input.dat 파일이 있습니다. 이 파일에는 3 줄이 있습니다.
1 2 3
5 7 10 12
8 9 14 13 15 17
C를 사용하여 세 줄 중 하나를 읽고 요소 수를 반환합니다. 예를 들어, 두 번째 줄 5 7 10 12
을 메모리 로 읽고 두 번째 줄 의 값 수인 4
. 내 코드는 다음과 같습니다.
#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);
}
이 코드를 실행하면 데드 루프처럼 멈추지 않습니다. 여기서 문제는 무엇입니까?
답변
루프 while (sscanf(line, "%d ", &number))
는 줄의 첫 번째 숫자를 계속 구문 분석합니다.
strtol
대신 다음을 사용해야 합니다.
#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;
}
을 (를) 사용하여 올바른 경로를 따라 생각하고 sscanf()
있었습니다. 누락 된 유일한 퍼즐 조각은 오프셋을 적용 line
하여 다음 호출에서 줄의 다음 값을 읽는 방법 sscanf()
입니다. 전환 을 sscanf()
사용하기위한 각 호출에서 소비 된 문자 수를 추적 하여 "%n"
이를 수행 할 수 있습니다 (에서 반환 한 전환 수에 추가되지 않음 sscanf()
). 예를 들어 열린 파일 스트림에서 행을 읽으면 다음과 같이 fp
할 수 있습니다.
#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 */
}
( 참고 : 실패한 변환 strtol()
보다 더 나은 오류보고를 제공합니다 .sscanf()
)
프로그램의 첫 번째 인수로 제공된 파일 이름에서 읽는 (또는 stdin
인수가 지정되지 않은 경우 기본적으로 읽는) 예제와 함께 넣으면 다음을 수행 할 수 있습니다.
#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);
}
사용 / 출력 예시
파일 이름에 표시된 데이터를 사용하면 dat/nvals.txt
다음을 얻을 수 있습니다.
$ ./bin/fgetsnvals dat/nvals.txt
1 2 3 - 3 values
5 7 10 12 - 4 values
8 9 14 13 15 17 - 6 values
자세히 살펴보고 추가 질문이 있으면 알려주세요.
chqrlie 의 대답 의 조금 더 깨끗한 버전 . 그 이후에 질문이 실제로 무엇인지 문자열로 시작되었습니다 fgets()
.
sscanf()
문자열을 단계별로 실행하지 않고 항상 처음부터 읽습니다.
strtol()
long int
초기 공백을 무시하고 문자열 시작 부분에서 a 를 찾습니다 . 스캔을 중지 한 주소를 반환합니다.
의 매뉴얼에는 strtol()
변환 오류가 있는지 errno를 확인해야한다고 나와 있습니다.
#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;
}