我的目标是阅读 test.txt
,然后输出其内容。然而,问题是,我陷入了 sscanf 循环。所以它一直显示Australia
一遍又一遍
测试.txt
Australia Sydney Perth Brisbane
USA California Los-Angeles Silicon-Valley Dallas
Canada Toronto
异常输出
Country: Australia
Cities: Sydney Perth Brisbane
---------------
Country: USA
Cities: California Los-Angeles Silicon-Valley Dallas
---------------
Country: Canada
Cities: Toronto
---------------
我的代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX 2000
int main (void) {
FILE *fp = fopen("test.txt" ,"r");
char buf[MAX + 1];
char country[MAX];
char city[MAX];
while (fgets(buf, MAX, fp) != NULL) {
sscanf(buf, "%s", country);
printf("Country: %s\n", country);
printf("Cities:");
while (sscanf(buf, "%s", city) == 1) {
printf(" %s", city);
}
printf("\n---------------\n");
}
}
最佳答案
您进入无限循环,因为您试图从解析 country
的同一位置解析每个 city
- buf
的开头。要使用 sscanf
增量解析 buf
中的空格分隔字符串,您需要另外使用 "%n"
转换说明符来获取sscanf
在每次读取时消耗的字符(下面的 nchar
)。然后,您可以将其添加到偏移量(下面的 off
),以便在解析 country
后从 buf
连续解析每个 city
>.
方法很简单,使用 sscanf
和 "%s%n"
格式字符串将空格分隔的字符串解析为保存字符数的数组由 sscanf
在整型变量中读取/使用。例如:
while (fgets (buf, MAXC, fp)) { /* read each line */
int nchar = 0;
char cc[MAXC] = ""; /* buffer for country/city */
if (sscanf (buf, "%s%n", cc, &nchar)) { /* parse country, get used */
int off = nchar; /* add used char to offset */
printf ("%s\n", cc);
/* read each city getting used chars to add to offset */
while (sscanf (buf + off, "%s%n", cc, &nchar) == 1) {
printf (" %s\n", cc);
off += nchar;
}
}
}
上面的 buf + off
提供了 buf
中开始解析每个城市的位置。另请注意,使用 "%n"
不会增加转换计数(例如 sscanf
返回)。
完整示例:
#include <stdio.h>
#define MAXC 2048 /* good use of constanst, but avoid common MAX */
int main (int argc, char **argv) {
char buf[MAXC] = "";
/* 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 (buf, MAXC, fp)) { /* read each line */
int nchar = 0;
char cc[MAXC] = ""; /* buffer for country/city */
if (sscanf (buf, "%s%n", cc, &nchar)) { /* parse country, get used */
int off = nchar; /* add used char to offset */
printf ("%s\n", cc);
/* read each city getting used chars to add to offset */
while (sscanf (buf + off, "%s%n", cc, &nchar) == 1) {
printf (" %s\n", cc);
off += nchar;
}
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
示例使用/输出
$ ./bin/rdcountrycity <dat/countrycity.txt
Australia
Sydney
Perth
Brisbane
USA
California
Los-Angeles
Silicon-Valley
Dallas
Canada
Toronto
虽然使用 sscanf
解析每行文本中的国家和城市是可以的,但有一个更适合这项工作的工具,例如strtok
用于根据您提供的分隔符将字符串标记为标记。您可以提供“\t\n”
(空格、制表符、换行符)分隔符,以简单地解析每行中的每个空格分隔的单词。
实际上更简单,例如
#include <stdio.h>
#include <string.h>
#define MAXC 2048 /* good use of constanst, but avoid common MAX */
#define DELIM " \t\n" /* you can define character contstants too */
int main (int argc, char **argv) {
char buf[MAXC] = "";
/* 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 (buf, MAXC, fp)) { /* read each line */
char *p = buf;
if ((p = strtok (buf, DELIM))) { /* tokenize country */
printf ("%s\n", p);
while ((p = strtok (NULL, DELIM))) /* tokenize each city */
printf (" %s\n", p);
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
(输出相同)
(注意: strtok
修改原始字符串,因此您需要复制 buf
如果需要保留原件)
仔细检查一下,如果您还有任何其他问题,请告诉我。
关于c - 我的 sscanf 如果陷入无限循环,我该如何修复它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52921121/