繁体   English   中英

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

[英]How to allocate memory for input string of unknown length?

这是结构:

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

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

  • 解决方案应该愚蠢到死吗?
  • 是否应该灵活地适应各种输入长度?
  • 该代码是否仅在已知有足够内存的有限环境中运行?
  • 其他人是否需要了解解决方案,例如进行日常维护?

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

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()可以这样做,并且它巧妙地封装了基本操作。)这是健壮,低麻烦的代码的功能。

别。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM