【问题标题】:Dynamically increase the dimension of an array of characters动态增加字符数组的维度
【发布时间】:2015-05-26 13:05:31
【问题描述】:

我在 C 语言中有这个函数,我在我的项目中使用它来读取输入中的字符:

char* readStringInp()
{
    char* string=NULL,c=NULL;
    int i=0;

    string=(char *)malloc(sizeof(char)*LGTH_STRING_INPUT);

    for(i=0;i<LGTH_STRING_INPUT && ( (c=getchar()) != '\n' && c != EOF );i++)
        string[i]=c;

    string[i]='\0';

    return string;
}

LGTH_STRING_INPUT 是一个数字常量,表示可以读取的字符串的最大长度。 读取没有固定长度的字符串的最佳方法是什么?

【问题讨论】:

  • 请格式化和缩进你的代码,然后谷歌realloc
  • 在 ANSI C 中,强制转换 malloc() (或 calloc() 或 realloc() )的返回值是不正确的。
  • 还应该定义cint,至少能够成功检测到EOFgetchar() 返回int,顺便说一句。
  • 您的代码导致缓冲区溢出。当您 malloc N 字节时,有效索引为 0N-1。但是你继续在最后设置string[N]

标签: c string input


【解决方案1】:

这会为 20 个字符分配内存。当使用了 18 个字符时,再分配 20 个字符由 realloc 分配。随着字符串的增长,将分配 20 个字符的额外增量。如果 realloc 失败,则返回当前字符串。当找到换行符或 EOF 时,while 循环终止。
分配的内存应该由调用函数释放。
EDIT 添加了 main() 以显示分配的内存的释放

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

char* readStringInp();

int main()
{
    char *s=readStringInp();
    if ( s != NULL)
    {
        printf ( "%s\n", s);
        free ( s);
    }
    return 0;
}

char* readStringInp()
{
    char* string=NULL, *temp = NULL;
    int c=0, available=20, used=0, increment=20;

    string=malloc(available);
    if ( string == NULL)
    {
        printf ( "malloc failed\n");
        return NULL;
    }

    while( (c=getchar()) != '\n' && c != EOF )
    {
        if ( used == available - 2)
        {
             available += increment;
             temp = realloc ( string, available);
             if ( temp == NULL)
             {
                 printf ( "realloc failed\n");
                 return string;
             }
             string = temp;
        }
        string[used]=c;
        used++;
        string[used]='\0';
    }
    return string;
}

【讨论】:

  • 一旦不再需要内存,您在哪里处理释放内存?调用函数无法释放字符串,因为它是该函数的本地字符串。
  • 这个解决方案就像一个魅力,这是我真正需要的,非常感谢:)
  • @RichardTemp - 如果您喜欢答案,请点击它。 (每个答案左上角的小箭头)如果它回答了您的问题,请单击空心复选标记。
  • @ryyker 我知道,但我需要声望 15 才能投票:/
  • @RichardTemp - 哎呀。忘了那个小细节。奇怪的是,该网站限制某人点击他们自己问题之一的答案,无论他们的代表如何,你不觉得吗?
【解决方案2】:

读取没有固定长度的字符串的最佳方法是什么?

正如您在代码中已经完成的那样,使用malloc()动态分配内存并继续读取字符直到达到标记条件并继续增加使用realloc()在同一指针上分配的内存,除非您有空间容纳所有字符.

Don't cast malloc and family

【讨论】:

    【解决方案3】:

    calloc()(您已经在使用)和 realloc() 的组合将是用于动态调整缓冲区大小以适应不同长度的用户输入。
    但是,现有存在几个问题 在继续使用该组合之前应解决的示例代码:请参阅下面的建议和 cmets:

    正如所写,您现有的代码会泄漏内存,因为您从不调用 free()。 此外,您将在string 中获得缓冲区溢出。 (见下文解释)

    这里有一些更正可以让您的示例代码正常工作:(参见 cmets)

    #define LGTH_STRING_INPUT 20
    
    //have written function to accept argument, easier to free memory
    char* readStringInp(char *string){
    
        //char* string=NULL,c=NULL;//done in main
        int c; //getchar() requires int to detect EOF (-1)
        int i=0;
    
        //string=malloc(LGTH_STRING_INPUT);  //do not cast return value of calloc
    
        //   max length allow should be LGTH_STRING_INPUT - 1 
        //   to allow room for NULL after loop 
        for(i=0;i<LGTH_STRING_INPUT-1 && ( (c=getchar()) != '\n' && c != EOF );i++)
        {
            string[i]=c;
        }
    
        string[i]='\0';
    
        return string;
    }
    
    int main(void)
    {
        char *buf = {0};
        char bufIn[LGTH_STRING_INPUT];
    
        //allocated and free memory in calling function:
        buf = malloc(LGTH_STRING_INPUT);
        if(buf)//check return of malloc
        {
            sprintf(bufIn, "%s", readStringInp(buf)); //use return value in buffer
            free (buf);//free memory that has been created
        }
        return 0;
    }
    

    【讨论】:

    • 感谢这个解决方案,但实际上我更喜欢第一个,也是因为我不想使用 sprintf 。谢谢:D
    • @RichardTemp - 感谢您的评论。为了演示,sprintf() 的使用完全是任意的。您可以使用任何字符串函数来获取函数的结果并将其放入缓冲区。 strcpy()strcat() 是两个可能对您有用的示例。无论如何,这个答案的重点是三个方面:1)指出malloc()的正确用法,2)应该进行内存清理,3)帮助你找到一种在这样的情况下编写函数的方法允许轻松清理内存的方式。
    • 好的。只是说,我在程序的其他地方使用了 free ,这就是为什么我没有在我的错误代码中编写它。但是我不知道以这种方式使用的强制转换会产生所有这些麻烦。
    • @RichardTemp - 在这种特殊情况下,演员阵容在这里不太可能给您带来任何麻烦。这对 ANSI C 来说不是必需的,并且 可能 导致问题。这是我提到它的唯一原因。
    猜你喜欢
    • 2019-01-06
    • 2019-12-19
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    相关资源
    最近更新 更多