C 从fgets()输入中删除尾随换行符

C 从fgets()输入中删除尾随换行符,c,string,gcc,newline,fgets,C,String,Gcc,Newline,Fgets,我试图从用户那里获取一些数据,并将其发送到gcc中的另一个函数。代码是这样的 printf("Enter your Name: "); if (!(fgets(Name, sizeof Name, stdin) != NULL)) { fprintf(stderr, "Error reading Name.\n"); exit(1); } 但是,我发现它的结尾有一个换行符\n。因此,如果我输入John,它将发送John\n。如何删除该\n并发送正确的字符串。优雅的方式: Nam

我试图从用户那里获取一些数据,并将其发送到gcc中的另一个函数。代码是这样的

printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}
但是,我发现它的结尾有一个换行符
\n
。因此,如果我输入
John
,它将发送
John\n
。如何删除该
\n
并发送正确的字符串。

优雅的方式:

Name[strcspn(Name, "\n")] = 0;
略显丑陋的方式:

char*pos;
如果((pos=strchr(名称,'\n'))!=NULL)
*pos='\0';
其他的
/*缓冲区输入太长,标志错误*/
有点奇怪的方式:

strtok(名称“\n”);
请注意,如果用户输入一个空字符串(即只按Enter键),则strtok函数不会按预期工作。它使
\n
字符保持不变


当然还有其他的。

如果每行都有'\n',请直接从fgets输出中删除'\n'

size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
line[strlen(line) - 1] = '\0';
否则:

void remove_newline_ch(char *line)
{
    int new_line = strlen(line) -1;
    if (line[new_line] == '\n')
        line[new_line] = '\0';
}

下面是从
fgets()
保存的字符串中删除潜在
'\n'
的快速方法
它使用带有2个测试的
strlen()

char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {

  size_t len = strlen(buffer);
  if (len > 0 && buffer[len-1] == '\n') {
    buffer[--len] = '\0';
  }
现在根据需要使用
buffer
len

此方法的附带好处是后续代码的
len
值。它可以轻松地比strchr(名称,'\n')
更快。YMMV,但这两种方法都有效


在某些情况下,原始
fgets()
中的
缓冲区将不包含在
“\n”
中:
A) 对于
缓冲区
而言,行太长,因此只有
字符
前面的
'\n'
保存在
缓冲区
中。未读字符仍保留在流中。
B) 文件中的最后一行没有以
'\n'
结尾

如果输入在某处嵌入了空字符
'\0'
,则
strlen()
报告的长度将不包括
'\n'
位置


