在目标包含源的位置使用strncpy()

在目标包含源的位置使用strncpy(),c,string,nested,trim,strncpy,C,String,Nested,Trim,Strncpy,我编写了一个函数来修剪C中字符串中的空白字符。 我关心的是下面trim()函数的最后一行,其中源包含在目标中。测试用例和其他一些测试结果都很好。复制源和目标位于同一内存中的字符串的全部或部分是否会导致奇怪的问题 源代码: #include <stdio.h> #include <string.h> void trim(char *line) { int i, len = strlen(line); char *ptr, whitespace[] = &qu

我编写了一个函数来修剪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;
  }
#包括
#包括
空白修剪(字符*行)
{
int i,len=strlen(直线);
char*ptr,空格[]=“\t\n”;
//扫描与空白字符串中的字符不匹配的第一个字符
对于(i=0;i0;i--)
if(strchr(空格,第[i]行]==NULL)
打破
第[i]+1行)='\0';
//将结果复制到行(这是与问题相关的行)
strncpy(线路、ptr、len);
}
内部主(空)
{
int i;
字符测试[4][64]={
“没有前导空格和尾随空格的行”,
“包含一些前导空格和尾随空格的行”,
“\t带前导和尾随制表符的行\t”,
“\n带前导和尾随换行符的行\n”
};
对于(i=0;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';
二者之一:

  • 或者将
    for
    循环重写为
    for(i=len-1;i>=0;i--)
  • 或者在循环中写入对
    *(line+i-1)
    的引用
第一次进入循环时,您会得到一个
\0
字符(位于
*(line+len)
,它不在您使用的
“\n\t”
集合中,因此循环总是在开始时失败,使您在
i+1
位置写入一个
\0
(这是未定义的行为,因为您正在将其写入
\0
字符)

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

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


另一方面,我不知道搜索以null结尾的字符串(使用
strchr(3)
)查找字符
'\0'
是否是未定义的行为,但如果它正确找到字符串终止符,您将很幸运,并且不会跳出
for
循环(
\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”
集合中,因此循环总是在开始时失败,使您在
i+1
位置写入一个
\0
(这是未定义的行为,因为您正在将其写入
\0
字符)

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

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


另一方面,我不知道搜索以null结尾的字符串(使用
strchr(3)
)查找字符
'\0'
是否是未定义的行为,但如果它正确找到字符串终止符,您将很幸运,并且不会跳出
for
循环(
\0
以某种方式存在于所有字符串中)正如手册中没有提到任何东西,也许有人可以从标准中说明。

这似乎是一种复杂的字符串串方法。只要循环是真的,两端都是。如果源和目的地重叠,则考虑使用MeMeTest.JoaCHIMPILBORG,我确实考虑了ISSLASE,但我想保持灵活性。将我选择的任何字符委派为空白。有点过于复杂,我放弃了对简单数组索引的解引用,例如arr[I]对不起,写
*(line+I)
而不是更可读的
行[I]的目的是什么
???多年来,它们一直被认为是编写相同内容的等效表单,您必须同意第二种表单更具可读性。@LuisColorado请查看我在您上方的评论。我确实在我的源代码中进行了更改,但根据您的反馈,我也在发布的代码中进行了更改,以避免进一步的评论这不是一个问题。谢谢。这似乎是一个复杂的字符串串的方法。只要循环是真的,两端都是。如果源和目的地重叠,则考虑使用MeMeSt.“JoaCHIMPILBORG,我确实考虑了ISStudio,但是我想保持将我选择的任何字符委派为空白的灵活性。omplex,我放弃了简单数组索引的解引用,例如arr[I]对不起,写
*(line+I)
而不是更可读的
行[I]
?多年来,它们被认为是写相同内容的等效形式,您必须同意第二种形式更真实