是否有任何函数可以从标准输入中获取无限的输入字符串

Posted

技术标签:

【中文标题】是否有任何函数可以从标准输入中获取无限的输入字符串【英文标题】:Is there any function to get an unlimited input string from standard input 【发布时间】:2015-02-12 12:11:24 【问题描述】:

条件是:

我想从标准输入中输入一行,我不知道它的大小,可能很长。

scanfgets这样的方法需要知道您可以输入的最大长度,以便您的输入大小小于缓冲区大小。

那么有什么好的方法来处理呢?

答案只能是C,不是C++,所以c++字符串不是我想要的。我想要的是 C 标准字符串,类似于 char* 并以 '\0' 结尾。

【问题讨论】:

MAYBE 有什么东西可以根据你在 C 中的输入大小自动分配内存吗? 这个功能很少有用。对于处理无限制输入的代码,更常见的是,一些输入发生,即被处理,然后是更多输入。等等。通过真实的用户输入,例如人名、电话号码或书名,是的,肯定有 100 个 char 长的名称/标题和数十位数字的电话号码。但是允许无限制的输入会邀请黑客用十亿长的名称/标题等来压倒系统。允许异常的,甚至是病态的长输入要好得多,但不是无限制的。 fgets(user_name, 1000, stdin) 就足够了。 gets 不允许您指定目标数组的大小。这就是它本质上不安全的原因,这就是为什么它从 2011 ISO C 标准的语言中删除。你在想fgets吗? 读取未知数量数据的方式很大程度上取决于读取器如何处理数据。您可能想提供任何详细信息吗? 【参考方案1】:

使用getcharmallocrealloc 读取无限输入字符串

声明String类型,也可以使用char *

// String type
typedef char *String;

我写了这个函数来加入字符串末尾的字符

/**
 * Join the Char into end of String
 *
 * @param string - String
 * @param c - joined char
 */
void String_joinChar(String *string, const char c)

  const size_t length = strlen(*string);
  (*string) = (String)realloc((*string), sizeof(char) * (length + 2));
  (*string)[length] = c;
  (*string)[length + 1] = '\0';

此函数用于输入字符串,它使用getchar从键盘读取字符并将其加入当前字符串的末尾。

/**
 * Input String
 *
 * @return Inputed String
 */
String String_input()

  String string = (String)malloc(sizeof(char));
  strcpy(string, "");

  char cursor;
  fflush(stdin);
  while ((cursor = getchar()) != '\n' && cursor != EOF)
  
    String_joinChar(&string, cursor);
  

  return string;

使用char *mallocrealloc的原因,我们必须释放它

/**
 * Destroy String
 *
 * @param string - Destroyed String
 */
void String_destroy(String string)

  free(string);

现在我们就用它!!

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

int main()

  String string = String_input();
  printf("\n%s\n", string);
  String_destroy(string);
  return 0;

希望对你有用!

【讨论】:

从实际的角度来看,将大小为 X 的数组重新分配为大小 X + 2 是无效的 - 您将在每一秒输入 char 上重新分配整个数组。最好重新分配到 X * 2 的大小。这样您将达到恒定的摊销渐近时间复杂度,而不是插入操作到动态数组的线性复杂度。 @Fanick 你是对的,如果是这样,那么它将达到恒定摊销渐近时间复杂度,但如果输入序列由无穷大字符组成,它将随着时间的推移达到所谓的内存消耗。无穷大 * 2 = 超无穷大 :)) 哈哈哈【参考方案2】:

其中一种方法是使用 getchar() 函数,我们可以获取字符中的输入并将其传输到动态创建的数组中。可以看到,当超过我们设置的默认长度时,我们重新分配了存储字符的空间

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

void main()
    int size = 10;
    char* str;
    str = (char*) calloc(size,sizeof(char));
    char c;
    c = getchar();
    int t = 0;
    int cnt = 0;
    int len;

    while(c!='\n') 
        if(cnt > size) 
            str = (char*) realloc(str,2*cnt);
        

        str[t] = c;
        c = getchar();
        t++;
        cnt++;
    
        str[t]='\0';
    printf("The string is %s\n",str);
    len = strlen(str);
    printf("The size is %d",len);

【讨论】:

【参考方案3】:

scanf 中有一个经常被忽视的conversion specification,它将分配足够的内存来保存字符串输入,而不管长度如何。较新版本的scanf 使用m 用于此目的。 旧版本使用a。例如:

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

int main (void) 
    char *str = NULL;
    printf (" enter a string of any length, whitespace is OK: ");
    scanf ("%m[^\n]%*c", &str);
    printf ("\n str: %s\n\n", str);
    if (str) free (str);
    return 0;

注意: scanf 需要 char ** 指针参数来接收分配的字符串。另外 note scanf 不包括'\n' 存储的字符串。进一步注意%*c 接收并丢弃'\n' 字符以防止换行符保留在输入缓冲区中。您也可以在转换说明符之前加上空格,以跳过输入缓冲区中可能存在的任何/所有空格。

最后注意:有报道称并非所有scanf 的实现都提供此功能。 (这也可能与 m/a 更改混淆)检查您的实施。

【讨论】:

'm' 的这种用法由 POSIX 定义,而不是由 ISO C 定义。 正确,在'm' 之前是'a',因此您必须查看手册页 以了解您的scanf 版本——好点。 @NehalSamee 你用的是什么编译器? 嗯...是的...但是在 Windows 上使用 MinGW 或 Cgywin 作为编译器。或者在 Linux 上使用 gcc 或 clang。我不相信 MinGW 版本支持它。如果你安装了 C::B 和编译器,那么它很可能是 TDM-MinGW,好的编译器,但对 m 修饰符的支持值得怀疑。 其实我刚刚查了一下,TDM-MinGW不支持'm' modier。【参考方案4】:

一种方法是使用getchar 运行一个循环并继续将字符放入一个数组中。一旦数组已满,realloc将其吃到更大的大小。

【讨论】:

酷!是否有任何 C 库函数实现它? @youKnowDai 兄弟是C,你必须自己做这一切并创建库。 标准 C 中没有函数 getch()。您的意思可能是 getc()getchar() 是的,我的意思是 getchar,只是修复了它。感谢您指出这一点!【参考方案5】:

C 标准没有定义这样的函数,但 POSIX 有。

getline 函数 documented here(或者如果您使用的是类 UNIX 系统,则输入 man getline)可以满足您的要求。

它可能不适用于非 POSIX 系统(例如 MS Windows)。

一个演示其用法的小程序:

#include <stdio.h>
#include <stdlib.h>
int main(void) 
    char *line = NULL;
    size_t n = 0;
    ssize_t result = getline(&line, &n, stdin);
    printf("result = %zd, n = %zu, line = \"%s\"\n", result, n, line);
    free(line);

fgets 一样,'\n' 换行符留在数组中。

【讨论】:

以上是关于是否有任何函数可以从标准输入中获取无限的输入字符串的主要内容,如果未能解决你的问题,请参考以下文章

使用 cin::fail() 从标准输入进行无限循环读取

C语言试题184之编写一个函数,从标准输入读取一个字符串,把字符串复制到动态内存分配的内存中,并返回该字符串的拷贝,这个函数不应该对读入字符串的长度作任何限制

C语言试题184之编写一个函数,从标准输入读取一个字符串,把字符串复制到动态内存分配的内存中,并返回该字符串的拷贝,这个函数不应该对读入字符串的长度作任何限制

golang碎片整理之 fmt.Scan

VS2015提示gets未定义

为啥使用 getline 从标准输入获取大量输入会截断我的输入?