繁体   English   中英

如何仅在 C 中具有一定长度时才接受字符串输入,否则请用户再次输入字符串

[英]How to accept string input only if it of certain length in C else ask user to input the string again

如何在 C 中接受一组字符串作为输入,如果超过一定长度,如何再次提示用户重新输入字符串。 我尝试如下

#include<stdio.h>
int main()
{
    char arr[10][25]; //maximum 10 strings can be taken as input of max length 25
    for(int i=0;i<10;i=i+1)
    {
        printf("Enter string %d:",i+1);
        fgets(arr[i],25,stdin);
    }
}

但是这里 fgets 也接受大于该长度的字符串。 如果用户点击返回,则必须将第二个字符串作为输入。 我是 C 的新手

仅当字符串输入具有一定长度时如何接受

形成一个助手 function 来处理各种边缘情况。 使用fgets() ,然后删除潜在'\n'fgets()保留)并检测长输入。

一些未经测试的代码给 OP 一个想法:

#include <assert.h>
#include <stdio.h>

// Pass in the max string _size_.
// Return NULL on end-of-file without input.
// Return NULL on input error.
// Otherwise return the buffer pointer.
char* getsizedline(size_t sz, char *buf, const char *reprompt) {
  assert(sz > 0 && sz <= INT_MAX && buf != NULL); // #1
  while (fgets(buf, (int) sz, stdin)) {
    size_t len = strlen(buf);
    // Lop off potential \n
    if (len > 0 && buf[--len] == '\n') { // #2
      buf[len] = '\0';
      return buf;
    }
    // OK if no more input
    if (feof(stdin)) {                     // #3
      return buf;
    }
    // OK if next ends the line
    int ch = fgetc(stdin);
    if (ch == '\n' || feof(stdin)) {       // #4 
      return buf;
    }

    // Consume rest of line;
    while (ch != '\n' && ch != EOF) {      // #5
      ch = fgetc(stdin);
    }
    if (ch == EOF) {                       // #6
      return NULL;
    }

    if (reprompt) {
      fputs(reprompt, stdout);
    }
  }
  return NULL;
}

不常见:读取null 字符仍然是一个待定问题。

作为学习者的 OP 的详细信息。

  1. 一些针对健全输入参数的测试。 零大小不允许保存为null 字符终止字符串的任何输入。 缓冲区可能大于INT_MAX ,但fgets()不能直接处理。 可以修改代码以处理 0 和巨大的缓冲区,但将其留到另一天。

  2. fgets()并不总是读取'\n' 缓冲区可能会先满,或者文件结尾之前的最后一行可能缺少'\n' 不常见的是,可能会读取null 字符- 甚至是第一个字符,因此len > 0测试,导致strlen()不足以确定读取的字符长度。 如果null 字符输入需要详细支持,则代码需要进行重大更改以适应确定大小。

  3. feof(stdin)如果之前的fgets()读取了一些东西,但是文件结束发生了,那么很高兴回到这里。

  4. 如果之前的fgets()填满了它的缓冲区,并且下一次读取字符尝试导致文件结束或'\n' ,则此测试为真并且正常,因此返回成功。

  5. 如果先前的fgetc()导致输入错误,则此循环立即退出。 否则,我们需要使用 rest 来查找'\n'EOF (这可能是由于文件结束或输入错误。)

  6. 如果返回EOF (由于文件结尾或输入错误),则没有理由继续。 返回NULL

用法

// fgets(arr[i],25,stdin);
if (getsizedline(arr[i], sizeof(arr[i]), "Too long, try again.\n") == NULL) {
  break;
}

此代码使用的缓冲区略大于所需的最大长度。 如果无法将文本行和换行符读入缓冲区,则读取该行的 rest 并将其丢弃。 如果可以,它会在太长(或太短)时再次丢弃。

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

#define INPUTS  10
#define STRMAX  25

int main(void) {
    char arr[INPUTS][STRMAX+1];
    char buf[STRMAX+4];
    for(int i = 0; i < INPUTS; i++) {
        bool success = false;
        while(!success) {
            printf("Enter string %d: ", i + 1);
            if(fgets(buf, sizeof buf, stdin) == NULL) {
                exit(1);                    // or sth better
            }

            size_t index = strcspn(buf, "\n");
            if(buf[index] == '\0') {        // no newline found
                // keep reading until end of line
                while(fgets(buf, sizeof buf, stdin) != NULL) {
                    if(strchr(buf, '\n') != NULL) {
                        break;
                    }
                }
                if(feof(stdin)) {
                    exit(1);                // or sth better
                }
                continue;
            }

            if(index < 1 || index > STRMAX) {
                continue;                   // string is empty or too long
            }

            buf[index] = '\0';              // truncate newline
            strcpy(arr[i], buf);            // keep this OK string
            success = true;
        }
    }
    
    printf("Results:\n");
    for(int i = 0; i < INPUTS; i++) {
        printf("%s\n", arr[i]);
    }
    return 0;
}

fgets()的好处是它会将换行符( '\n' )放在输入缓冲区中。 您所要做的就是寻找它。 如果它在那里,你就会得到一整行输入。 如果没有,还有更多内容需要阅读。

那么策略是:

fgets( s, size_of_s, stdin );
char * p = strpbrk( s, "\r\n" );
if (p)
{
  // end of line was found.
  *p = '\0';
  return s; (the complete line of input)
}

如果pNULL ,那么还有更多工作要做。 由于您希望简单地忽略太长的行,这与丢弃输入相同。 用一个简单的循环来做到这一点:

int c;
do c = getchar(); while ((c != EOF) && (c != '\n'));

流通常在幕后缓冲,由 C 库或操作系统(或两者)缓冲,但即使它们不是,这也不是太大的开销。 (在播放“我是一个优化编译器”之前使用分析器。不要假设 C 库有坏处。)

一旦你扔掉了所有你不想要的东西(到 EOL),确保你的输入不在 EOF 并循环要求用户再试一次。

把它们放在一起

char * prompt( const char * message, char * s, size_t n )
{
  while (!feof( stdin ))
  {
    // Ask for input
    printf( "%s", message );
    fflush( stdout );  // This line _may_ be necessary.

    // Attempt to get an entire line of input
    if (!fgets( s, n, stdin )) break;
    char * p = strpbrk( s, "\r\n" );

    // Success: return that line (sans newline character(s)) to the user
    if (p)
    {
      *p = '\0';
      return s;
    }

    // Failure: discard the remainder of the line before trying again
    int c;
    do c = getchar(); while ((c != EOF) && (c != '\n'));
  }

  // If we get this far it is because we have 
  // reached EOF or some other input error occurred.
  return NULL;
}

现在您可以轻松地使用此实用程序 function:

char user_name[20];  // artificially small

if (!prompt( "What is your name (maximum 19 characters)? ", user_name, sizeof(user_name) )) 
{
  complain_and_quit(); 
  // ...because input is dead in a way you likely cannot fix.
  // Feel free to check ferror(stdin) and feof(stdin) for more info.
}

这个小prompt function 只是您可以编写的各种帮助实用程序函数的示例。 你可以做一些事情,比如当用户不服从你的时候有一个额外的提示:

你叫什么名字? 约翰·雅各布·金勒海默·施密特
唉,我被限制在 19 个字符之内。 请再试一次:
你叫什么名字? 约翰施密特
你好约翰施密特。

暂无
暂无

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

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