动态提示字符串而不知道字符串大小

时间:2014-08-10 22:44:24

标签: c dynamic prompt c-strings

在C中,如果我们无法提示字符串长度,那么在没有浪费空间的情况下提示和存储字符串的最佳方法是什么。例如,通常我会做类似以下的事情......

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],而是动态分配字符串的大小。有什么想法吗?

2 个答案:

答案 0 :(得分:3)

来自man scanf

  

•可选的'm'字符。这用于字符串转换(%s,   %c,%[],并减轻调用者分配a的需要   相应的缓冲区来保存输入:相反,scanf()分配一个   大小足够的缓冲区,并指定此缓冲区的地址   相应的指针参数,应该是指向a的指针   char * variable(此变量之前不需要初始化)   电话)。随后调用者应该释放(3)此缓冲区   不再需要。

然而这是一个POSIX扩展(由fiddling_bits指出)。

为了便于携带,我认为在您的使用案例中,我会准备如下函数:

char *alloc_answer() {
  char buf[1000];
  fgets(buf,sizeof(buf),stdin);
  size_t l = strlen(buf);
  if (buf[l-1]=='\n') buf[l]=0; // remove possible trailing '\n'
  return strdup(buf);
}

即使这个解决方案会破坏超过1000个字符的行(但它至少会阻止缓冲区溢出)。

一个功能齐全的解决方案需要以块的形式读取输入并在每个块上重新分配缓冲区......

答案 1 :(得分:3)

您可以创建一个函数,在用户输入时为输入动态分配内存,使用getchar()一次读取一个字符。

#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;
}