scanf 从生成的字符串
Posted
技术标签:
【中文标题】scanf 从生成的字符串【英文标题】:scanf from a generated string 【发布时间】:2022-01-22 08:29:20 【问题描述】:我需要创建一个程序来逐行读取文件并在每一行扫描一些数据。 例如在一行中:
# 2 (x1,y1)(x2,y2)
我需要 x1,y1 和 x2,y2 我的代码是
char firstCharacter;
char line[100];
scanf("%c",&firstCharacter);
while ((fgets(line, sizeof line, stdin) != NULL) && (line[0] != '\n'))
if(firstCharacter == '#')
int nu_deadend;
sscanf(line,"%d",&nu_deadend);
for (int i = 0; i < nu_deadend; i++)
int x,y;
sscanf(line,"(%d,%d)",&x,&y);
printf("x: %d y: %d\n",x,y);
return 0;
但来自输入:
# 2 (2,3)(3,4)
它输出:
x:0 y:0
x:0 y:0
预期输出:
x:2 y:3
x:3 y:4
我做错了什么?
【问题讨论】:
请出示minimal reproducible example。 请说明您的代码忽略的scanf的所有返回值。 与scanf
不同,sscanf
会从它给定的缓冲区开始。因此,您可能需要使用(例如)char *cp = line;
,然后使用并前进cp
以指向下一个令牌。 sscanf
不适合这个。最好使用fgets
、cp
和strtok
并将strtok
的返回值传递给sscanf
此外,您永远不会为第二行重置firstCharacter
(即我假设每一行都以@987654338 开头@)
【参考方案1】:
来自我的***评论...
与scanf
不同,sscanf
会从它给定的缓冲区开始。因此,您可能需要使用(例如)char *cp = line;
,然后使用并前进cp
以指向下一个令牌。
sscanf
不适合这个,因为它返回一个 count 而不是消耗的字节数。
最好使用fgets
、cp
和strtok
并将strtok
的返回值传递给sscanf
另外,您永远不会为第二行重置 firstCharacter
(即我假设每一行都以 #
开头)
这是一个重构版本。有注释:
#include <stdio.h>
#include <string.h>
#ifdef DEBUG
#define dbgprt(_fmt...) printf(_fmt)
#else
#define dbgprt(_fmt...) do while (0)
#endif
int
main(void)
char *tok;
char line[100];
// FORMAT:
// # <count> (x,y)(x,y)...
while (fgets(line, sizeof line, stdin) != NULL)
dbgprt("LINE: %s",line);
// get first token
tok = strtok(line," \n");
if (tok == NULL)
break;
// this must be "#"
if (*tok != '#')
continue;
// get the count
int nu_deadend;
tok = strtok(NULL," \n");
sscanf(tok, "%d", &nu_deadend);
dbgprt("NUM: %d\n",nu_deadend);
// get "(x,y)(x,y)(x,y)"
tok = strtok(NULL," \n");
for (int i = 0; i < nu_deadend; i++)
int x, y;
dbgprt("TOK: '%s'\n",tok);
sscanf(tok, "(%d,%d)", &x, &y);
printf("x: %d y: %d\n", x, y);
// advance past the end of the current (x,y)
tok = strchr(tok,')');
if (tok == NULL)
break;
++tok;
return 0;
这是我使用的测试输入:
# 2 (2,3)(3,4)
# 3 (1,7)(9,2)(8,3)
这是调试输出:
LINE: # 2 (2,3)(3,4)
NUM: 2
TOK: '(2,3)(3,4)'
x: 2 y: 3
TOK: '(3,4)'
x: 3 y: 4
LINE: # 3 (1,7)(9,2)(8,3)
NUM: 3
TOK: '(1,7)(9,2)(8,3)'
x: 1 y: 7
TOK: '(9,2)(8,3)'
x: 9 y: 2
TOK: '(8,3)'
x: 8 y: 3
而且,这里是干净的输出:
x: 2 y: 3
x: 3 y: 4
x: 1 y: 7
x: 9 y: 2
x: 8 y: 3
【讨论】:
【参考方案2】:您正在从输入中读取“#”。输入中剩下的内容(包括最初的“2”)被读入缓冲区。
与输入流相比,您使用的字符串line
在sscanf(line,"%d",&nu_deadend);
之后仍然包含已成功扫描的初始“2”,而不是在成功扫描时丢失它。
因此,您尝试扫描“(...)”需要考虑“2”。
例如喜欢
sscanf(line,"%*d (%d,%d)",&x,&y);
对于第一个“()”。
第二个需要更精细的忽略,或者需要在适当的索引处开始扫描字符串中相关的“(”。 由于您需要循环,因此精心忽略无济于事。您必须首先搜索正确的“(”,然后进行扫描。
【讨论】:
“除了输入流”是什么意思? 我编辑了。现在清楚了吗? @kirjosieppo 好的,谢谢! 感谢您的回复,我实际上是 c 的新手。如何更改索引以开始扫描? 如果您知道相应“(”的索引,您可以将其添加到line
。有关详细信息,请单独提问。最好先检查现有的类似问题。以上是关于scanf 从生成的字符串的主要内容,如果未能解决你的问题,请参考以下文章
要从键盘读入含有空格字符的字符串,应该用啥函数?A.getc() B.gets() C.getchar() D.scanf