如何确保C中数据类型的一致性?

时间:2019-04-26 17:04:03

标签: c types

让我们假设以下代码:

from kivy.base import runTouchApp
from kivy.lang import Builder


runTouchApp(Builder.load_string("""
<UserSelectionInput@BoxLayout>:
    orientation: 'horizontal'
    size_hint: None, 1
    spacing: 4

    lb_text: ''
    sp_values: '', ''
    text: user_selection_spinner.text

    Label:
        id: user_selection_label
        size_hint_x: 0.4
        text: root.lb_text
    Spinner:
        id: user_selection_spinner
        text: 'Select'
        values: root.sp_values

<InnerBox@AnchorLayout>:
    anchor_x: 'center'
    anchor_y: 'center'

    BoxLayout:
        orientation: 'horizontal'
        size_hint: None, 1
        width: 2 * root.width / 3
        spacing: 1

        UserSelectionInput:
            width: root.width / 3
            sp_values: 'A', 'B', 'C'
            lb_text: 'Type'
            on_text:
                print("UserSelectionInput.spinner_1: text=", self.text)

        UserSelectionInput:
            width: root.width / 3
            sp_values: 'D', 'E', 'F', 'G'
            lb_text: 'Version'
            on_text:
                print("UserSelectionInput.spinner_2: text=", self.text)

<MainContent@GridLayout>:
    rows: 3

    Label:
        text: "Some Text"
    GridLayout:
        cols: 1
        InnerBox:

MainContent:

"""))

如何确保用户提供的数据是整数(而不是char)?

是否存在用于确保用户读取数据的库?

1 个答案:

答案 0 :(得分:0)

您需要围绕scanf进行其他工作。

首先,scanf将返回成功的转换和分配的次数-在这种情况下,您期望1成功。如果没有成功的转换和分配,它将返回0。如果输入错误,它将返回EOF

因此,作为第一步,您将执行以下操作:

if ( scanf( "%d", &n ) != 1 )
  // input was not an integer or error on input
else
  // successful input, do something with n

仅靠这本身是不够的。

%d告诉scanf跳过前导空格,然后读取第一个非数字字符。如果输入"abc",则没有有效的数字字符,scanf返回0,而n未经修改。

但是,如果您输入"12c"之类的字符串,则会读取并转换"12"n将被赋值为12scanf将返回1,并且 'c'将留在输入流中以阻止下一次读取。理想情况下,您应该拒绝整个输入。

有两种解决方法。您可以在输入后立即查看字符-如果它是空格,则输入有效:

char dummy;
int items_read = scanf( "%d%c", &n, &dummy );

如果items_read为2,则表示scanf至少读 一个十进制数字字符,然后读取一个非十进制数字字符。如果dummy包含空格字符,则表示输入为有效整数。如果dummy包含非空格字符,则用户在输入中用手指指了一个非数字字符(这意味着n中的值不应被信任)。无论哪种方式,我们都需要先将该虚拟字符推回输入流,然后再继续。

如果items_read为1,则表示我们至少读取 个十进制数字字符,然后按EOF键,这意味着我们的输入也必须是有效的整数。

因此,测试看起来像这样:

if ( items_read == 2 && isspace( dummy ) || items_read == 1 )
{
  // do something with n
  if ( items_read == 2 )
    ungetc( dummy, stdin );
}
else
{
  // input was not an integer, or error on input
}

或者,您可以将输入作为 string 读取,然后使用strtol进行转换:

char input[MAX_INPUT_LENGTH+1];
if ( fgets( input, sizeof input, stdin ) ) // using fgets instead of scanf for this
{
  char *chk; // stores address of first character *not* converted
  long tmp = strtol( input, &chk, 0 ); // convert into a temporary
  if ( isspace( *chk ) || *chk == 0 )
  {
    // input is good, assign tmp to n
    if ( tmp <= INT_MAX && tmp >= INT_MIN )
      n = tmp;
    else
      // input was within range for long but not int
  }
  else
    // trailing non-digit character
}