繁体   English   中英

如何读取未知长度的输入字符串?

[英]How can I read an input string of unknown length?

如果我不知道这个词有多长,我就不能写char m[6]; ,
单词的长度可能是十或二十长。 如何使用scanf从键盘获取输入?

#include <stdio.h>
int main(void)
{
    char  m[6];
    printf("please input a string with length=5\n");
    scanf("%s",&m);
    printf("this is the string: %s\n", m);
    return 0;
}

请输入一个长度为5的字符串
输入:你好
这是字符串:你好

在动态确保区域的同时进入

例如

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

char *inputString(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
    char *str;
    int ch;
    size_t len = 0;
    str = realloc(NULL, sizeof(*str)*size);//size is start size
    if(!str)return str;
    while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
        str[len++]=ch;
        if(len==size){
            str = realloc(str, sizeof(*str)*(size+=16));
            if(!str)return str;
        }
    }
    str[len++]='\0';

    return realloc(str, sizeof(*str)*len);
}

int main(void){
    char *m;

    printf("input string : ");
    m = inputString(stdin, 10);
    printf("%s\n", m);

    free(m);
    return 0;
}

使用当今的计算机,您可以避免分配非常大的字符串(数十万个字符),同时几乎不会影响计算机的 RAM 使用量。 所以我不会太担心。

然而,在过去,当内存非常宝贵时,通常的做法是分块读取字符串。 fgets从输入中读取最大数量的字符,但保留输入缓冲区的其余部分不变,因此您可以随意读取其余部分。

在这个例子中,我读取了 200 个字符的块,但是你当然可以使用任何你想要的块大小。

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

char* readinput()
{
#define CHUNK 200
   char* input = NULL;
   char tempbuf[CHUNK];
   size_t inputlen = 0, templen = 0;
   do {
       fgets(tempbuf, CHUNK, stdin);
       templen = strlen(tempbuf);
       input = realloc(input, inputlen+templen+1);
       strcpy(input+inputlen, tempbuf);
       inputlen += templen;
    } while (templen==CHUNK-1 && tempbuf[CHUNK-2]!='\n');
    return input;
}

int main()
{
    char* result = readinput();
    printf("And the result is [%s]\n", result);
    free(result);
    return 0;
}

请注意,这是一个没有错误检查的简化示例; 在现实生活中,您必须通过验证fgets的返回值来确保输入正确。

还要注意,最后如果是 readinput 例程,没有字节被浪费; 该字符串具有它需要的确切内存大小。

我只见过一种读取任意长字符串的简单方法,但我从未使用过它。 我认为它是这样的:

char *m = NULL;
printf("please input a string\n");
scanf("%ms",&m);
if (m == NULL)
    fprintf(stderr, "That string was too long!\n");
else
{
    printf("this is the string %s\n",m);
    /* ... any other use of m */
    free(m);
}

%s之间的m告诉scanf()测量字符串并为其分配内存并将字符串复制到该字符串中,并将该分配的内存的地址存储在相应的参数中。 一旦你完成了它,你必须free()它。

但是,并非每个scanf()实现都支持此功能。

正如其他人指出的那样,最简单的解决方案是设置输入长度的限制。 如果您仍然想使用scanf()那么您可以这样做:

char m[100];
scanf("%99s",&m);

请注意, m[]的大小必须至少比%s之间的数字大一个字节。

如果输入的字符串长于 99,则剩余的字符将等待被另一个调用或传递给scanf()的格式字符串的其余部分读取。

通常不推荐使用scanf()来处理用户输入。 它最适用于由另一个应用程序创建的基本结构化文本文件。 即便如此,您也必须意识到输入的格式可能不是您所期望的,因为有人可能会干扰它以试图破坏您的程序。

C 标准中有一个新函数可以在不指定大小的情况下获取一行。 getline函数会自动分配所需大小的字符串,因此无需猜测字符串的大小。 以下代码演示了用法:

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


int main(void)
{
    char *line = NULL;
    size_t len = 0;
    ssize_t read;

    while ((read = getline(&line, &len, stdin)) != -1) {
        printf("Retrieved line of length %zu :\n", read);
        printf("%s", line);
    }

    if (ferror(stdin)) {
        /* handle error */
    }

    free(line);
    return 0;
}

如果我可以建议一种更安全的方法:

声明一个足够大的缓冲区来保存字符串:

char user_input[255];

安全的方式获取用户输入:

fgets(user_input, 255, stdin);

获取输入的安全方法,第一个参数是指向将存储输入的缓冲区的指针,第二个是函数应该读取的最大输入,第三个是指向标准输入的指针 - 即用户输入的位置从。

特别是安全性来自第二个参数,限制将读取的数量,以防止缓冲区溢出。 此外, fgets负责以空值终止处理后的字符串。

有关该功能的更多信息,请点击此处

编辑:如果您需要进行任何格式化(例如将字符串转换为数字),您可以在输入后使用atoi

更安全更快(容量翻倍)版本:

char *readline(char *prompt) {
  size_t size = 80;
  char *str = malloc(sizeof(char) * size);
  int c;
  size_t len = 0;
  printf("%s", prompt);
  while (EOF != (c = getchar()) && c != '\r' && c != '\n') {
    str[len++] = c;
    if(len == size) str = realloc(str, sizeof(char) * (size *= 2));
  }
  str[len++]='\0';
  return realloc(str, sizeof(char) * len);
}

