为啥要使用 strtok(line, "\n") **not** 来去除 fgets() 留下的换行符

Posted

技术标签:

【中文标题】为啥要使用 strtok(line, "\\n") **not** 来去除 fgets() 留下的换行符【英文标题】:Why should strtok(line, "\n") **not** be used to strip the newline left by fgets()为什么要使用 strtok(line, "\n") **not** 来去除 fgets() 留下的换行符 【发布时间】:2021-01-25 22:12:52 【问题描述】:

fgets() 是读取输入行的安全函数,但它将从文件中读取的 新行 字节 '\n' 存储在数组中(如果合适)。

在许多情况下,如果不是大多数情况下,此新行必须在进一步处理行内容之前被删除。

可以使用几种简单的方法,但我看到了一个紧凑而棘手的建议:

strtok(line, "\n");    // strip the newline

为什么这种方法不正确,为什么它并不总是有效?

【问题讨论】:

密切相关:Removing trailing newline character from fgets() input. @FredLarson:有趣的参考。我专门针对我最近多次看到的strtok() 的滥用。 是的,这是我链接的问题的已接受答案的一部分。 【参考方案1】:

该方法很棘手,因为strtok() 函数对全局隐藏状态变量有副作用。这可能会影响周围的代码并证明难以调试。

此外,还有一个简单的情况,strtok(line, "\n") 不会用空字节覆盖'\n':如果fgets() 读取的行是一个空行,只包含一个新行 字节。对于此内容,strtok() 将跳过最初的换行,搜索不存在的不同字符,并返回NULL 修改数组。因此它不会剥离 新行

这是不使用strtok(line, "\n") 去除换行字节的令人信服的理由。

当然可以通过以下方式解决这个问题:

   if (*line == '\n')
       *line = '\0';
   else
       strtok(line, "\n");

或繁琐的单行:

    (void)(*line == '\n' ? (*line = '\0') : (strtok(line, "\n"), 0);
    if (!strtok(line, "\n")) *line = '\0';
    (void)(strtok(line, "\n") || (*line = '\0'));

但代码不再紧凑,还有其他副作用。

其他方法可用:

使用明确的for 语句:

  for (char *p = line; *p; p++) 
      if (*p == '\n')
          *p = '\0';
  

使用strlen():

  size_t len = strlen(line);
  if (len > 1 && line[len - 1] == '\n') 
      line[--len] = '\0';
  
  // len is the length if the stripped line

使用strchr():

  char *p = strchr(line, '\n');
  if (p) 
      *p = '\0';
  

在单行中使用strcspn()

  line[strcspn(line, "\n")] = '\0';  // strip the newline if any.

【讨论】:

+ 就像用两天时间为机械臂编程一个螺丝。 @0___________: 或使用steam hammer 钉钉子:)

以上是关于为啥要使用 strtok(line, "\n") **not** 来去除 fgets() 留下的换行符的主要内容,如果未能解决你的问题,请参考以下文章

strtok函数怎么用啊?

strcat 如何影响 strtok?

C语言 字符串处理函数strtok第二次及以后的调用中第一个参数要用NULL的原因是啥? 能不能解释下原理?

strtok - 详细示例解析

C语言如何实现分割字符串为一个个单独的字符并保存

浅谈strtok