替代获取?
Alternative to gets?
我曾经使用 gets 但后来听说它已从 c11 中删除并且它总体上非常危险。
所以我做了一些搜索,发现您可以使用 fgets() 来做同样的事情。
问题是,当我使用 fgets() 时,它似乎也复制了该行的末尾,这最终导致了额外的不需要的行。
向您展示我的意思:
//if I have
char key[30];
fgets(key, sizeof(key), stdin);
//now if ender for instance: Doggo and do:
printf("The key is:%s|hozaah!\n", key);
//I expect it to print:
The key is:Doggo|hozaah!
//Instead it prints:
The key is:Doggo
|hozaah!
有办法解决这个问题吗?或者我可以使用其他功能吗?
答案在于 fgets
读取缓冲区中容纳的所有字符,包括空终止符,但只读到文件末尾或换行符,它将 也将换行符存储在字符串中:man 3 fgets
因此,如果您在终端上输入,换行符也会传输到标准输入,并由 fgets
读取。这与旧的 gets
不同,它用空字节替换换行符。
因此,如果您正在阅读行并且不想要潜在的换行符,请将其删除。不幸的是,fgets
不会告诉您读取了多少个字符,因此您必须再次扫描字符串才能计算出来:
char* p = fgets(key, sizeof(key), stdin);
if (!p) { /* error */ }
size_t n = strlen(key);
if (n > 0 && key[n - 1] == '\n') {
key[n - 1] = '[=10=]';
} else {
/* buffer too short or EOF reached without newline */
}
printf("The line was: '%s'\n", key);
可能值得考虑替代方案:如果您只需要一个输入,请不要首先输入换行符。如果您需要很多行,请使用 fread
到固定大小的缓冲区并自行扫描换行符。
gets()
没有标准的直接替换,但是有很多简单的方法可以去掉换行符(如果存在):
最简单的使用strcspn
(在<string.h>
中声明):
if (fgets(buf, sizeof buf, fp)) {
buf[strcspn(buf, "\n")] = '[=10=]';
}
经典使用strlen
:
if (fgets(buf, sizeof buf, fp)) {
size_t len = strlen(buf);
if (len > 0 && buf[len - 1] == '\n')
buf[--len] = '[=11=]';
}
又一经典 strchr
:
if (fgets(buf, sizeof buf, fp)) {
char *p = strchr(buf, '\n');
if (p != NULL)
*p = '[=12=]';
}
另一种方法是 POSIX 函数 getline()
,它可能在您的系统上可用:
#include <stdio.h>
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
缓冲区已分配或重新分配malloc()
,其大小已更新为*n
。初始值应为 lineptr = NULL
和 n = 0
.
我曾经使用 gets 但后来听说它已从 c11 中删除并且它总体上非常危险。 所以我做了一些搜索,发现您可以使用 fgets() 来做同样的事情。
问题是,当我使用 fgets() 时,它似乎也复制了该行的末尾,这最终导致了额外的不需要的行。
向您展示我的意思:
//if I have
char key[30];
fgets(key, sizeof(key), stdin);
//now if ender for instance: Doggo and do:
printf("The key is:%s|hozaah!\n", key);
//I expect it to print:
The key is:Doggo|hozaah!
//Instead it prints:
The key is:Doggo
|hozaah!
有办法解决这个问题吗?或者我可以使用其他功能吗?
答案在于 fgets
读取缓冲区中容纳的所有字符,包括空终止符,但只读到文件末尾或换行符,它将 也将换行符存储在字符串中:man 3 fgets
因此,如果您在终端上输入,换行符也会传输到标准输入,并由 fgets
读取。这与旧的 gets
不同,它用空字节替换换行符。
因此,如果您正在阅读行并且不想要潜在的换行符,请将其删除。不幸的是,fgets
不会告诉您读取了多少个字符,因此您必须再次扫描字符串才能计算出来:
char* p = fgets(key, sizeof(key), stdin);
if (!p) { /* error */ }
size_t n = strlen(key);
if (n > 0 && key[n - 1] == '\n') {
key[n - 1] = '[=10=]';
} else {
/* buffer too short or EOF reached without newline */
}
printf("The line was: '%s'\n", key);
可能值得考虑替代方案:如果您只需要一个输入,请不要首先输入换行符。如果您需要很多行,请使用 fread
到固定大小的缓冲区并自行扫描换行符。
gets()
没有标准的直接替换,但是有很多简单的方法可以去掉换行符(如果存在):
最简单的使用
strcspn
(在<string.h>
中声明):if (fgets(buf, sizeof buf, fp)) { buf[strcspn(buf, "\n")] = '[=10=]'; }
经典使用
strlen
:if (fgets(buf, sizeof buf, fp)) { size_t len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') buf[--len] = '[=11=]'; }
又一经典
strchr
:if (fgets(buf, sizeof buf, fp)) { char *p = strchr(buf, '\n'); if (p != NULL) *p = '[=12=]'; }
另一种方法是 POSIX 函数 getline()
,它可能在您的系统上可用:
#include <stdio.h>
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
缓冲区已分配或重新分配malloc()
,其大小已更新为*n
。初始值应为 lineptr = NULL
和 n = 0
.