strncpy 的用法

在官方的文档中,http://www.cplusplus.com/reference/cstring/strncpy/,例程的 strncpy 的用法是:

/* strncpy example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str1[]= "To be or not to be";
  char str2[40];
  char str3[40];

  /* copy to sized buffer (overflow safe): */
  strncpy ( str2, str1, sizeof(str2) );

  /* partial copy (only 5 chars): */
  strncpy ( str3, str2, 5 );
  str3[5] = '\0';   /* null character manually added */

  puts (str1);
  puts (str2);
  puts (str3);

  return 0;
}

注意到第 12 行,最后的参数是直接 sizeof,这样虽然可以防止溢出,但是其实还是 printf strlen 之类的不安全的,看看这个例子:

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

int main() {
    char str[3];
    memset(str, 0, sizeof(str));
    strncpy(str, "testtest", sizeof(str));
    printf("[%s][%d]\n", str, strlen(str));
    return 0;
}

看看输出:

$ ./a.out 
[tes][6]
$ ./a.out 
[tesx][6]
$ ./a.out 
[tesn][6]
$ ./a.out 
[tes][6]
$ ./a.out 
[tes€][6]
$ ./a.out 
[tes*][6]
$ ./a.out 
[tes¡][6]
$ ./a.out 
[tesP][6]
$ ./a.out 
[tes][6]

可以看到,最后那个 char 是不确定的,而且 strlen 也出错,那么,稳妥的做法应该是 -1

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

int main() {
    char str[3];
    memset(str, 0, sizeof(str));
    strncpy(str, "testtest", sizeof(str)-1);
    printf("[%s][%d]\n", str, strlen(str));
    return 0;
}
$ ./a.out 
[te][2]
$ ./a.out 
[te][2]
$ ./a.out 
[te][2]
$ ./a.out 
[te][2]

这样才能有稳定的输出


历史评论

ZRJ (2013-09-29 21:13:02):

而另外,snprintf 则不需要 - 1

ZRJ (2014-01-27 17:17:24):

http://stackoverflow.com/questions/12275381/strncpy-vs-sprintf

使用 Hugo 构建
主题 StackJimmy 设计