如何为未知长度的输入字符串分配内存?

这是结构:

typedef struct _friend { char *firstname; char *lastname; char birthdate[9]; } friend; 

我很困惑如何让用户输入一个字符串并将其作为firstname (或lastname )放在friend结构中。 另外,如果用户在使用fgets时输入的字符数超过256个,该怎么办? 这就是我到目前为止……

 friend *f = (friend *)malloc(sizeof(friend)); //initialize f pointer to friend char *str; fgets(str,256,stdin); f->firstname = (char*)malloc(sizeof(char)*(strlen(str)+1)); strcpy(f->firstname,str); 

好吧,因为stdin是一个缓冲输入,你可以使用fgetc逐个字符地读取输入,直到你遇到换行符或EOF。 也许你正在寻找这样的东西:

 #include  #include  #include  struct friend { char *firstname; char *lastname; char birthdate[9]; }; static char *read_line(FILE *f) { char *r = NULL; char *p = r; char *e = p; int c; while ((c = fgetc(f)) != EOF) { if (p >= e) { size_t l = e > r ? (size_t)(e - r) : 32u; char *x = realloc(r, l); if (!x) { free(r); r = NULL; goto out; } p = x + (p - r); e = x + l; r = x; } if (c != '\n') { *p++ = (char)c; } else { *p++ = '\0'; goto out; } } if (ferror(f) != 0) { free(r); r = NULL; } out: return r; } int main(void) { struct friend f; memset(&f, 0, sizeof(struct friend)); printf("Please enter your first name: "); fflush(stdout); f.firstname = read_line(stdin); if (!f.firstname) goto on_error; printf("Please enter your last name: "); fflush(stdout); f.lastname = read_line(stdin); if (!f.lastname) goto on_error; printf("You first name is: %s\n", f.firstname); printf("Your last name is: %s\n", f.lastname); free(f.firstname); free(f.lastname); return EXIT_SUCCESS; on_error: perror("read_line"); free(f.firstname); free(f.lastname); return EXIT_FAILURE; } 

对于这个问题,没有一个通用的解决方案。 任何特定的工程师可能会根据各种标准对同一问题使用多种解决方案中的一种:

  • 难道解决方案应该简单愚蠢吗?
  • 它应该灵活适应各种输入长度吗?
  • 代码是否只能在有限的环境中运行,而这些环境中已知有足够的内存?
  • 是否有其他人必须了解解决方案,例如持续维护?

对于已知的,适当的内存环境中的简单解决方案,我可能会这样做:

 char buf [1000]; // for English names, this should be big enough friend f; // not a pointer, but a full struct if (!fgets (buf, sizeof buf, stdin)) { perror ("error reading from stdin"); return; } f.firstname = strdup (buf); // allocates the right size of memory and copies ... // when finished with the structure, deallocate the dynamic strings: free (f.firstname); 

注意这几乎完全避免了操纵指针? (只有strdup()正在这样做,它巧妙地封装了必要的操作。)这是一个强大,低故障的代码的function。

别。

有一个单独的缓冲区供用户输入。 然后在用户输入数据到此缓冲区后,您解析它并确定它是否合理(例如,如果它不是空字符串,如果它不包含任何数字或其他奇怪的字符),并删除多余的空格等。如果数据是可以接受的,确定它实际存在多长时间并分配正确的内存量以将其复制到其中。

要将用户输入到单独的缓冲区中,请不要使用fgets() 。 而是在循环中使用fgetc() ,以便在必要时可以增加缓冲区的大小。 例如,您可以从一个小的32字节缓冲区开始,然后在它变满时将缓冲区的大小加倍(使用realloc() )。