使用返回的字符串和 malloc 确定输入是否仅为数字或 q

determine if input is only digits or q using a returned string and malloc

提问人:Alexander Jonsson 提问时间:6/16/2023 更新时间:6/16/2023 访问量:63

问:

我想创建自己的函数,在其中输入输入,然后我的函数将确定我是只输入数字(例如 23412)还是只输入单个 q。其他所有内容都应计为无效输入。请注意,“242q42”、“5435q”或“qq”应被视为无效输入。我相信我设法创建了一个工作函数,可以决定我是否只输入数字,但我不确定我应该怎么做才能让 q 的东西正常工作。这是我的代码(如果您看到错误或低效的代码或我可以进行的其他改进,请发表评论):

char *readLine(int nr) {
   int ch, i=0;
   char *string;
   string = malloc(nr);

   while((ch = getchar()) != '\n') {
       if(i<nr && isdigit(ch)!=0) {
          string[i++]=ch;
       }
       else {
          string=NULL;
          return string;
       }
   }
   string[i]='\0';

   return string;
} 


int main(void) {
   int number;

   printf("Enter number: ");
   char *p=readLine(100);

   if(p==NULL) {
      printf("Invalid input!\n");
   }
   else {
      number=atoi(p);
      printf("Number as int is %d ", number);
   }
   free(p);

   return 0;
}
c 字符串 malloc

评论

0赞 Barmar 6/16/2023
您没有检查 .q
0赞 Pepe N O 6/16/2023
@Barmar 他在上面提到过
1赞 Andreas Wenzel 6/16/2023
您确定希望输入是“仅数字”吗?或者您希望用户也能够输入负数,例如 ?在这种情况下,不是数字。你也想允许那个角色吗?-23-
0赞 Alexander Jonsson 6/16/2023
只有正整数
0赞 Andreas Wenzel 6/16/2023
@AlexanderJonsson:输入是否应该被拒绝,因为字符不是数字?或者是否应该接受该输入,因为该输入是正整数?+23++23

答:

2赞 Barmar 6/16/2023 #1

添加另一个检查为第一个字符的语句,并将其添加到 .ifqstring

在分配之前,您还需要这样做,否则会出现内存泄漏。free(string)NULL

在呼叫者中,在尝试呼叫之前检查 。qatoi()

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

char *readLine(int nr) {
    int ch, i=0, q_entered = 0;
    char *string;
    string = malloc(nr);

    while((ch = getchar()) != '\n') {
        if(i<nr && !q_entered && isdigit(ch)!=0) {
            string[i++]=ch;
        } else if (i == 0 && ch == 'q') {
            string[i++] = ch;
            q_entered = 1;
        } else {
            free(string);
            return NULL;
        }
    }
    string[i]='\0';

    return string;
}

int main(void) {
    int number;

    printf("Enter number: ");
    char *p=readLine(100);

    if(p==NULL) {
        printf("Invalid input!\n");
    } else if (strcmp(p, "q") == 0) {
        printf("Quitting\n");
    } else {
        number=atoi(p);
        printf("Number as int is %d\n", number);
    }
    free(p);

    return 0;
}

也就是说,通常更好的设计是将输入代码与解析输入的代码分开。 应该只以任何格式返回该行,并且您应该有一个单独的函数来检查这一点。readLine()allDigits()

评论

0赞 Alexander Jonsson 6/16/2023
它适用于诸如“qq”之类的输入,但是如果我输入“q123”,则输出为“Number as int is 0”
0赞 Barmar 6/16/2023
我错过了那个案子。我添加了另一个变量,用于检查是否已输入,然后才允许添加数字。q
0赞 Andreas Wenzel 6/16/2023
OP 在评论部分表示,他们也希望输入被拒绝,但该解决方案没有这样做。但是,我仍然赞成这个答案,因为 OP 在实际问题中没有提到这一点。"0"
0赞 Barmar 6/16/2023
这是通过检查最简单的方法。if (number == 0)
0赞 Pepe N O 6/16/2023 #2

同时检查“q”,您的代码将如下所示:

char *readLine(int nr) {
   int ch, i=0;
   char *string;
   string = malloc(nr);

   while((ch = getchar()) != '\n') {
       if(i<nr && isdigit(ch)!=0) {
          string[i++]=ch;
       }       
       else if (ch=='q' && i==0 && getchar()=='\n')
       {
        string[i++]=ch;
        return string;
       }                      
       else {
          string=NULL;
          return string;
       }
   }
   string[i]='\0';
   return string;
} 


int main(void) {
   int number;

   printf("Enter a number or q: ");
   char *p=readLine(100);

   if(p==NULL) {
      printf("Invalid input!\n");
   }
   else if (p[0]=='q' && p[1]=='\0')   
   {
      printf("You entered q\n");
   }
   
   else {
      number=atoi(p);
      printf("Number as int is %d ", number);
   }
   free(p);

   return 0;
}
1赞 Andreas Wenzel 6/16/2023 #3

