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

时间:2012-10-14 00:20:42

标签: c string

这是结构:

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

我对如何让用户输入字符串并将其置于friend结构firstname(或lastname)感到困惑。另外,如果用户在使用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);

3 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:2)

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

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

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

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()正在这样做,并且它巧妙地封装了必要的操作。)这是强大,低故障代码的一个特性。

答案 2 :(得分:1)

别。

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

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