snprintf()にハマる

C言語の初心者にありがちなミスです.
sprintf()という関数が教科書に書かれていますが,バッファオーバーランを防ぐために,現在ではsnprintf()を使うことが推奨されています.

  • sprintf()の例
#include <stdio.h>
#include <string.h>
int main()
{
  char buf[]="abc";
  sprintf(buf,"123456");  /* <---- バッファオーバーフロー */
  printf("%s\n",buf);
  return(0);
}
  • snprintf)の例
#include <stdio.h>
#include <string.h>
int main()
{
  char buf[]="abc";
  snprintf(buf,3,"123456");  /* <---- バッファオーバーフロー防止 */
  printf("%s\n",buf);
  return(0);
}

ところが,「"abc"と3文字分のバッファを用意したから,123と表示されるはず,と思っても,表示されません.
snprintf()の書き込み文字数指定には,文字列末尾の'\0'もカウントしなければならないからです.
「buf[]="abc"」だと,4バイト確保しているので,文字列長は3じゃなくて4を指定しなければなりません.また,わざわざ数える必要もなくて,

  • 正しいsnprintf)の例
#include <stdio.h>
#include <string.h>
int main()
{
  char buf[]="abc";
  snprintf(buf,sizeof(buf),"123456");  /* <---- バッファオーバーフロー防止 */
  printf("%s\n",buf);
  return(0);
}

でよろしいです(strlen()は'\0'はカウントしませんが,sizeofは'\0'もカウントします).