取一个字符指针来存储所需的字符串。如果您对字符串的可能大小有所了解,请使用函数

char *fgets (char *str, int size, FILE* file);`

否则,您也可以使用动态提供请求的内存的malloc()函数在运行时分配内存。

我知道我是在 4 年后到达的,但为时已晚,但我想我有另一种方式可供人们使用。 我曾经使用过这样的getchar()函数:-

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

//I had putten the main Function Bellow this function.
//d for asking string,f is pointer to the string pointer
void GetStr(char *d,char **f)
{
    printf("%s",d);

    for(int i =0;1;i++)
    {    
        if(i)//I.e if i!=0
            *f = (char*)realloc((*f),i+1);
        else
            *f = (char*)malloc(i+1);
        (*f)[i]=getchar();
        if((*f)[i] == '\n')
        {
            (*f)[i]= '\0';
            break;
        }
    }   
}

int main()
{
    char *s =NULL;
    GetStr("Enter the String:- ",&s);
    printf("Your String:- %s \nAnd It's length:- %lu\n",s,(strlen(s)));
    free(s);
}

这是该程序的示例运行:-

Enter the String:- I am Using Linux Mint XFCE 18.2 , eclispe CDT and GCC7.2 compiler!!
Your String:- I am Using Linux Mint XFCE 18.2 , eclispe CDT and GCC7.2 compiler!! 
And It's length:- 67

使用fgets()直接读入分配的空间。

需要特别注意区分成功读取、文件结束、输入错误和内存不足。 EOF 需要适当的内存管理。

此方法保留一行的'\\n'

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

#define FGETS_ALLOC_N 128

char* fgets_alloc(FILE *istream) {
  char* buf = NULL;
  size_t size = 0;
  size_t used = 0;
  do {
    size += FGETS_ALLOC_N;
    char *buf_new = realloc(buf, size);
    if (buf_new == NULL) {
      // Out-of-memory
      free(buf);
      return NULL;
    }
    buf = buf_new;
    if (fgets(&buf[used], (int) (size - used), istream) == NULL) {
      // feof or ferror
      if (used == 0 || ferror(istream)) {
        free(buf);
        buf = NULL;
      }
      return buf;
    }
    size_t length = strlen(&buf[used]);
    if (length + 1 != size - used) break;
    used += length;
  } while (buf[used - 1] != '\n');
  return buf;
}

示例用法

int main(void) {
  FILE *istream = stdin;
  char *s;
  while ((s = fgets_alloc(istream)) != NULL) {
    printf("'%s'", s);
    free(s);
    fflush(stdout);
  }
  if (ferror(istream)) {
    puts("Input error");
  } else if (feof(istream)) {
    puts("End of file");
  } else {
    puts("Out of memory");
  }
  return 0;
}

我也有一个标准输入和输出的解决方案

#include<stdio.h>
#include<malloc.h>
int main()
{
    char *str,ch;
    int size=10,len=0;
    str=realloc(NULL,sizeof(char)*size);
    if(!str)return str;
    while(EOF!=scanf("%c",&ch) && ch!="\n")
    {
        str[len++]=ch;
        if(len==size)
        {
            str = realloc(str,sizeof(char)*(size+=10));
            if(!str)return str;
        }
    }
    str[len++]='\0';
    printf("%s\n",str);
    free(str);
}

我有一个使用 C 标准库的解决方案,并且还像在 C++ 中一样创建了一个字符串类型(char* 的别名)

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

typedef char* string;

typedef struct __strstr {
    char ch;
    struct __strstr *next;
}Strstr;

void get_str(char **str) {
    char ch, *buffer, a;
    Strstr *new = NULL;
    Strstr *head = NULL, *tmp = NULL;
    int c = 0, k = 0;
    while ((ch = getchar()) != '\n') {
        new = malloc(sizeof(Strstr));
        if(new == NULL) {
            printf("\nError!\n");
            exit(1);
        }
        new->ch = ch;
        new->next = NULL;
        new->next = head;
        head = new;
    }

    tmp = head;
    while (tmp != NULL) {
        c++;
        tmp = tmp->next;
    }

    if(c == 0) {
        *str = "";
    } else {
        buffer = malloc(sizeof(char) * (c + 1));
        *str = malloc(sizeof(char) * (c + 1));
        if(buffer == NULL || *str == NULL) {
            printf("\nError!\n");
            exit(1);
        }
        tmp = head;
        while (tmp != NULL) {
            buffer[k] = tmp->ch;
            k++;
            tmp = tmp->next;
        }
        buffer[k] = '\0';
        for (int i = 0, j = strlen(buffer)-1; i < j; i++, j--) {
            a = buffer[i];
            buffer[i] = buffer[j];
            buffer[j] = a;
        }
        strcpy(*str, buffer);
        // Dealloc
        free(buffer);
        while (head != NULL) {
            tmp = head;
            head = head->next;
            free(tmp);
        }
    }
}

int main() {
    string str;

    printf("Enter text: ");
    get_str(&str);

    printf("%s\n", str);

    return 0;
}

暂无
暂无

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

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