当输入为浮点时,如何阻止scanf解析整数部分

当输入为浮点时,如何阻止scanf解析整数部分,c,floating-point,integer,C,Floating Point,Integer,所以这个程序是一个简单的十进制到二进制的转换器 我希望代码重复,直到用户按下ctrl+D。我还想让用户知道,如果他们输入像-2或1.1这样的数字,那么输入的数字不是正整数 问题是当他们输入一个floatmy code时,我的代码只是无限地打印我的第一个print语句 这是我的代码: void DecToBin(int userInput){ int binary[32]; int i = 0; while (userInput > 0) { binary[i

所以这个程序是一个简单的十进制到二进制的转换器

我希望代码重复,直到用户按下
ctrl+D
。我还想让用户知道,如果他们输入像
-2
1.1
这样的数字,那么输入的数字不是正整数

问题是当他们输入一个
float
my code时,我的代码只是无限地打印我的第一个print语句

这是我的代码:

void DecToBin(int userInput){
   int binary[32];
   int i = 0;
   while (userInput > 0) {
       binary[i] = userInput % 2;
       userInput /= 2;
       i++;
   }

   for (int j = i - 1; j >= 0; --j) {
       printf("%d", binary[j]);
   }
}
因此,当我输入像
11.1
或负值之类的内容时,它不应该接受它,并在终端中打印
“请输入一个正整数(或EOF退出)”

应接受
11.0
等输入


所以,我想问的是,我的代码有什么问题使得它这样做,我应该如何修复它?我是否应该使用一个
float
来代替?

条件
userDec%1==0
始终为真,任何整数除以1的余数始终为0

scanf(“%d”,&userDec)
无法解析输入的值时,它返回0,当您的输入不是数字时会发生这种情况,您可以利用这种情况

要检查一个值是否有小数部分,我们可以使用
math.h
库函数,该函数将double的小数部分与其整数部分分开并返回,因此是的,使用
double
(而不是精度较低的
float
)将是一个不错的策略

(在Linux中,使用
gcc
可能需要使用
-lm
编译器标志链接
math.h
头。)

将这些更改应用到代码中,您将得到如下结果:

#include <stdlib.h>
#include <math.h>
int main(无效)
{
双用户DEC;
二重积分;
字符输入[100];
char*endptr=NULL;
INTC;
//将输入解析为字符串
while(printf(“请输入正整数(或EOF以退出):”&&scanf(“%99[^\n]”,input)==1)
{
errno=0;
userDec=strtod(输入,&endptr);//转换为双精度
//如果为负或溢出或输入无效或分数
如果(userDec<0 | | | |(userDec==大的|值&&errno==ERANGE)| |*endptr!='\0'| | modf(userDec,&integral))
{
printf(“对不起,这不是一个正整数。\n”);
}
其他的
{
printf(“%.0lf(基数-10)相当于”,userDec);
德克托宾(userDec);
printf(“(base-2)!\n”);
}
而((c=getchar())!='\n'&&c!=EOF){continue;}//清除缓冲区
如果(c==EOF){return EXIT_FAILURE;}//c=EOF,则视为不可恢复
} 
返回退出成功;
}
当然,有了这样的东西,您需要支持转换器函数来接受更大的值,它现在只接受
int
作为参数


无论哪种方式,代码中的所有这些输入限制都应该方便地记录在案。

请记住,
scanf
返回成功转换和赋值的次数,或者在文件结束或读取错误时返回
EOF

%d
转换说明符将跳过前导空格并读取十进制数字,直到第一个非十进制数字字符如果第一个非空白字符不是十进制数字,则匹配失败,
scanf
将返回
0
,而不是
EOF

当您输入
11.1
时,
scanf
成功地将
11
转换并分配给
userDec
,并返回
1
。但是,它会将剩余的
.1
保留在输入流中,而这永远不会被清除

下次读取时,
scanf
看到
.1
并立即停止读取并返回
0
。但是,您只测试了
scanf
不会返回
EOF
,因此它永远不会跳出循环

使用
scanf
时,您最好根据您希望成功转换的项数进行测试-在这种情况下,您的测试应该是

if ( res != 1 )
  break;
我将按如下方式重新构造您的读取循环:

while ( 1 )
{
  // prompt

  if ( (res = scanf( "%d", &userDec)) != 1 )
  {
    // print error message
    break;
  }
  else
  {
    if ( userDec <= 0 )
    {
      // print error message
    }
    else
    {
      // process input
    }
  }
}
if ( res != EOF )
{
  // had a matching failure from bad input
}
else
{
  // user signaled EOF
}

最可靠的方法不使用
scanf()
读取用户输入行。而是使用
fgets()
,然后使用
strto*()
和friends解析字符串

由于OP寻找的是整数或带整数值的浮点数形式的有效输入,所以构造辅助程序例程来做好每项工作

#include <ctype.h>
#include <errno.h>
#include <stdio.h>

void base(int n) {
  if (n == 0)
    return;
  base(n / 2);
  printf("%d", n % 2);
}
// Return error flag, 0 implies success
int String2int(int *dest, const char *s, int min, int max) {
  if (dest == NULL)
    return 1;
  *dest = 0;
  if (s == NULL)
    return 1;

  errno = 0;
  char *endptr;
  long L = strtol(s, &endptr, 0);

  if (s == endptr)
    return 1;  // no conversion
  if (errno == ERANGE || L < min || L > max)
    return 1; // out of range
  while (isspace((unsigned char) *endptr))
    endptr++;
  if (*endptr)
    return 1;  // Extra text after input
  *dest = (int) L;
  return 0;
}

int String2Whole(double *dest, const char *s, double min, double max_plus1) {
  if (dest == NULL)
    return 1;
  *dest = 0.0;
  if (s == NULL)
    return 1;

  errno = 0;
  char *endptr;
  double d = strtof(s, &endptr);

  if (s == endptr)
    return 1;  // no conversion
  // Save whole part into dest
  if (modf(d, dest))
    return 1; // Test return of non-zero fractional part.
  if (d < min || d >= max_plus1)
    return 1; // out of range
  while (isspace((unsigned char) *endptr))
    endptr++;
  if (*endptr)
    return 1;  // Extra text after input
  return 0;
}

userDec%1==0
应该测试什么条件?当然,除以
1
总会留下
0
的余数。scanf函数希望得到一个整数,而不是浮点或双精度类型。我假设整数输入没有同样的问题。您可能还需要一个单独的函数将小数部分转换为二进制从输入中提取字符,直到找到与格式字符串不匹配的字符。因此,如果您输入
12.34
scanf将取
1
2
,然后找到
,但
%d
格式中不允许小数点,因此它将停止取字符。然后转换
12
并返回到scanf,但scanf找到的第一个字符是
,它无法使用该字符,因此停止。但是你没有检查返回码。要修复它,请检查scanf的返回代码,如果失败,则F设置行的其余部分以收集
.34\n
,然后再次扫描。
res=(int)(res)-这是一个完全无用的语句。它打算做什么?@Amy在
int
中没有小数部分哦,是的,对不起,我想我在我最初的问题中没有解释太多。我希望输入11.1告诉用户它不工作。我的代码只是重复了“请输入…”语句。那么我应该作为一个浮标来扫描吗?@osito_solito,是的,是的
int main(void)
{
    double userDec;
    double integral;
    char input[100];
    char *endptr = NULL;
    int c;

    // parse input as string
    while (printf("Please enter a positive whole number (or EOF to quit): ") && scanf("%99[^\n]", input) == 1)
    {
        errno = 0;
        userDec = strtod(input, &endptr); // convert to double
        
        // if negative or overflow or invalid input or fractional
        if (userDec < 0 || (userDec == HUGE_VAL && errno == ERANGE) || *endptr != '\0' || modf(userDec, &integral))
        {
            printf("Sorry, that was not a positive whole number.\n");
        }
        else
        {
            printf("%.0lf (base-10) is equivalent to ", userDec);
            DecToBin(userDec);
            printf(" (base-2)!\n");
        }
        while ((c = getchar()) != '\n' && c != EOF) { continue; } // clear buffer
        if (c == EOF) { return EXIT_FAILURE; }   // c = EOF, treated as unrecoverable
    } 
    return EXIT_SUCCESS;
}
if ( res != 1 )
  break;
while ( 1 )
{
  // prompt

  if ( (res = scanf( "%d", &userDec)) != 1 )
  {
    // print error message
    break;
  }
  else
  {
    if ( userDec <= 0 )
    {
      // print error message
    }
    else
    {
      // process input
    }
  }
}
if ( res != EOF )
{
  // had a matching failure from bad input
}
else
{
  // user signaled EOF
}
 int itemsRead;
 int userDec;
 char dummy;

 /**
  * Read the next integer input and the character immediately
  * following.
  */
 itemsRead = scanf( "%d%c", &userDec, &dummy );
 
 /**
  * Here are the possible scenarios:
  *
  * 1.  If itemsRead is 2, then we read at least one decimal digit
  *     followed by a non-digit character.  If the non-digit character
  *     is whitespace, then the input was valid.  If the non-digit
  *     character is *not* whitespace, then the input was not valid.
  *
  * 2.  If itemsRead is 1, then we read at least one decimal digit
  *     followed immediately by EOF, and the input was valid.
  *
  * 3.  If itemsRead is 0, then we had a matching failure; the first
  *     non-whitespace character we saw was not a decimal digit, so the
  *     input was not valid.
  *
  * 4.  If itemsRead is EOF, then we either saw an end-of-file condition 
  *     (ctrl-d) before any input, or there was a read error on the input
  *     stream.
  *  
  * So, our test is if itemsRead is less than 1 OR if itemsRead is 2 and 
  * the dummy character is not whitespace
  */
 if ( itemsRead < 1 || itemsRead == 2 && !isspace( dummy ) )
 {
   // input was not valid, handle as appropriate.
 }
 else
 {
   // input was valid, process normally
 }
#include <ctype.h>
#include <errno.h>
#include <stdio.h>

void base(int n) {
  if (n == 0)
    return;
  base(n / 2);
  printf("%d", n % 2);
}
// Return error flag, 0 implies success
int String2int(int *dest, const char *s, int min, int max) {
  if (dest == NULL)
    return 1;
  *dest = 0;
  if (s == NULL)
    return 1;

  errno = 0;
  char *endptr;
  long L = strtol(s, &endptr, 0);

  if (s == endptr)
    return 1;  // no conversion
  if (errno == ERANGE || L < min || L > max)
    return 1; // out of range
  while (isspace((unsigned char) *endptr))
    endptr++;
  if (*endptr)
    return 1;  // Extra text after input
  *dest = (int) L;
  return 0;
}

int String2Whole(double *dest, const char *s, double min, double max_plus1) {
  if (dest == NULL)
    return 1;
  *dest = 0.0;
  if (s == NULL)
    return 1;

  errno = 0;
  char *endptr;
  double d = strtof(s, &endptr);

  if (s == endptr)
    return 1;  // no conversion
  // Save whole part into dest
  if (modf(d, dest))
    return 1; // Test return of non-zero fractional part.
  if (d < min || d >= max_plus1)
    return 1; // out of range
  while (isspace((unsigned char) *endptr))
    endptr++;
  if (*endptr)
    return 1;  // Extra text after input
  return 0;
}
char *doit(void) {
  int i = 0;
  char buf[100];
  if (fgets(buf, sizeof buf, stdin) == NULL) {
    return "Input closed";
  }

  if (String2int(&i, buf, 0, INT_MAX)) {
    double x;
    if (String2Whole(&x, buf, 0.0, (INT_MAX / 2 + 1) * 2.0)) {
      return "Invalid input";
    }
    i = (int) x;
  }
  printf("O happy day! %d\n", i);
  return 0;
}

int main(void) {
    doit();
}