76

如果我不知道这个词有多长,我就不会写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 的字符串
输入:你好
这是字符串:你好

4

10 回答 10

108

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

例如

#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;
}
于 2013-06-01T10:28:05.103 回答
20

使用当今的计算机,您可以避免分配非常大的字符串(数十万个字符),而几乎不会影响计算机的 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 例程的最后,不会浪费任何字节;该字符串具有所需的确切内存大小。

于 2013-06-01T10:42:38.587 回答
12

I've seen only one simple way of reading an arbitrarily long string, but I've never used it. I think it goes like this:

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);
}

The m between % and s tells scanf() to measure the string and allocate memory for it and copy the string into that, and to store the address of that allocated memory in the corresponding argument. Once you're done with it you have to free() it.

This isn't supported on every implementation of scanf(), though.

As others have pointed out, the easiest solution is to set a limit on the length of the input. If you still want to use scanf() then you can do so this way:

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

Note that the size of m[] must be at least one byte larger than the number between % and s.

If the string entered is longer than 99, then the remaining characters will wait to be read by another call or by the rest of the format string passed to scanf().

Generally scanf() is not recommended for handling user input. It's best applied to basic structured text files that were created by another application. Even then, you must be aware that the input might not be formatted as you expect, as somebody might have interfered with it to try to break your program.

于 2013-06-01T12:07:20.413 回答
7

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;
}
于 2020-05-28T17:19:08.790 回答
5

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

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

char user_input[255];

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

fgets(user_input, 255, stdin);

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

安全性尤其来自第二个参数,它限制了读取的数量,从而防止缓冲区溢出。此外,还fgets负责处理的字符串以空值结尾。

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

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

于 2013-06-01T08:25:37.547 回答
3

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

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);
}
于 2014-05-01T08:52:12.500 回答
1

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

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

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

于 2013-06-01T09:08:47.437 回答
1

使用 直接读入分配的空间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;
}
于 2015-12-06T22:43:34.893 回答
1

我知道我在 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
于 2017-10-16T17:13:33.533 回答
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);
}
于 2018-01-12T11:49:44.343 回答