strncpy函数的循环没看懂

The loop of the strncpy function is not understood

char *strncpy(char *dest, const char *source, size_t n) {
  char *start = dest;

  while (n && (*dest++ = *source++)) n--;
// I don't understand from the code below this
// I know I put'[=10=]' at the end of dest.
// But I don't know how if (n) while (--n) works.
  if (n) while (--n) *dest++ = '[=10=]';
  return start;
}

http://www.jbox.dk/sanos/source/lib/string.c.html#:38

这个循环

while (n && (*dest++ = *source++)) n--;

条件表达式中有两个子表达式。

第一个是子表达式n,可以等价重写为n != 0

因此,如果 n 不等于 0,则计算第二个子表达式 (*dest++ = *source++),将指针源指向的字符复制到指针 [=16] 指向的目标数组的元素=].

你可以对这个子表达式进行成像

(*dest++ = *source++)

如下操作顺序

( *dest = *source++, *dest++ != '[=12=]' )

表达式的结果是被复制字符的值。因此,如果复制的字符不是终止零字符 '[=17=]',则子表达式的逻辑值为真。否则为假,因为等于零 ('[=18=]').

因此此循环要么复制 n 个字符,要么如果遇到零字符,则此零终止字符之前的所有字符包括零终止字符本身。

下一个循环向目标字符串附加零,直到表达式 --n 等于 0。

该函数在处理 n 的值时有点混淆。

但是,我想您知道 if (...) { something; } 的工作原理,如果里面只有一个语句就不需要大括号?

if (n) while (--n) *dest++ = '[=10=]';

只是一个 while 嵌套在 if 中,它与:

完全相同
if (n) {
   while (--n) {
      *dest++ = '[=11=]';
   }
}

第一个 while 循环最多复制 n 个字符,从 sourcedest。此循环在 n == 0(*dest++ = *source++) 计算结果为 NUL ('[=16=]') 时停止,这意味着已找到源字符串的末尾。

然后测试n看是否还有预期的操作——也就是说,调用者希望复制更多的字符,但是source字符串提前结束。第二个循环通过放置 NUL 字节来实现这一点,填充 dest 以匹配 n.

的大小

此代码的风格决定使新手开发人员难以阅读。通过美化器快速 运行 给出了这个结果(添加了我自己的评论)。

//takes a destination string, a source string, and a size (count) of characters to copy
char * strncpy(char * dest, const char * source, size_t n) {

  //create a pointer to the start of the destination string
  char * start = dest;

  //run this loop until one of two things happens: 
  //- n hits 0, meaning we've copied the required number of characters
  //- the assignment operator '=' returns '[=10=]', indicating that we've just copied
  //  a '[=10=]' into dest - this means we've hit the last character in source.
  while (n && ( * dest++ = * source++)) {
    n--;
  }

  //this checks to see if n still has leftover value - if it does, it means that
  //source had fewer characters than we were asked to copy
  if (n) {
    //we will now go through the remaining characters and pad the returned string
    while (--n) {
      //add '[=10=]' to the return string
      * dest++ = '[=10=]';
    }
  }

  return start;
}