【问题标题】:Universal Product Code challenge通用产品代码挑战
【发布时间】:2015-04-09 20:25:56
【问题描述】:

我很好奇如何在C语言中正确使用%d。我目前正在学习 C 编程课程,我们遇到了一个小挑战来编辑教科书(C Programming A Modern Approach, K. N. KING)中的代码。 目标是从条形码的三个输入中编辑代码:

  • 第 1 位、第 5 位和第 5 位最后一个输入,或
  • 一次所有 11 位数字。

在文中解释运算符的方式中,我相信%1d允许将输入的整数单独分配给相应的变量。 以下是修改后的代码。

#include <stdio.h>

int main(void)
{

    /* 11 integers that come from the bar code of the product, 
    then 2 intermediate variables for calulation, and lastly the final answer.*/

    int d, i1, i2, i3, i4, i5, j1, j2, j3, j4, j5, first_sum, second_sum, total;    

    printf("Enter the 11 digit Universal Product Code: ");
    scanf("%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d", &d, &i1, &i2, &i3, &i4, &i5, &j1, &j2, &j3, &j4, &j5);

    // The steps for each calculation from the textbook.
    first_sum = d + i2 + i4 + j1 + j3 + j5;
    second_sum = i1 + i3 + i5 + j2 + j4;
    total = 3 * first_sum + second_sum;

    // Prints check digit for given product code.
    printf("Check Digit: %d\n", 9 - ((total-1) % 10));
    return 0;
}

但是,当我运行程序时(与原始程序相同的问题),它不接受将 11 位数字输入为 11 个单独的数字,而只接受一个大数字。相反,它仍然需要在每个整数后按回车键。可以这样读取整数并将其分配给变量吗?

【问题讨论】:

  • 将其读取为字符串,然后使用 strtok 对其进行标记
  • 永远不要使用strtok。它被彻底破坏了。
  • 读取为字符串,依次取出每个字符(srtr[0],str[1],str[2],...)
  • @abelenky - 从不使用 strtok。它被彻底破坏了 - 至少引用一些东西。 strtok() 没有 无可救药地坏了。最近有人引用的问题是它缺乏线程安全性。但它并不声称线程安全。那么,有什么问题呢?
  • 1) 要么你的编译器坏了,要么描述的事件不是这样。 2) scanf() 的返回值是多少,d 的返回值是多少?

标签: c operators


【解决方案1】:

给定下面的代码,如果你输入“123”然后按回车,它将打印“1 2 3”。

int main( void )
{
    int a, b, c;

    printf( "Enter a three digit number\n" );
    if ( scanf( "%1d%1d%1d", &a, &b, &c ) != 3 )
        printf( "hey!!!\n" );
    else
        printf( "%d %d %d\n", a, b, c );
}

也就是说%1d 一次读取一个数字。


以下示例来自 C11 规范草案的第 7.21.6.2 节

EXAMPLE 2 The call:
    #include <stdio.h>
    /* ... */
    int i; float x; char name[50];
    fscanf(stdin, "%2d%f%*d %[0123456789]", &i, &x, name);

with input:
    56789 0123 56a72
will assign to i the value 56 and to x the value 789.0, will skip 0123,
and will assign to name the sequence 56\0. The next character read from 
the input stream will be a.

这一直是这样,所以如果你的编译器不这样做,你需要一个新的编译器。

【讨论】:

  • 我猜这取决于 libc 的实现...你测试了哪一个?
  • @SukkoPera:它应该总是有效的,除非我遗漏了什么。 OP,你能用你的实现测试这段代码吗?也许这是一些奇怪的错误或什么的。
  • 好的,感谢 C11 草案参考。现在我们知道这是标准规定的行为,我不确定。
【解决方案2】:

您的问题的简短回答是否定的。 %d 标签将尽可能获取最大的整数,而不仅仅是单个数字,除非字符串中有某种分隔空间。

解决这个问题的一般方法是将输入读取为字符串,然后使用 strtok 等对输入进行标记。

但是,由于在 C 中字符串只是字符数组,因此您也可以遍历循环并调用 string[0]、string[1] 等,然后将它们分别转换为整数正如您事先知道输入的长度一样,这听起来像您的解释。

【讨论】:

  • 不是反对票——而是关于然后使用 strtok 标记输入:使用strtok() 标记什么分隔符。 (我认为你的第三段是一个合理的方法)
  • 我是反对者:%d 标签将获取它所能获取的最大整数,而不仅仅是一个数字,除非字符串中有某种分隔空间。如其他答案所示,这是一个本质上错误的陈述。
【解决方案3】:

嗯,我刚刚测试了以下程序:

#include <stdio.h>

int main (void) {
    int n, x, y, z;

    n = sscanf ("1234567890", "%1d%1d%1d", &x, &y, &z);

    printf ("Found %d items: %d, %d and %d\n", n, x, y, z);

    return 0;
}

我在 Slackware Linux 下使用常用的 GCC 和 glibc 编译它。它输出:

找到 3 个项目:1、2 和 3

所以,它似乎应该按照您希望的方式工作,但我不确定这实际上是标准行为还是 GCC 扩展。

另一种方法是使用%1c 一次读取一个字符,然后使用atoi() 将其转换为相应的整数,或者简单地从中减去'0',如果您必须/想要绝对使用scanf()大大地。否则我会用 %s 读取整个字符串,然后迭代单个字符,这在 C 中很容易,因为字符串只是一个字符数组。

【讨论】:

    【解决方案4】:

    您的代码应该可以在 gcc 编译器中运行。 但是,由于它不起作用,您应该将 11 位数字转换为字符数组,即字符串,然后遍历数组,同时将每个字符转换为其对应的整数值。在您的情况下,您只需计算 array[i]-'0'd = array[0]-'0'i1 = array[1]-'0' 等即可获得该值。

    【讨论】:

      最近更新 更多