使用strncpy(),其中destination包含源

时间:2015-10-22 08:02:14

标签: c string nested trim strncpy

首先,如果有人回答,我道歉。我做了搜索stackoverflow,但找不到类似的主题。 (也许我的搜索功能很弱)

我写了一个函数来修剪C中字符串中的空格字符。 我关心的是trim函数中的最后一行,其中源包含在目标中。测试用例都很好,还有其他一些测试。可以复制源和目标位于同一内存中的全部或部分字符串会导致奇怪的问题吗?

谢谢,

代码

#include <stdio.h>
#include <string.h>

void trim(char *line)
  {
  int  i, len = strlen(line);
  char *ptr, whitespace[] = " \t\n";

  // 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) = '\0';

  // 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 tabs\t",
    "\na line with leading and trailing newlines\n"
    };

  for (i=0; i<4; i++)
    {
    printf("test %d\nno trim: %s\n", i, test[i]);
    trim(test[i]);
    printf("trimmed: %s\n", test[i]);
    }
  return 0;
  }

2 个答案:

答案 0 :(得分:10)

如果您阅读例如this strncpy reference你会看到

  

如果字符数组重叠,则行为未定义。

您需要使用memmove来指定处理重叠内存。

答案 1 :(得分:0)

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

// 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) = '\0';

两个中的一个:

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

第一次进入循环时,会得到一个\0字符(*(line + len)处的字符,并且它不在您使用的"\n \t"集中,因此循环始终会失败一开始,让你在位置\0写一个i + 1(这是未定义的行为,因为你将它写在\0字符之后)。

如同其他回应所指出的那样,对重叠字符串的阻止使用strncpy也是如此。

注意

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

另一方面,我不知道是否为字符strchr(3)搜索空终止字符串('\0'}是未定义的行为,但如果它找到了正确的字符串终止符,那么''很幸运,不会离开for循环(\0出现在所有字符串中,不知何故)由于手册没有说明任何内容,也许有人可以从标准中说明