其他一些答案的问题:

  • strtok(缓冲区“\n”)缓冲区
    “\n”
    时,code>无法删除
    “\n”
    。从本答案开始-在本答案之后进行修订,以警告此限制

  • fgets()
    读取的第一个
    char
    '\0'
    时,以下操作很少失败。当输入以嵌入的
    '\0'
    开头时会发生这种情况。然后
    buffer[len-1]
    变成
    buffer[SIZE\u MAX]
    访问内存肯定超出了
    buffer
    的合法范围。黑客在愚蠢地读取UTF16文本文件时可能会尝试或发现的东西。这是写下这个答案时的状态。后来,一个非OP编辑了它,以包含类似于此答案的代码检查

  • sprintf(缓冲区,“%s”,缓冲区)是未定义的行为:。此外,它不保存任何前导、分隔或尾随空格。现在

  • [由于以后良好而编辑]1线性
    缓冲区[strcspn(缓冲区,“\n”)]=0没有问题strlen()
    方法相比,代码>而非性能。如果代码正在进行I/O(CPU时间的黑洞),修剪性能通常不是问题。如果下面的代码需要字符串的长度或对性能非常敏感,请使用此
    strlen()
    方法。否则,
    strcspn()
    就是一个很好的选择


  • 也许最简单的解决方案是使用我最喜欢的一个鲜为人知的函数:

    如果希望它也处理
    '\r'
    (例如,如果流是二进制的):

    该函数计算字符数,直到找到
    '\r'
    '\n'
    (换句话说,它找到第一个
    '\r'
    '\n'
    )。如果没有命中任何内容,它将停止在
    '\0'
    (返回字符串的长度)


    请注意,即使没有换行符,这也可以正常工作,因为
    strcspn
    '\0'
    处停止。在这种情况下,整行只需将单个'\n'修剪的
    '\0'
    替换为
    '\0'

    void remove_new_line(char* string)
    {
        size_t length = strlen(string);
        if((length > 0) && (string[length-1] == '\n'))
        {
            string[length-1] ='\0';
        }
    }
    
    void remove_multi_new_line(char* string)
    {
      size_t length = strlen(string);
      while((length>0) && (string[length-1] == '\n'))
      {
          --length;
          string[length] ='\0';
      }
    }
    
    对于多个'\n'修剪

    void remove_new_line(char* string)
    {
        size_t length = strlen(string);
        if((length > 0) && (string[length-1] == '\n'))
        {
            string[length-1] ='\0';
        }
    }
    
    void remove_multi_new_line(char* string)
    {
      size_t length = strlen(string);
      while((length>0) && (string[length-1] == '\n'))
      {
          --length;
          string[length] ='\0';
      }
    }
    

    TimČas one liner对于通过调用fgets获得的字符串来说是惊人的,因为您知道它们的末尾包含一个换行符

    如果您处于不同的上下文中,并且希望处理可能包含多个换行符的字符串,那么您可能正在寻找strrspn。它不是POSIX,这意味着您无法在所有Unice上找到它。我为自己的需要写了一本

    /* Returns the length of the segment leading to the last 
       characters of s in accept. */
    size_t strrspn (const char *s, const char *accept)
    {
      const char *ch;
      size_t len = strlen(s);
    
    more: 
      if (len > 0) {
        for (ch = accept ; *ch != 0 ; ch++) {
          if (s[len - 1] == *ch) {
            len--;
            goto more;
          }
        }
      }
      return len;
    }
    
    对于那些在C中寻找Perl chomp等价物的人,我认为就是这样(chomp只删除后面的换行符)

    strrcpn功能:

    /* Returns the length of the segment leading to the last 
       character of reject in s. */
    size_t strrcspn (const char *s, const char *reject)
    {
      const char *ch;
      size_t len = strlen(s);
      size_t origlen = len;
    
      while (len > 0) {
        for (ch = reject ; *ch != 0 ; ch++) {
          if (s[len - 1] == *ch) {
            return len;
          }
        }
        len--;
      }
      return origlen;
    }
    

    下面的函数是我在Github上维护的字符串处理库的一部分。它会从字符串中删除不需要的字符,这正是您想要的

    int zstring_search_chr(const char *token,char s){
        if (!token || s=='\0')
            return 0;
    
        for (;*token; token++)
            if (*token == s)
                return 1;
    
        return 0;
    }
    
    char *zstring_remove_chr(char *str,const char *bad) {
        char *src = str , *dst = str;
        while(*src)
            if(zstring_search_chr(bad,*src))
                src++;
            else
                *dst++ = *src++;  /* assign first, then incement */
    
        *dst='\0';
            return str;
    }
    
    一个示例用法可以是

    Example Usage
          char s[]="this is a trial string to test the function.";
          char const *d=" .";
          printf("%s\n",zstring_remove_chr(s,d));
    
      Example Output
          thisisatrialstringtotestthefunction
    
    您可能希望检查其他可用功能,甚至为项目做出贡献:)


    因为您将使用单引号,而不是双引号。如果您想了解更多信息,请提供一个关于单引号与双引号的链接如果使用
    getline
    是一个选项—不要忽略其安全性问题,如果您希望使用大括号指针—您可以避免使用字符串函数,因为
    getline
    返回字符数。像下面这样

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        char *fname, *lname;
        size_t size = 32, nchar; // Max size of strings and number of characters read
        fname = malloc(size * sizeof *fname);
        lname = malloc(size * sizeof *lname);
        if (NULL == fname || NULL == lname)
        {
            printf("Error in memory allocation.");
            exit(1);
        }
        printf("Enter first name ");
        nchar = getline(&fname, &size, stdin);
        if (nchar == -1) // getline return -1 on failure to read a line.
        {
            printf("Line couldn't be read..");
            // This if block could be repeated for next getline too
            exit(1);
        }
        printf("Number of characters read :%zu\n", nchar);
        fname[nchar - 1] = '\0';
        printf("Enter last name ");
        nchar = getline(&lname, &size, stdin);
        printf("Number of characters read :%zu\n", nchar);
        lname[nchar - 1] = '\0';
        printf("Name entered %s %s\n", fname, lname);
        return 0;
    }
    
    #包括
    #包括
    int main()
    {
    字符*fname,*lname;
    size\u t size=32,nchar;//字符串的最大大小和读取的字符数
    fname=malloc(大小*sizeof*fname);
    lname=malloc(尺寸*尺寸*lname);
    if(NULL==fname | | NULL==lname)
    {
    printf(“内存分配错误”);
    出口(1);
    }
    printf(“输入名字”);
    nchar=getline(&fname,&size,stdin);
    if(nchar=-1)//getline读取一行失败时返回-1。
    {
    printf(“无法读取行…”);
    //这个if块也可以在下一个getline中重复
    出口(1);
    }
    printf(“Num
    
    Example Usage
          char s[]="this is a trial string to test the function.";
          char const *d=" .";
          printf("%s\n",zstring_remove_chr(s,d));
    
      Example Output
          thisisatrialstringtotestthefunction
    
     for(int i = 0; i < strlen(Name); i++ )
    {
        if(Name[i] == '\n') Name[i] = '\0';
    }
    
    if(Name[i] == '\n') Name[i] = '\0';
    
    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        char *fname, *lname;
        size_t size = 32, nchar; // Max size of strings and number of characters read
        fname = malloc(size * sizeof *fname);
        lname = malloc(size * sizeof *lname);
        if (NULL == fname || NULL == lname)
        {
            printf("Error in memory allocation.");
            exit(1);
        }
        printf("Enter first name ");
        nchar = getline(&fname, &size, stdin);
        if (nchar == -1) // getline return -1 on failure to read a line.
        {
            printf("Line couldn't be read..");
            // This if block could be repeated for next getline too
            exit(1);
        }
        printf("Number of characters read :%zu\n", nchar);
        fname[nchar - 1] = '\0';
        printf("Enter last name ");
        nchar = getline(&lname, &size, stdin);
        printf("Number of characters read :%zu\n", nchar);
        lname[nchar - 1] = '\0';
        printf("Name entered %s %s\n", fname, lname);
        return 0;
    }
    
    #define IPT_SIZE 5
    
    int findNULL(char* arr)
    {
        for (int i = 0; i < strlen(arr); i++)
        {
            if (*(arr+i) == '\n')
            {
                return i;
            }
        }
        return 0;
    }
    
    int main()
    {
        char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
        int counter = 0;
    
        //prompt user for the input:
        printf("input string no longer than %i characters: ", IPT_SIZE);
        do
        {
            fgets(input, 1000, stdin);
            *(input + findNULL(input)) = '\0';
            if (strlen(input) > IPT_SIZE)
            {
                printf("error! the given string is too large. try again...\n");
                counter++;
            }
            //if the counter exceeds 3, exit the program (custom function):
            errorMsgExit(counter, 3); 
        }
        while (strlen(input) > IPT_SIZE);
    
    //rest of the program follows
    
    free(input)
    return 0;
    }
    
    size_t sl = strlen(NAME);
    
    if(sl == 0)
    {
       // Skip the newline replacement process.
    }
    
    if(NAME[sl - 1] == '\n')
    {
       NAME[sl - 1] = '\0';
    }
    
    if(sl > 0 && NAME[sl - 1] == '\n')
    {
       NAME[sl - 1] = '\0';
    }
    
    size_t sl = strlen(NAME);
    if(sl > 0 && NAME[sl - 1] == '\n')
    {
       NAME[sl - 1] = '\0';
    }
    
    void fgets_newline_kill(char a[])
    {
        size_t sl = strlen(a);
    
        if(sl > 0 && a[sl - 1] == '\n')
        {
           a[sl - 1] = '\0';
        }
    }
    
    printf("Enter your Name: ");
    
    if (fgets(Name, sizeof Name, stdin) == NULL) {
        fprintf(stderr, "Error reading Name.\n");
        exit(1);
    }
    else {
        fgets_newline_kill(NAME);
    }
    
    #include <stdio.h>
    int
    main(void)
    {
            char Name[256];
            char fmt[32];
            sprintf(fmt, "%%%zd[^\n]", sizeof Name - 1);
            if( scanf(fmt, Name) == 1 ) {
                    printf("Name = %s\n", Name);
            }
            return 0;
    }