简体   繁体   English

使用strtol验证ANSI C中的整数输入

[英]Using strtol to validate integer input in ANSI C

I am new to programming and to C in general and am currently studying it at university. 我是编程和C的新手,我目前正在大学学习。 This is for an assignment so I would like to avoid direct answers but are more after tips or hints/pushes in the right direction. 这是一个任务,所以我想避免直接的答案,但更多的提示或提示/推动正确的方向。

I am trying to use strtol to validate my keyboard input, more specifically, test whether the input is numeric. 我试图使用strtol来验证我的键盘输入,更具体地说,测试输入是否为数字。 I have looked over other questions on here and other sites and I have followed instructions given to other users but it hasn't helped me. 我已经查看过这里和其他网站上的其他问题,我已经按照给其他用户的说明,但它没有帮助我。

From what I have read/ understand of strtol (long int strtol (const char* str, char** endptr, int base);) if the endptr is not a null pointer the function will set the value of the endptr to the first character after the number. 从我读取/理解的strtol (long int strtol(const char * str,char ** endptr,int base);)如果endptr不是空指针,该函数将endptr的值设置为第一个字符在号码之后。

So if I was to enter 84948ldfk, the endptr would point to 'l', telling me there is characters other than numbers in the input and which would make it invalid. 因此,如果我要输入84948ldfk,则endptr将指向'l',告诉我输入中除了数字之外还有其他字符,这会使其无效。

However in my case, what is happening, is that no matter what I enter, my program is returning an Invalid input. 然而在我的情况下,正在发生的事情是,无论我输入什么,我的程序返回一个无效的输入。 Here is my code: 这是我的代码:

void run_perf_square(int *option_stats)
{
   char input[MAX_NUM_INPUT + EXTRA_SPACES]; /*MAX_NUM_INPUT + EXTRA_SPACES are defined
                                              *in header file. MAX_NUM_INPUT = 7 
                                              *and EXTRA_SPACES 
                                              *(for '\n' and '\0') = 2. */
   char *ptr;
   unsigned num=0; /*num is unsigned as it was specified in the start up code for the 
                    *assignment. I am not allow to change it*/

   printf("Perfect Square\n");
   printf("--------------\n");
   printf("Enter a positive integer (1 - 1000000):\n");
   if(fgets(input, sizeof input, stdin) != NULL)
   {
      num=strtol(input, &ptr, 10);
      if( num > 1000001)
      {
         printf("Invalid Input! PLease enter a positive integer between 1 
                  and 1000000\n");
         read_rest_of_line();        /*clears buffer to avoid overflows*/
         run_perf_square(option_stats);
      }
      else if (num <= 0)
      {
         printf("Invalid Input! PLease enter a positive integer between 1 
                  and 1000000\n");
         run_perf_square(option_stats);
      }
      else if(ptr != NULL)
      {
         printf("Invalid Input! PLease enter a positive integer between 1 
                  and 1000000\n");
         run_perf_square(option_stats);
      }
      else
      {
         perfect_squares(option_stats, num);
      }
   }
}

Can anyone help me in the right direction? 谁能帮助我朝正确的方向发展? Obviously the error is with my if(ptr != NULL) condition, but as I understand it seems right. 显然错误是我的if(ptr!= NULL)条件,但据我所知它似乎是正确的。 As I said, I have looked at previous questions similar to this and took the advice in the answers but it doesn't seem to work for me. 正如我所说,我已经看过以前类似的问题,并在答案中提出了建议,但这似乎对我没有用。 Hence, I thought it best to ask for my help tailored to my own situation. 因此,我认为最好根据自己的情况寻求帮助。

Thanks in advance! 提前致谢!

You're checking the outcome of strtol in the wrong order, check ptr first, also don't check ptr against NULL , derference it and check that it points to the NUL ( '\\0' ) string terminator. 你正在以错误的顺序检查strtol的结果,首先检查ptr ,也不要检查ptr对NULL ,对它进行修改并检查它是否指向NUL'\\0' )字符串终止符。

if (*ptr == '\0') {
  // this means all characters were parsed and converted to `long`
}
else {
  // this means either no characters were parsed correctly in which
  // case the return value is completely invalid
  // or
  // there was a partial parsing of a number to `long` which is returned
  // and ptr points to the remaining string
}

num > 1000001 also needs to be num > 1000000 num > 1000001也需要为num > 1000000

num < 0 also needs to be num < 1 num < 0也需要为num < 1

You can also with some reorganising and logic tweaks collapse your sequence of if statements down to only a single invalid branch and a okay branch. 您还可以通过一些重组和逻辑调整将if语句序列折叠为仅一个无效分支和一个okay分支。

OP would like to avoid direct answers .... OP希望避免直接回答....

validate integer input 验证整数输入

  1. Separate I/O from validation - 2 different functions. 将I / O与验证分开 - 2种不同的功能。

  2. I/O: Assume hostile input. I / O:假设敌对输入。 (Text, too much text, too little text. I/O errors.) Do you want to consume leading spaces as part of I/O? (文本,文本太多,文本太少.I / O错误。)您是否希望将前导空格作为I / O的一部分使用? Do you want to consume leading 0 as part of I/O? 您是否希望将前导0作为I / O的一部分使用? (suggest not) (建议不要)

  3. Validate the string (NULL, lead space OK?, digits after a trailing space, too short, too long, under-range, over-range, Is 123.0 an OK integer) 验证字符串(NULL,引导空间OK ?,尾随空格后的数字,太短,太长,欠范围,超范围,是123.0是否为OK整数)

  4. strtol() is your friend to do the heavy conversion lifting. strtol()是你做重型转换提升的朋友。 Check how errno should be set and tested afterward. 检查之后应该如何设置和测试errno Use the endptr . 使用endptr Should its value be set before. 它的值是否应该在之前设定。 How to test afterward. 以后如何测试。 It consume leading spaces, is that OK? 它消耗领先的空间,是吗? It converts text to a long , but OP wants the nebulous "integer". 它将文本转换为long ,但OP需要模糊的“整数”。

Qapla' Qapla”

The function strtol returns long int, which is a signed value. 函数strtol返回long int,这是一个带符号的值。 I suggest that you use another variable (entry_num), which you could test for <0, thus detecting negative numbers. 我建议你使用另一个变量(entry_num),你可以测试<0,从而检测负数。

I would also suggest that regex could test string input for digits and valid input, or you could use strtok and anything but digits as the delimiter ;-) Or you could scan the input string using validation, something like: 我还建议正则表达式可以测试数字和有效输入的字符串输入,或者你可以使用strtok和除数字之外的任何东西作为分隔符;-)或者你可以使用验证扫描输入字符串,如:

int validate_input ( char* input )
{
    char *p = input;
    if( !input ) return 0;
    for( p=input; *p && (isdigit(*p) || iswhite(*p)); ++p )
    {
    }
    if( *p ) return 0;
    return 1;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM