C语言 使用strncpy(),其中目标包含源



我用C写了一个函数来从字符串中删除空白字符。我关心的是下面trim()函数的最后一行,其中源包含在目标中。测试用例和其他一些测试结果都很好。复制源和目标在同一内存中的字符串的全部或部分会导致奇怪的问题吗?

源代码:

#include <stdio.h>
#include <string.h>
void trim(char *line)
  {
  int  i, len = strlen(line);
  char *ptr, whitespace[] = " tn";
  // scan for first char which does not match a char in whitespace string
  for (i=0; i<len; i++)
    if (strchr(whitespace, line[i]) == NULL)
      break;
  ptr = line + i;
  // scan for last char which does not match a char in whitespace string
  for (i=len; i>0; i--)
    if (strchr(whitespace, line[i]) == NULL)
      break;
  line[i] + 1) = '';
  // copy result to line (this is the line relevant to the question)
  strncpy(line, ptr, len);
  }
int main(void)
  {
  int i;
  char test[4][64] = {
    "a line with no leading and trailing spaces",
    "  a line with some leading and trailing spaces  ",
    "ta line with leading and trailing tabst",
    "na line with leading and trailing newlinesn"
    };
  for (i=0; i<4; i++)
    {
    printf("test %dnno trim: %sn", i, test[i]);
    trim(test[i]);
    printf("trimmed: %sn", test[i]);
    }
  return 0;
  }

如果你读这个strncpy参考,你会看到

如果字符数组重叠,该行为是未定义的。

您需要使用memmove,它被指定用于处理重叠内存。

首先,第二个循环是错误的。我将它复制到这里,以显示它失败的确切位置:

// scan for last char which does not match a char in whitespace string
for (i=len; i>0; i--)
  if (strchr(whitespace, *(line + i)) == NULL)
    break;
*(line + i + 1) = '';

二选一:

  • 或者将for循环重写为for(i = len-1; i>=0; i--)
  • 或者在循环中写入对*(line + i - 1)的引用。

你第一次进入循环,你得到一个字符(在*(line + len)的一个,它不在你使用的"n t"集合中,所以循环总是在开始时失败,使你在位置i + 1上写一个(这是未定义的行为,因为你正在写它超过字符)。

不鼓励在重叠字符串上使用strncpy,正如其他响应所指出的那样。

注意

*(line + i - 1)相当于line[i-1],可读性更强,更不容易出错。并且与函数头中使用的指针定义完全兼容。C语言将这两个表达式定义为等价的。

另一方面,我不知道搜索字符''的空终止字符串(与strchr(3))是否是未定义的行为,但如果它找到正确的字符串终止符,你会很幸运,不会走出for循环(存在于所有字符串中,不知怎的)由于手册没有说任何关于,也许有人可以从标准中说明。

相关内容

  • 没有找到相关文章

最新更新