在不知道字符串大小的情况下动态提示输入字符串

在不知道字符串大小的情况下动态提示输入字符串

问题描述:

在C语言中,如果我们无法提示字符串长度,那么提示和存储字符串而不浪费空间的最佳方法是什么?例如,通常我会执行以下操作……

In C, what is the best way of prompting and storing a string without wasted space if we cannot prompt for the string length. For example, normally I would do something like the following...

char fname[30];
char lname[30];

printf("Type first name:\n");
scanf("%s", fname);

printf("Type last name:\n");
scanf("%s", lname); 

printf("Your name is: %s %s\n", fname, lname);

但是,我为必须使用更多的空间而感到恼火不想使用 char fname [30] ,而是动态分配字符串的大小。有什么想法吗?

However, I'm annoyed with the fact that I have to use more space than needed so I do not want to use char fname[30], but instead dynamically allocate the size of the string. Any thoughts?

您可以使用 getchar()一次读取一个字符。

You can create a function that dynamically allocates memory for the input as the user types, using getchar() to read one character at a time.

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

void* safeRealloc(void* ptr, size_t size) {
  void *newPtr = realloc(ptr, size);
  if (newPtr == NULL) { // if out of memory
    free(ptr); // the memory block at ptr is not deallocated by realloc
  }
  return newPtr;
}

char* allocFromStdin(void) {
  int size = 32; // initial str size to store input
  char* str = malloc(size*sizeof(char));
  if (str == NULL) {
    return NULL; // out of memory
  }
  char c = '\0';
  int i = 0;
  do {
    c = getchar();
    if (c == '\r' || c == '\n') {
        c = '\0'; // end str if user hits <enter>
    }
    if (i == size) {
        size *= 2; // duplicate str size
        str = safeRealloc(str, size*sizeof(char)); // and reallocate it
        if (str == NULL) {
          return NULL; // out of memory
        }
    }
    str[i++] = c;
  } while (c != '\0');
  str = safeRealloc(str, i); // trim memory to the str content size
  return str;
}

int main(void) {
  puts("Type first name:\n");
  char* fname = allocFromStdin();

  puts("Type last name:\n");
  char* lname = allocFromStdin();

  printf("Your name is: %s %s\n", fname, lname);

  free(fname); // free memory afterwards
  free(lname); // for both pointers
  return 0;
}