【问题标题】:Using char arrays with scanf in C在 C 中使用带有 scanf 的 char 数组
【发布时间】:2017-12-03 11:41:29
【问题描述】:

我想编写一个程序,询问用户一些输入值并根据输入值给出结果。以下代码有效,但是当我输入“John”时,100 个内存中只使用了 4 个空格。其他96个被浪费了。此外,不能保证输入将小于 100 个字符(非常不可能但可能)。有没有办法优化这个?

P.S:当我研究它时,一些网站说我应该使用 sscanf() 或 fgets() 但我不明白如何在我的代码中使用它们。

P.P.S : 我对 C 很陌生,所以请告诉我最简单的方法。

#include <stdio.h>
int main()
{
     char name[100];
     printf("Your name: \n");
     scanf("%100s", name);
     printf("Name: %s  \n", name);

    return 0;
}

【问题讨论】:

  • 我看到了那个讨论,但我不明白第一个答案是什么意思。看起来有点复杂。
  • 简而言之,上面链接的答案读取用户输入一次一个字符,并为输入缓冲区使用动态内存分配,一次多分配 16 个字节随着输入字符数的增加,需要。如果您花时间逐行​​研究该答案并查找文档和所涉及函数的使用,您将学到一些关于 C 编程的知识。
  • scanf("%100s", name);--注意这应该是scanf("%99s", name);以避免缓冲区溢出。 \0 字符在使用%s 时由scanf() 自动写入;指定的最大宽度是输入项的最大长度,不包括空终止符。

标签: c arrays char scanf


【解决方案1】:

不,没有办法。您必须确保有足够的内存随时保存用户的数据。也许在某些时候用户会尝试写 100 个字符。在这种情况下,您需要内存中可用的 101 字节用于尾随零。

如果您使用sscanfgets,您仍然需要内存来保存您的字符串,并且在这两种情况下您都不知道可以从输入中获得多少字节。

以下代码有效,但是当我输入“John”时,100 个内存中只使用了 4 个空格。其他 96 个都被浪费了。

不,其他 95 个都被浪费了,你错过了尾随零。


如果你想做低效的代码,那么你可以为每个接收到的字符realloc内存,但是你必须使用getchar函数从输入中逐个字符地读取。


进一步阅读

How can I read an input string of unknown length?

【讨论】:

    【解决方案2】:

    此操作需要重新分配内存(程序运行时内存会改变)

    char *name = 0;
    char *tmp = 0;
    int inputAsingleChar,i=0,j=4;
    printf("Your name: \n");
    while((inputAsingleChar = getchar()) != '\n' && inputAsingleChar != EOF)
    {
        if(i==j){
            j+=4;
            tmp = realloc(name, j);
            if(tmp== NULL){printf("Couldn't realloc but the 'name' array is still valid");}
            else{name = tmp;}
        }
        name[i++] = inputAsingleChar ;
    }
    name[i] = '\0';
    printf("Name: %s  \n", name);
    free(name);
    free(tmp);
    

    在慷慨的 David Bowling 的帮助下,第 2 版(最终版)

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
        int inputAsingleChar,i=0,j=4;
        char *name = malloc(j);
        if (name == NULL){
            printf("No memory");
            exit(1);
        }
        printf("Your name: \n");
        while((inputAsingleChar = getchar()) != '\n' && inputAsingleChar != EOF)
        {
            if(i==j){
                j+=4;
                char * tmp = realloc(name, j);
                if(tmp== NULL){printf("Couldn't realloc but the 'name' array is still valid");}
                else{name = tmp;}
            }
            name[i++] = inputAsingleChar ;
        }
        name[i] = '\0';
        printf("Name: %s  \n", name);
        free(name);
        return 0;
    }
    

    也在这里直播http://ideone.com/cDxkDV

    【讨论】:

    • 这是非常低效的,但它确实有效。顺便说一句,这里的c 是什么?
    • @tilz0R 至少以后不会浪费资源。如果 Harold 想让该输入成为用户名,他可以简单地使用一个 16 字节的数组。但他不想浪费字节
    • 担心一个名称有 95 个字节没有多大意义。这在存储许多名称时可能很重要;那么最好使用一个大的缓冲区并复制到自定义分配的内存,或者使用 realloc() 将分配调整为大小。 IAC,这个答案非常低效,有这么多不必要的分配。为什么malloc 开始时有 4 个字符,而您在第一次循环迭代中只是 realloc() 到 2?此外,还有一个潜在的内存泄漏:name = realloc(name, i+1);。没有理由在接受的答案中使用这种不良做法。
    • 嗯。现在有 UB,因为 name[i++] = inputAsingleChar; 发生在对 realloc() 的调用之前。抛开效率不谈,(最好通过定期加倍将内存从合理大小增长到所需大小),我的主要抱怨是将realloc() 的结果直接分配给指向重新分配对象的指针。 realloc() 可能会返回一个空指针,然后失去对先前分配的访问权限,从而导致内存泄漏和数据丢失。通过首先存储然后检查临时变量来简单地说明学习者的良好做法。
    • 有一些问题。 1) tmp 未声明。 2)tmp 不应该realloced 两次,而是重新分配,并且 freed,因为这会解除最近的重新分配。 3) 需要在分配name[i++] = ... 之前进行一些分配。 4) sizeof(name) 给出指针的大小,而不是数组。也有一些错别字;建议在发布前使用#includes 和main() 进行编译以进行测试。 Here is an Ideone link 代码的改进版本。我在这里使用了加倍,但你也可以使用j += 4; 来增长。
    【解决方案3】:

    如果您担心内存使用情况,请使用内存的动态分配,即使用malloc()realloc(),您可以获得某些行为,例如这样。

    int main() {

     char a;
    int i=0;
    char *str=0;
    while((a=getchar())!='\n')
    {
        str=realloc(str,i+2);   //1 for character to store, + 1 for '\0' terminating character
        str[i++]=a;      
    }
     str[i]='\0';
    printf("%s\n",str);
    return 0;
    

    } 当用户输入字符时,此代码会立即生成内存并存储结果。当用户按下Enter时,输入读取过程终止。

    此方法非常节省内存,但执行时间较长。因此,我们总是需要管理性能与内存之间的权衡。希望这会有所帮助。

    【讨论】:

    • 谢谢,它看起来可以帮助我节省一些空间。
    • 如果还有其他疑问可以提问。
    • @anil 你的意思是strlen(str) 而不是sizeof(str)?对指针执行 sizeof 总是返回相同的值。
    猜你喜欢
    • 2015-06-27
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    • 2015-11-26
    • 2015-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多