我的目标是从test.txt
中读取内容,然后输出其内容。但是,问题是,我陷入了sscanf循环中。因此,它会不断读取Australia
test.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");
}
}
答案 0 :(得分:1)
您进入无限循环,因为您尝试从解析的city
的同一位置(country
的开头)解析每个buf
。要使用sscanf
逐步解析buf
中的空格分隔的字符串,您需要另外使用"%n"
转换说明符,以获取{消耗的字符数(下面的nchar
)每次读取{1}}。然后,您可以将其添加到偏移量(下面的sscanf
)中,以在解析off
之后依次解析city
中的每个buf
。
该方法很简单,将country
与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
来保留原始字符串)
仔细检查一下,如果还有其他问题,请告诉我。
答案 1 :(得分:0)
您需要有一个整数偏移量,将其命名为off
,然后将buf + off
传递为sscanf
的第一个参数,而不只是buf
:
printf("Cities:");
int off = 0;
while (sscanf(buf + off, "%s", city) == 1) {
printf(" %s", city);
off += strlen(city);
}
为for
:
int off;
for (off = 0; sscanf(buf + off, "%s", city) == 1; off += strlen(city))
printf(" %s", city);
答案 2 :(得分:0)
您的代码有缓冲区溢出,这很危险。
从长行中读取时,line
可能不会以\n
结尾。如果该行不包含任何空格,则city
缓冲区将无法容纳完整行。