【问题标题】:Better ways to get a string from user从用户那里获取字符串的更好方法
【发布时间】:2020-02-20 13:41:47
【问题描述】:

我想从用户那里得到一个字符串(其实我是想控制长度,但是没办法),然后输出。我尝试了一种可行的方法(但我认为这不是一个好的解决方案,因为它很容易溢出或占用太多内存。任何人都可以提供更好的方法来做到这一点?

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

int main(){
  char p[1024];   //there if i use 'char *p=(char*)malloc(sizeof(char)*1024)' error too.
  int i=0;
  fgets(p,1024,stdin); //there if i use 'scanf("%s",p)', wrong.
  while(p[i]!='\0'&&i<1024){
    printf("%c",p[i]);
    i++;
  }
  return 0;
}

谁能提供更好的方法来解释我的错误? 提前致谢。

【问题讨论】:

  • 请缩进您的代码。 fgets 有什么问题?什么不起作用?您得到的输出与您期望的输出有何不同?你可以edit你的问题。另请阅读:How to Ask
  • 对我来说很好。似乎是什么问题?
  • 函数fgets()如果你传递了正确的长度就不能溢出缓冲区,但是它可以截断输入。如果输入字符串包含换行符\n,那么它不会被截断。否则,如果字符串长度 + 终止符小于缓冲区大小,则不会被截断,但没有换行符(例如文件中的最后一行)。否则还有更多要读的。如果动态分配缓冲区,在这种情况下可以扩展,fgets() 在前一个字符串终止符的位置重复。这可以循环完成,直到输入完成。
  • ...请注意,您不需要检查i&lt;1024,因为fgets() 保证提供您检查的字符串终止符。

标签: c pointers char scanf fgets


【解决方案1】:

我想控制长度,但是没办法

确实,代码无法通过魔术臂接触到用户并限制用户打字,但代码可以(并且应该 IMO)将输入 保存 限制在一定数量,比如 @ 987654321@ 阅读名称。

超出理智的输入最好被视为攻击而不是有效的极端。此类输入不需要完整保存,只需检测和处理即可。

使用fgets()

int main(void) {
  char p[1024];
  if (fgets(p, sizeof p,stdin) == NULL) {
    puts("Input closed");
    return -1;
  }
  size_t len = strlen(p);
  if (len > 0 && p[len - 1] == '\n') {  // lop off potential \n
    p[--len] = '\0';
  }
  if (len + 1 == sizeof p) {  // too long a line
    int ch;
    while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
      ; // consume rest of line
    }
    printf("Input too long, first part <%s>\n", p);
    return -1;
  }
  printf("Input OK <%s>\n", p);
  return 0;
}

【讨论】:

    【解决方案2】:

    如果我理解正确,您想读取字符串而不需要硬编码大小。 fgets 不可能做到这一点。你给它一个硬编码的大小,希望输入适合,如果输入不适合,它会被截断。

    如果您的编译器与 POSIX 兼容,您可以使用 new(er) getline:

    #include <stdio.h>
    #include <stdlib.h>
    int main() {
        char *p = NULL;
        size_t size = 0;
        getline(&p, &size, stdin);
        for (int i = 0; p[i] != '\0' &&i < size; i++)
            printf("%c", p[i]);
        free(p);
        printf("size %zu",size);
        return 0;
    }
    

    这样您就不必担心缓冲区的大小。 getline 负责处理。完成后只需free 内存即可。

    【讨论】:

    • 请注意,getline() 是 gcc 扩展,而不是标准 C 的一部分。
    • 非常感谢,但 'getline' 不是通用解决方案,它在我的编译器中无法工作。
    • @WeatherVane getline() 不是 gcc 扩展。 getline() is standard POSIX
    • @AndrewHenle 谢谢,但 C18 标准中没有提到 getline(),POSIX 在其参考书目部分中得到了提及。
    • @WeatherVane 根据this,它最初是一个 GNU 扩展,然后在 POSIX.1-2008 中被标准化。
    猜你喜欢
    • 2014-11-20
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 2019-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多