用 fgets() 替换 gets()
Replacing gets() with fgets()
我一直在测试这个结构,我收到关于使用 gets
的警告。有人提到要改用 fgets
并将末尾替换为 '[=13=]'
。有什么建议我可以更改我的代码来做到这一点吗?
void regCars(Car reg[], int *pNrOfCars) {
char again[WORDLENGTH] = "yes", model[WORDLENGTH], tmp[WORDLENGTH];
int year, milage;
while (strcmp(again, "yes") == 0) {
printf("Enter model:");
gets(model);
printf("Enter Year:");
gets(tmp);
year = atoi(tmp);
printf("Enter milage:");
gets(tmp);
milage = atoi(tmp);
reg[*pNrOfCars] = createCar(model, year, milage);
(*pNrOfCars)++;
printf("Continue? (yes/no)");
gets(again);
}
}
举个例子
if (NULL != fgets(model, WORDLENGTH, stdin)) /* Read the string. */
{
model[strcspn(model, "\r\n")] = '[=10=]'; /* Cut off \n and/or \r, if any. */
}
它比看起来要复杂一些。如果您随后处理超长输入的截断行并将其视为有效,则仅用 fgets() 替换 gets 没有多大意义。您只是用错误的行为替换了未定义的行为。
if( fgets(line, sizeof(line), fp) )
{
if(!strchr(line, '\n'))
{
/* line is too long, what you do is up to you, but normally
we will discard it */
int ch;
while( (ch = fgetc(fp)) != EOF)
if(ch == '\n')
break;
}
else
{
/* line is a normal line with a trailing '\n' (gets trims the '\n') */
}
}
您可以编写一个实用函数 mygets()
,它接受 2 个参数:一个指向目标数组的指针及其大小:
char *mygets(char *dest, size_t size) {
/* read a line from standard input and strip the linefeed if any */
if (fgets(dest, size, stdin)) {
dest[strcspn(dest, "\n")] = '[=10=]');
return dest;
}
return NULL;
}
void regCars(Car reg[], int *pNrOfCars) {
char model[WORDLENGTH], tmp[WORDLENGTH];
int year, milage;
for (;;) {
printf("Enter model:");
if (!mygets(model, sizeof mode))
break;
printf("Enter year:");
if (!mygets(tmp, sizeof tmp))
break;
year = atoi(tmp);
printf("Enter milage:");
if (!mygets(tmp, sizeof tmp))
break;
milage = atoi(tmp);
reg[*pNrOfCars] = createCar(model, year, milage);
(*pNrOfCars)++;
printf("Continue? (yes/no)");
if (!mygets(tmp, sizeof(tmp))
break;
if (strcmp(again, "yes") != 0)
break;
}
}
请注意,您可以使用 prompt()
输出问题并读取响应的函数分解更多代码:
char *prompt(const char *message, char *dest, size_t size) {
printf("%s ", message);
fflush(stdout);
/* read a line from standard input and strip the linefeed if any */
if (fgets(dest, size, stdin)) {
dest[strcspn(dest, "\n")] = '[=11=]');
return dest;
}
return NULL;
}
void regCars(Car reg[], int *pNrOfCars) {
char model[WORDLENGTH], tmp[WORDLENGTH];
int year, milage;
for (;;) {
if (!prompt("Enter model:", model, sizeof mode))
break;
if (!prompt("Enter year:", tmp, sizeof tmp))
break;
year = atoi(tmp);
if (!prompt("Enter milage:", tmp, sizeof tmp))
break;
milage = atoi(tmp);
reg[*pNrOfCars] = createCar(model, year, milage);
(*pNrOfCars)++;
if (!prompt("Continue? (yes/no)", tmp, sizeof(tmp))
break;
if (strcmp(again, "yes") != 0)
break;
}
}
另请注意,此函数应采用 reg
数组的大小,以便在数组已满时停止提示更多输入。正如目前指定的那样,它具有与gets()
相同的缺点,意外的输入将导致未定义的行为。
我一直在测试这个结构,我收到关于使用 gets
的警告。有人提到要改用 fgets
并将末尾替换为 '[=13=]'
。有什么建议我可以更改我的代码来做到这一点吗?
void regCars(Car reg[], int *pNrOfCars) {
char again[WORDLENGTH] = "yes", model[WORDLENGTH], tmp[WORDLENGTH];
int year, milage;
while (strcmp(again, "yes") == 0) {
printf("Enter model:");
gets(model);
printf("Enter Year:");
gets(tmp);
year = atoi(tmp);
printf("Enter milage:");
gets(tmp);
milage = atoi(tmp);
reg[*pNrOfCars] = createCar(model, year, milage);
(*pNrOfCars)++;
printf("Continue? (yes/no)");
gets(again);
}
}
举个例子
if (NULL != fgets(model, WORDLENGTH, stdin)) /* Read the string. */
{
model[strcspn(model, "\r\n")] = '[=10=]'; /* Cut off \n and/or \r, if any. */
}
它比看起来要复杂一些。如果您随后处理超长输入的截断行并将其视为有效,则仅用 fgets() 替换 gets 没有多大意义。您只是用错误的行为替换了未定义的行为。
if( fgets(line, sizeof(line), fp) )
{
if(!strchr(line, '\n'))
{
/* line is too long, what you do is up to you, but normally
we will discard it */
int ch;
while( (ch = fgetc(fp)) != EOF)
if(ch == '\n')
break;
}
else
{
/* line is a normal line with a trailing '\n' (gets trims the '\n') */
}
}
您可以编写一个实用函数 mygets()
,它接受 2 个参数:一个指向目标数组的指针及其大小:
char *mygets(char *dest, size_t size) {
/* read a line from standard input and strip the linefeed if any */
if (fgets(dest, size, stdin)) {
dest[strcspn(dest, "\n")] = '[=10=]');
return dest;
}
return NULL;
}
void regCars(Car reg[], int *pNrOfCars) {
char model[WORDLENGTH], tmp[WORDLENGTH];
int year, milage;
for (;;) {
printf("Enter model:");
if (!mygets(model, sizeof mode))
break;
printf("Enter year:");
if (!mygets(tmp, sizeof tmp))
break;
year = atoi(tmp);
printf("Enter milage:");
if (!mygets(tmp, sizeof tmp))
break;
milage = atoi(tmp);
reg[*pNrOfCars] = createCar(model, year, milage);
(*pNrOfCars)++;
printf("Continue? (yes/no)");
if (!mygets(tmp, sizeof(tmp))
break;
if (strcmp(again, "yes") != 0)
break;
}
}
请注意,您可以使用 prompt()
输出问题并读取响应的函数分解更多代码:
char *prompt(const char *message, char *dest, size_t size) {
printf("%s ", message);
fflush(stdout);
/* read a line from standard input and strip the linefeed if any */
if (fgets(dest, size, stdin)) {
dest[strcspn(dest, "\n")] = '[=11=]');
return dest;
}
return NULL;
}
void regCars(Car reg[], int *pNrOfCars) {
char model[WORDLENGTH], tmp[WORDLENGTH];
int year, milage;
for (;;) {
if (!prompt("Enter model:", model, sizeof mode))
break;
if (!prompt("Enter year:", tmp, sizeof tmp))
break;
year = atoi(tmp);
if (!prompt("Enter milage:", tmp, sizeof tmp))
break;
milage = atoi(tmp);
reg[*pNrOfCars] = createCar(model, year, milage);
(*pNrOfCars)++;
if (!prompt("Continue? (yes/no)", tmp, sizeof(tmp))
break;
if (strcmp(again, "yes") != 0)
break;
}
}
另请注意,此函数应采用 reg
数组的大小,以便在数组已满时停止提示更多输入。正如目前指定的那样,它具有与gets()
相同的缺点,意外的输入将导致未定义的行为。