如何使用scanf中的空格输入3个字符到char数组?

时间:2015-08-19 23:43:05

标签: c scanf

我以前是一名java程序员,但我现在正在大学(计算机科学专业)修读C课程。

我需要用户能够输入3个字符,前2个是数字,最后1个是'v'或'h'。 例如“1 2 v”。

我需要用户能够输入每个字符之间的空格。

这是我目前的代码:

// Compact lambda
lst.Find(a => a.Name.Equals("Alex"))

// Explicitly typed parameter
lst.Find((FindPerson a) => a.Name.Equals("Alex"))

// Explicit delegate type
lst.Find(new Predicate<FindPerson>(a => a.Name.Equals("Alex")))

// Combination of the two above
lst.Find(new Predicate<FindPerson>((FindPerson a) => a.Name.Equals("Alex")))

// Explicit delegate type through casting
lst.Find((Predicate<FindPerson>)(a => a.Name.Equals("Alex")))

// Lambda block
lst.Find(a => { return a.Name.Equals("Alex"); })

// Delegate block
lst.Find((Predicate<FindPerson>)(delegate(FindPerson a) { return a.Name.Equals("Alex"); }))

// ... etc

}

但是如果我运行它,当我输入带有“12v”之类的空格的字符时它可以正常工作,但是如果我输入“1 2 v”,它将打印出“1”,调用printBox,然后打印出来“ 2“,然后再打印出来,等等。

如果有人能解释我在这里做错了什么,我会很感激。

4 个答案:

答案 0 :(得分:3)

  

如果有人能解释我在这里做错了什么,我会很感激。

短篇小说是:您的代码无法满足您的要求。它根本不能做你想做的事。

您的要求是:

  • 所有字段必须是一个字符。您的代码无法满足此要求。您的代码将错误地接受每个字段的多个字符。
  • 字段之间必须有一个空格(恰好是一个空格?)。您的代码无法满足此要求。字段之间可能有多个空格,您的代码会错误地接受它。

实际上,您的代码通过访问move数组超出范围来调用未定义的行为。请考虑由于上述某种情况i可能会变成某些情况值高于3.此代码中可能会发生什么:move[i] = input[i];

您的代码也太复杂了。您的所有功能都可以由scanf单独执行。当你知道如何正确使用它时,它是一个非常强大的功能......当你有机会时,我建议多次阅读和理解the manual。你会学习很多

我注意到你在你提出的逻辑中忽略了一些东西:预计第一个字段也可能是'x',它对应于 exit 用例。这是一个糟糕的设计;来电者没有机会清理......但我会用它来运行。您确实应该使用return(并返回int值或其他内容(对应于错误/成功)。

让我们把最后一段放在一边,因为我们可以简单地认为'x'是无效输入(并因此退出),我不想改变你的功能合同;我会留给你的。到目前为止所描述的表达似乎是int x = scanf("%1[0123456789]%*1[ ]%1[0123456789]%*1[ ]%1[vh]", a, b, c);

请注意,abc应该有足够的空间来存储长度为一个字节的字符串。也就是说,他们的声明应该是:char a[2], b[2], c[2];

请务必检查返回值(示例中为x)!如果x为3,则可以安全地假设三个变量{{1} },ab可以安全使用。如果c为2,则可以安全地假设xa可以安全使用,依此类推......如果bx或{ {1}},它们都不能安全使用。

通过检查返回值,您可以拒绝与该精确模式不匹配的输入,即:

  • 将拒绝宽度不是一个字节的字段。
  • 太多或太少的空格都会被拒绝。

你忽略了提到的其他东西,它也存在于你的代码中:Chux提到你可能期望输入以EOF(换行符)字符终止。这也可以使用0

以多种方式实现
  • '\n'会尝试准确读取和丢弃一个scanf字符,但无法确保成功。 scanf("%1*[\n]");更适合此目的; '\n'的某些内容可能是有意义的,如果你希望确保输入线完美形成并且当它们不是......时展开...... {/ 1}}
  • getchar更有意义;如果你有兴趣每行阅读一个项目,那么丢弃该行上剩下的所有内容,然后是新行字符本身是有意义的。请注意,您的程序应始终告诉用户何时丢弃或截断输入。您也可以使用if (getchar() != '\n') { exit(EXIT_FAILURE); }
#define BOMB_OUT

答案 1 :(得分:1)

%s用scanf读取以空格分隔的字符串,所以如果这不是你想要的,那就不是用的了。 %c读取单个字符,但不跳过whitespce,因此您可能还希望格式中的(空格)跳过空格:

char input[3];

scanf(" %c %c %c", intput, input+1, input+2);

将读取3个非空格字符并跳过它们之前或之间的任何空格。您还应检查scanf的返回值以确保它为3 - 如果不是,则在到达文件结尾之前输入中的字符少于3个。

答案 2 :(得分:0)

由于潜在的缓冲区溢出,通过scanf读取字符串通常是一个坏主意。考虑使用{/ 1}}或更好fscanf,如

fgets

请注意&#39; \ 0&#39;。

的额外字节

此外,您在此处将char与字符串进行比较:fgets(input, 15, stdin); 。它应该是input[i] != "\n"

顺便说一句,你可以使用像

这样的东西
input[i] != '\n'

答案 3 :(得分:0)

这看起来像两个简单的错误。

您需要为move []和input []

使用单独的索引
    int i = 0;
    while(input[i] != 0){

            if(input[i] != ' ' && input[i] != "\n"){
                    move[i] = input[i];
            }
            i++;
    }

想象一下输入1 2 v

输入[0]!= 0,所以我们进入循环

它不是&#39; &#39;或者&#39; \ n&#39;或者,所以我们将input [0]复制到move [0]

到目前为止一切顺利

你增加i,发现输入[1] ==&#39; &#39;

但是你再次增加我

你发现你对输入[2](2)感兴趣 - 所以你把它复制到移动[2],而不是移动[1]。糟糕!

然后更糟糕的是,你永远不会在move []的最后一个有效字符后面放一个字符串结尾的字符。