【问题标题】:How to dynamically allocate memory space for a string and get that string from user?如何为字符串动态分配内存空间并从用户那里获取该字符串?
【发布时间】:2011-12-31 03:06:48
【问题描述】:

我想使用 C 程序读取用户的输入。我不想像这样使用数组,

char names[50];

因为如果用户给出长度为 10 的字符串,那么剩余的空间就被浪费了。

如果我使用字符指针,

char *names;

那么我需要为此分配内存,

names = (char *)malloc(20 * sizeof(char));

在这种情况下,也存在内存浪费的可能性。

所以,我需要的是为一个与字符串长度完全相同的字符串动态分配内存。

假设,

如果用户输入是"stackoverflow",那么分配的内存应该是14(即字符串的长度= 13和1个额外的空间'\0')。

我怎样才能做到这一点?

【问题讨论】:

  • 一些编译器提出了这些解决方案 char a[ ] 而不是称为动态数组!

标签: c string memory-management malloc dynamic


【解决方案1】:

一次读取一个字符(使用getc(stdin)),然后不断增加字符串(realloc)。

这是我前段时间写的一个函数。请注意,它仅用于文本输入。

char *getln()
{
    char *line = NULL, *tmp = NULL;
    size_t size = 0, index = 0;
    int ch = EOF;

    while (ch) {
        ch = getc(stdin);

        /* Check if we need to stop. */
        if (ch == EOF || ch == '\n')
            ch = 0;

        /* Check if we need to expand. */
        if (size <= index) {
            size += CHUNK;
            tmp = realloc(line, size);
            if (!tmp) {
                free(line);
                line = NULL;
                break;
            }
            line = tmp;
        }

        /* Actually store the thing. */
        line[index++] = ch;
    }

    return line;
}

【讨论】:

  • 除非您知道您的数据来自固定大小的记录,否则将大小增加一个倍数(即大小的 1.5 倍或两倍)通常会更有效。
  • getln() 不会在文件末尾返回NULL。如何检查文件结尾?
  • CHUNK 是分配多少字节。如果这样更清楚,你可以称之为CHUNKSIZE
【解决方案2】:

您可以有一个以 10 个元素开始的数组。逐个字符读取输入。如果它过去了,重新分配另外 5 个。不是最好的,但您可以稍后释放其他空间。

【讨论】:

  • vsnprintf的Linux手册中,这正是他们在他们的例子中所做的(虽然它是关于格式化字符串而不是输入,但原理是一样的。)
【解决方案3】:

如果您应该节省内存,请每次逐个读取字符并重新分配。性能会下降,但你会节省这 10 个字节。

另一个好的权衡是读入一个函数(使用局部变量)然后复制。所以大缓冲区将是函数作用域。

