3

这是结构:

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

我对如何让用户输入一个字符串并将其作为(或)放置在friend结构中感到困惑。另外,如果用户在我使用时输入超过 256 个字符怎么办?这是我目前所拥有的......firstnamelastnamefgets

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);
4

3 回答 3

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

请注意这几乎完全避免了操作指针?(Onlystrdup()正在做,它巧妙地封装了基本操作。)这是健壮、低故障代码的一个特点。

于 2012-10-14T01:08:05.493 回答
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;
}
于 2012-10-14T01:00:49.677 回答
1

不。

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

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

于 2012-10-14T00:52:15.360 回答