替代获取?

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 = NULLn = 0.