【讨论】:

    【解决方案4】:

    您还可以使用正则表达式,例如以下代码:

    char *names
    scanf("%m[^\n]", &names)
    

    将从标准输入获取整行,动态分配所需的空间量。在那之后,当然,你必须释放names

    【讨论】:

    • m scanf 修饰符是非标准的。您的 C 库可能支持也可能不支持。
    【解决方案5】:

    下面是创建动态字符串的代码:

    void main()
    {
      char *str, c;
      int i = 0, j = 1;
    
      str = (char*)malloc(sizeof(char));
    
      printf("Enter String : ");
    
      while (c != '\n') {
        // read the input from keyboard standard input
        c = getc(stdin);
    
        // re-allocate (resize) memory for character read to be stored
        str = (char*)realloc(str, j * sizeof(char));
    
        // store read character by making pointer point to c
        str[i] = c;
    
        i++;
        j++;
      }
    
      str[i] = '\0'; // at the end append null character to mark end of string
    
      printf("\nThe entered string is : %s", str);
    
      free(str); // important step the pointer declared must be made free
    }
    

    【讨论】:

    • 未定义的行为,因为 c 未针对空输入文件的首次测试、无限循环和最终崩溃进行初始化。
    • 另外,free(c)呢?也应该是必要的imo!
    【解决方案6】:

    首先,定义一个新函数来读取输入(根据您输入的结构)并存储字符串,这意味着使用的堆栈中的内存。将字符串的长度设置为足以满足您的输入。

    其次,使用strlen测量之前存储的字符串的确切使用长度,使用malloc在堆中分配内存,其长度由strlen定义。代码如下所示。

    int strLength = strlen(strInStack);
    if (strLength == 0) {
        printf("\"strInStack\" is empty.\n");
    }
    else {
        char *strInHeap = (char *)malloc((strLength+1) * sizeof(char));
        strcpy(strInHeap, strInStack);
    }
    return strInHeap;
    

    最后,使用strcpystrInStack的值复制到strInHeap,并返回指向strInHeap的指针。 strInStack 会被自动释放,因为它只在这个子函数中退出。

    【讨论】:

      【解决方案7】:

      这是我编写的一个函数 sn-p,用于扫描用户输入的字符串,然后将该字符串存储在与用户输入大小相同的数组中。请注意,我将 j 初始化为 2 的值,以便能够存储 '\0' 字符。

      char* dynamicstring() {
          char *str = NULL;
          int i = 0, j = 2, c;
          str = (char*)malloc(sizeof(char));
          //error checking
          if (str == NULL) {
              printf("Error allocating memory\n");
              exit(EXIT_FAILURE);
          }
      
          while((c = getc(stdin)) && c != '\n')
          {
              str[i] = c;
              str = realloc(str,j*sizeof(char));
              //error checking
              if (str == NULL) {
                  printf("Error allocating memory\n");
                  free(str);
                  exit(EXIT_FAILURE);
              }
      
              i++;
              j++;
          }
          str[i] = '\0';
          return str;
      }
      

      在 main() 中,您可以声明另一个 char* 变量来存储 dynamicstring() 的返回值,然后在使用完毕后释放该 char* 变量。

      【讨论】:

        【解决方案8】:

        这是我编写的一个 sn-p,它执行相同的功能。

        这段代码和Kunal Wadhwa写的类似。

        char *dynamicCharString()
        {
            char *str, c;
            int i = 0;
            str = (char*)malloc(1*sizeof(char));
        
            while(c = getc(stdin),c!='\n')
            {
              str[i] = c;
              i++;
              realloc(str,i*sizeof(char));
            }
            str[i] = '\0';
            return str;
        }
        

        【讨论】:

          【解决方案9】:
          char* load_string()
           {
          
          char* string = (char*) malloc(sizeof(char));
          *string = '\0';
          
          int key;
          int sizer = 2;
          
          char sup[2] = {'\0'};
          
          while( (key = getc(stdin)) != '\n')
          {
              string = realloc(string,sizer * sizeof(char));
              sup[0] = (char) key;
              strcat(string,sup);
              sizer++
          
          }
          return string;
          
          }
          
          int main()
            {
          char* str;
          str = load_string();
          
          return 0;
            }
          

          【讨论】:

          • 请解释一下答案和你写的代码。描述不仅可以帮助提出问题的人,还可以帮助遇到问题的人。
          【解决方案10】:

          realloc 是一个相当昂贵的动作...... 这是我接收字符串的方式,realloc 比率不是 1:1:

          char* getAString()
          {    
              //define two indexes, one for logical size, other for physical
              int logSize = 0, phySize = 1;  
              char *res, c;
          
              res = (char *)malloc(sizeof(char));
          
              //get a char from user, first time outside the loop
              c = getchar();
          
              //define the condition to stop receiving data
              while(c != '\n')
              {
                  if(logSize == phySize)
                  {
                      phySize *= 2;
                      res = (char *)realloc(res, sizeof(char) * phySize);
                  }
                  res[logSize++] = c;
                  c = getchar();
              }
              //here we diminish string to actual logical size, plus one for \0
              res = (char *)realloc(res, sizeof(char *) * (logSize + 1));
              res[logSize] = '\0';
              return res;
          }
          

          【讨论】:

            猜你喜欢
            • 2018-04-07
            • 1970-01-01
            • 2018-06-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-11-28
            • 2013-06-07
            相关资源
            最近更新 更多