在您的问题中,您表示您希望输入包含以下任一内容

  • 仅数字,或
  • 只有单个字符."q"

否则,输入无效,应被拒绝。

但是,在评论部分,您指出输入字符串也应该被拒绝。相反,您希望输入在某个最大值的范围内。"0"1

在这种情况下,使用该函数来确定输入是否有效是没有意义的,因为它会将该输入报告为有效,尽管您希望该输入被拒绝为无效。isdigit"0"

出于这个原因,我建议您首先使用函数 fgets 读取整行,然后检查该行的内容。如果该行由单个字符组成,则您知道输入有效。否则,您可以使用函数 strtol 尝试将输入转换为整数。q

如果此转换失败,那么您将知道输入无效。

但是,如果转换成功,则可以执行进一步的检查,以确定转换后的整数是否在所需范围内,例如,它是否在 的范围内。120

下面是一个示例:

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

#define MIN_INPUT_NUMBER 1
#define MAX_INPUT_NUMBER 20

void get_line_from_user( const char prompt[], char buffer[], int buffer_size );

int main( void )
{
    char line[200], *p;
    long num;

    //read exactly one line of input from the user
    get_line_from_user(
        "Please enter a number: ",
        line, sizeof line
    );

    //determine whether the user entered `"q"` as input
    if ( line[0] == 'q' && line[1] == '\0' )
    {
        printf( "Input is valid, user entered \"q\".\n" );
        exit( EXIT_SUCCESS );
    }

    //attempt to convert input to a number
    errno = 0;
    num = strtol( line, &p, 10 );

    //verify that at least one character was converted
    if ( p == line )
    {
        printf( "Error: Unable to convert input to integer!\n" );
        exit( EXIT_FAILURE );
    }

    //verify that input is not too small or too large to be
    //representable as a `long int`
    if ( errno == ERANGE )
    {
        printf( "Error: Input is outside the range of a long int!\n" );
        exit( EXIT_FAILURE );
    }

    //verify that either all characters were converted or that all
    //remaining characters are whitespace characters, so that input
    //such as "242q42" gets rejected
    for ( ; *p != '\0'; p++ )
    {
        if ( !isspace( (unsigned char)*p ) )
        {
            printf( "Error: Not all non-whitespace characters were converted!\n" );
            exit( EXIT_FAILURE );
        }
    }

    //verify that the converted integer is in the desired range
    if ( num < MIN_INPUT_NUMBER || num > MAX_INPUT_NUMBER )
    {
        printf(
            "Error: Input must be in the range %d to %d.\n",
            MIN_INPUT_NUMBER, MAX_INPUT_NUMBER
        );
        exit( EXIT_FAILURE );
    }

    //everything went ok, so print the result
    printf( "Input was valid! User entered %ld.\n", num );

    return EXIT_SUCCESS;
}

//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
    for (;;) //infinite loop, equivalent to while(1)
    {
        char *p;

        //prompt user for input
        fputs( prompt, stdout );

        //attempt to read one line of input
        if ( fgets( buffer, buffer_size, stdin ) == NULL )
        {
            printf( "Error reading from input!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to find newline character
        p = strchr( buffer, '\n' );

        //make sure that entire line was read in (i.e. that
        //the buffer was not too small to store the entire line)
        if ( p == NULL )
        {
            int c;

            //a missing newline character is ok if the next
            //character is a newline character or if we have
            //reached end-of-file (for example if the input is
            //being piped from a file or if the user enters
            //end-of-file in the terminal itself)
            if ( (c=getchar()) != '\n' && !feof(stdin) )
            {
                if ( c == EOF )
                {
                    printf( "Error reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

                printf( "Input was too long to fit in buffer!\n" );

                //discard remainder of line
                do
                {
                    c = getchar();

                    if ( c == EOF )
                    {
                        //this error message will be printed if either
                        //a stream error or an unexpected end-of-file
                        //is encountered
                        printf( "Error reading from input!\n" );
                        exit( EXIT_FAILURE );
                    }

                } while ( c != '\n' );

                //reprompt user for input by restarting loop
                continue;
            }
        }
        else
        {
            //remove newline character by overwriting it with
            //null character
            *p = '\0';
        }

        //input was ok, so break out of loop
        break;
    }
}

此程序具有以下行为:

Please enter a number: 242q42
Error: Not all non-whitespace characters were converted!
Please enter a number: 5435q
Error: Not all non-whitespace characters were converted!
Please enter a number: qq
Error: Unable to convert input to integer!
Please enter a number: q
Input is valid, user entered "q".
Please enter a number: 50000000000000000000000000
Error: Input is outside the range of a long int!
Please enter a number: -23
Error: Input must be in the range 1 to 20.
Please enter a number: 0
Error: Input must be in the range 1 to 20.
Please enter a number: 22
Error: Input must be in the range 1 to 20.
Please enter a number: 17
Input was valid! User entered 17.

为了更改允许的范围,您可以更改线

#define MIN_INPUT_NUMBER 1
#define MAX_INPUT_NUMBER 20

在程序中。