🌊

【C言語】私が使用しない関数

2024/09/01に公開

はじめに

バッファオーバーランを起こす可能性があるため、以下の関数は使わないようにしています。

使用しない関数

strcpy

形式

#include <stdio>
char *strcpy(char *s1, const char *s2);

概要

ヌル文字を含む文字列*s2を、文字型配列*s1にコピーします。
ヌル文字もコピーするので、*s1はその分の大きさも考えて大きさを宣言しなくてはなりません。

しかし、以下のようなプログラムを実行してみるとこの関数の罠に気付きます。

int main(void) {
    char text[5] = "abcd";
    char buffer[3] = "";

    strcpy(buffer, text);
    printf("bufferの値:%s", buffer);
}
bufferの値:abcd

bufferのサイズは3なので、2文字までしか格納できないはずなのに、出力結果は4文字になっています。つまり、バッファオーバーフローが発生しています。バッファオーバーフローとは、予約していないメモリ領域にアクセスすることです。

このプログラムは、動かしても特に例外が発生することなく終了します。
しかし、バッファオーバーフローによってメモリを破壊している事実は変わりありません。
大規模システムにおいてこのようなプログラムがあると、予期せぬタイミングでエラーが発生し、解析に大きな労力がかかります。

代替案

strcpyではなく、strcpy_sを使用するようにしましょう。
参考:C言語 strcpy_sへの移行【strcpyより安全なコピー方式】

strcat

形式

#include <string.h>
char *strcat

概要

文字列を連結(concatenate)します。
参考:C言語 文字列連結【strcat関数の使い方と2つの注意すべきこと】

sprintf

gets

※既に廃止されています。

gets(char *buffer)

標準入力ストリームstdinから複数バイトを読み取り、それをbufferで指定される配列に格納する関数です。配列に対して1文字も書き込まれなかった場合、または読み込みが失敗した場合は、空ポインタ(NULL)を返します。
しかし、getsは引数の限度を超えて文字入力できてしまいます。

代替案

fgetsやscanfで書き換えると記載されていますが、この2つの関数は仕様が大きく異なります。
fgetsはgetsと異なり、改行文字が含まれてしまう、また入力ストリーム上にバッファが残ってしまう。
そのため、fgetsをgetsの代替に使う場合は、バッファクリアをし、改行文字をヌル文字に置き換える処理が必要になります。

getsは、標準入力から1行を読み込み、引数に指定された変数に格納します。
さらに詳しくいうと、\n(改行文字)またはEOFに出会うと、末尾にヌル文字を追加して戻ります。

fgetsは「入力文字数+ \n(改行文字)+ \0(ヌル文字)」と扱うため、

  • getsの場合
char str[5];
gets(str);
  • fgetsの場合
char str[5];
fgets(str, 5, stdin);

int length = strlen(str); // strの文字数
if (str[length-1] == \n) {
    // 改行文字をヌル文字に変換
    str[length - 1] = '\0';
} else {
    // バッファクリア
    while (getchar() != '\n') {
    }
}

Discussion