使用 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()
的特定用途制作一个类似的包装函数,它会为您吃掉额外的换行符,这样您每次调用该函数进行输入时都不必担心它。
这是你对 gets
和 scanf
的混合使用。当我混合使用 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;
}
我 运行 在将字符串(例如名称)保存到结构字段时遇到了一些问题。 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()
的特定用途制作一个类似的包装函数,它会为您吃掉额外的换行符,这样您每次调用该函数进行输入时都不必担心它。
这是你对 gets
和 scanf
的混合使用。当我混合使用 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;
}