获取的替代方案?

时间:2017-04-02 22:26:24

标签: c fgets 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!

有没有办法解决这个问题?或者我可以使用另一种功能吗?

2 个答案:

答案 0 :(得分:4)

gets()没有标准的直接替换,但有很多简单的方法可以摆脱换行符:

  • 最简单的使用strcspn(在<string.h>中声明):

    if (fgets(buf, sizeof buf, fp)) {
        buf[strcspn(buf, "\n")] = '\0';
    }
    
  • 使用strlen的经典:

    if (fgets(buf, sizeof buf, fp)) {
        size_t len = strlen(buf);
        if (len > 0 && buf[len - 1] == '\n')
            buf[--len] = '\0';
    }
    
  • strchr的另一个经典之作:

    if (fgets(buf, sizeof buf, fp)) {
        char *p = strchr(buf, '\n');
        if (p != NULL)
            *p = '\0';
    }
    

另一种选择是POSIX函数getline(),它可能在您的系统上可用:

#include <stdio.h>
ssize_t getline(char **lineptr, size_t *n, FILE *stream);

使用malloc()分配或重新分配缓冲区,其大小更新为*n。初始值应为lineptr = NULLn = 0

答案 1 :(得分:1)

答案在于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] = '\0';
} else {
  /* buffer too short or EOF reached without newline */
}

printf("The line was: '%s'\n", key);

可能值得考虑替代方案:如果您只需要一个输入,请不要首先输入换行符。如果您需要大量的行,请将fread用于固定大小的缓冲区并自行扫描换行符。