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 不适合这个。最好使用fgetscpstrtok 并将strtok 的返回值传递给sscanf 此外,您永远不会为第二行重置firstCharacter(即我假设每一行都以@987654338 开头@) 【参考方案1】:

来自我的***评论...

scanf 不同,sscanf 会从它给定的缓冲区开始。因此,您可能需要使用(例如)char *cp = line;,然后使用并前进cp 以指向下一个令牌。

sscanf 不适合这个,因为它返回一个 count不是消耗的字节数。

最好使用fgetscpstrtok并将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”)被读入缓冲区。

与输入流相比,您使用的字符串linesscanf(line,"%d",&amp;nu_deadend); 之后仍然包含已成功扫描的初始“2”,而不是在成功扫描时丢失它。

因此,您尝试扫描“(...)”需要考虑“2”。

例如喜欢

sscanf(line,"%*d (%d,%d)",&x,&y);

对于第一个“()”。

第二个需要更精细的忽略,或者需要在适当的索引处开始扫描字符串中相关的“(”。 由于您需要循环,因此精心忽略无济于事。您必须首先搜索正确的“(”,然后进行扫描。

【讨论】:

“除了输入流”是什么意思? 我编辑了。现在清楚了吗? @kirjosieppo 好的,谢谢! 感谢您的回复,我实际上是 c 的新手。如何更改索引以开始扫描? 如果您知道相应“(”的索引,您可以将其添加到line。有关详细信息,请单独提问。最好先检查现有的类似问题。

以上是关于scanf 从生成的字符串的主要内容,如果未能解决你的问题,请参考以下文章

要从键盘读入含有空格字符的字符串,应该用啥函数?A.getc() B.gets() C.getchar() D.scanf

scanf sscanf fscanf

如何使用 scanf 从用户输入中获取字符串( char * ),由双引号分隔并包含空格 [关闭]

scanf()函数分析

C语言scanf函数详解和示例

scanf函数输入字符串详解