使用 gets() 将字符串保存到结构?

Saving strings to structs using gets()?

我 运行 在将字符串(例如名称)保存到结构字段时遇到了一些问题。 gets()fgets() 都用过,但 fgets() 也不能正常工作。

我从来没有机会输入第一个员工的名字;它直接跳到员工代码,然后也跳过地址。不知为何,在输入第二个员工时,我输入了姓名和代码,然后又跳过了地址。

有人知道我做错了什么吗?

#include <stdio.h>

typedef struct {
    char name[150];
    int code;
    char add[300];
} tEmployee;

int main()
{
    printf("How many employees would you like to register?\n");
    int n;
    scanf("%i", &n);

    tEmployee employee[n];

    for (int i = 0; i < n; i++)
    {
        printf("Name: ");
        gets(employee[i].name);
        printf("Code: ");
        scanf("%i", &employee[i].code);
        printf("Address: ");
        gets(employee[i].add);

        printf("%s\n", employee[i].name);
        printf("%i\n", employee[i].code);
        printf("%s\n", employee[i].add);
     }
     return 0;
}

C 库输入例程在处理换行符 (\n) 的方式上不一致。有些人将其作为输入的一部分阅读,有些人则没有。由于 scanf() 在换行符之前得到了它需要的东西,它没有理由读入它,所以我们必须在下一次输入之前非常明确地将它从缓冲区中清除。有不同的技术,但仅调用 getchar() 即可用于此示例。

此外,由于 gets() 被认为 不安全 ,并在您输入的末尾留下一个换行符,我添加了自定义 my_gets()解决这两个问题的包装器:

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

typedef struct {
    char name[150];
    int code;
    char add[300];
} tEmployee;

char *my_gets(char *str, int size)
{
    char *pos;

    char *result = fgets(str, size, stdin);

    if (result != NULL && (pos = strchr(str, '\n')) != NULL)
        *pos = '[=10=]';

    return result;
}

int main()
{
    int n;
    printf("How many employees would you like to register?\n");
    scanf("%i", &n);
    getchar(); // eat newline \n

    tEmployee employee[n];

    for (int i = 0; i < n; i++)
    {
        printf("Name: ");
        my_gets(employee[i].name, 150);

        printf("Code: ");
        scanf("%i", &employee[i].code);
        getchar(); // eat newline \n

        printf("Address: ");
        my_gets(employee[i].add, 300);

        printf("%s\n", employee[i].name);
        printf("%i\n", employee[i].code);
        printf("%s\n", employee[i].add);
    }

    return 0;
}

您可以为 scanf() 的特定用途制作一个类似的包装函数,它会为您吃掉额外的换行符,这样您每次调用该函数进行输入时都不必担心它。

这是你对 getsscanf 的混合使用。当我混合使用 std::cin>> 运算符以及 std::getline 函数时,我在 C++ 中遇到过类似的问题。

此外,gets 已弃用,请勿使用...

无论如何,如果你真的想同时使用两者,那么每次使用 scanf 时都应该 "flush" stdin,否则下次你阅读 stdin 时,你将阅读其余部分直到行尾(\n)。

One way to do it,就是在每个scanf:

之后读到行尾
/* define the function */
void flush()
{
    while (getchar() != '\n');
}

然后在您的代码中使用它,如下所示:

printf("How many employees would you like to register?\n");
int n;
scanf("%i", &n);

flush();

tEmployee employee[n];

for (int i = 0; i < n; i++)
{
    printf("Name: ");
    gets(employee[i].name);
    printf("Code: ");
    scanf("%i", &employee[i].code);

    flush();

    printf("Address: ");
    gets(employee[i].add);

    printf("%s\n", employee[i].name);
    printf("%i\n", employee[i].code);
    printf("%s\n", employee[i].add);
 }
 return 0;

试试这个:

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

typedef struct {
    char name[150];
    int32_t code;
    char add[300];    
} tEmployee;

typedef uint_fast8_t bool_t;

/*****************************************************************************
 * flush stdin... this should be standard but somewhy you need to reinvent
 * it all the time...
 *****************************************************************************/
static inline void flush_stdin()
{
    char ch;

    do {
        ch = getchar();
    } while ((ch != '\n') && (ch != EOF));
}

/*****************************************************************************
 * reads a line of text from a stream.
 *****************************************************************************/
static inline bool_t xio_fgetline(FILE *stream, char *linebuf, size_t szline)
{
    fgets(linebuf, szline, stream);

    // find last character.
    char *lc = linebuf + strlen(linebuf) - 1;

    // the only case when lc is a null is if the program memory
    //     has been altered. In this case, it should crash anyway.
    //     therefore I skip a nullcheck before chomping.

    // chomp linebuf.
    if (*lc == '\n') {
        *lc = 0;
    }

    // string is {0} after chomping.
    if (strlen(linebuf) == 0) {
        return 0;
    }

    return 1;
}

/*****************************************************************************
 * reads a line of text from stdin.
 *****************************************************************************/
static inline bool_t xio_getline(char *linebuf, size_t szline)
{
    return (xio_fgetline(stdin, linebuf, szline));
}

int main(int argc, char **argv)
{
    int32_t n;
    tEmployee *employee = (tEmployee *)0;

    printf("How many employees would you like to register?\n");
    scanf("%i", &n);
    flush_stdin();

    employee = (tEmployee *)malloc(n * sizeof(tEmployee));

    for (int32_t i = 0; i < n; ++i) {
        printf("Name: ");
        xio_getline(employee[i].name, sizeof(employee[i].name));

        printf("Code: ");
        scanf("%i", &employee[i].code);
        flush_stdin();

        printf("Address: ");        
        xio_getline(employee[i].add, sizeof(employee[i].add));

        printf("%s\n", employee[i].name);
        printf("%i\n", employee[i].code);
        printf("%s\n", employee[i].add);
    }

    free(employee);
    return 0;
}