【C言語 strstr】文字列検索関数を使ったNGワード検索プログラムの実装

最終更新日 2025年11月15日

■この記事の概要

この記事では、C言語のstrstr関数を使って、ソースコード内のNGワード(不適切な変数名やコメントなど)を検出するプログラムの実装方法を紹介しています。

問題となるワードを定義した構造体を用いて、ファイル内の行ごとにNGワードをチェックし、得点化して出力する仕組みを解説しています。


■strstr関数の基本的な使い方

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

int main(void) {
    char str[] = "〒100-8111 東京都千代田区千代田1−1";

    // 指定文字列(東京都)での文字列検索
    char *p1 = strstr(str, "東京");
    puts(p1 != NULL ? p1 : "検索結果無し");

    char *p2 = strstr(str, "大阪");
    puts(p2 != NULL ? p2 : "検索結果無し");
}
./a.out
東京都千代田区千代田1−1
検索結果無し

strstr関数とは文字列を検索する関数です。
このコードは東京と大阪を検索した例です。

strstr関数は検索文字列が見つからないと
NULLを返すので必ずNULLチェックをして下さい。


■NGな変数名とは

ここでは、
ソースコードの中からNGワード
(NGな変数名やNGなコメント)を
検索するプログラムを考えてみましょう。

➡while(roop)
入社以来一度もレビューを受けていない

➡for(int loop_counter=0;
局所変数でもなんでもかんでも長い名前

➡int 何とか2;
info2,data2,flag2等の付加情報を持たない変数名の乱用
そもそも
情報でない変数とか
データでない変数とか、あるか?

■NGなコメントとは

➡/* 多分はずかも*/
確認していない。自信のない。

➡//開放
筆者経験で100%「解放」の間違い

strstr関数を使ったNGワードを検索するプログラム

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//日本人が書いたソースコードのレビューツール
//問題のありそうなコードを手っ取り早く見つける
//使い方:
//  $./a.out  ../*/*.c ../*/*/*.c 

struct {
    const char  *駄目語;  
    int         減点;       //点数が高いほど駄目
} 駄目語録[]={
    //駄目な変数名
    {"roop",            1000},  //誤字⇒一度もレビューを受けていない
    {"loop_counter",    200},   //局所変数に長い名前は読みにくい   
    
    //付加情報を持たない変数名
    // これらの変数名は読み手には意味が無い。
    //”何とか2”があるという事は”何とか1”もあり
    {"var2",            10},          
    {"info2",           50},
    {"data2",           100},
    {"flag2",           500},
    {"tmp2",            10},        
    
    //駄目なコメント
    {"Todo",            10},    //受け入れ試験直前で残っているのはオカシイ
    {"多分",            50},    //断定してください
    {"はず",            50},    //断定してください
    {"かも",            50},    //断定してください
    {"開放",            200},   //誤字:X資源の開放⇒〇資源の解放 
    
    {NULL,              0}
};
static int 行検索(char *source){
    int 減点 = 0 ;
    for(int i = 0; 駄目語録[i].駄目語 != NULL;i++){
        if(strstr(source,駄目語録[i].駄目語)){
            減点 += 駄目語録[i].減点 ;
            printf("\t%4d点:%-16s\t:%s",
                駄目語録[i].減点,
                駄目語録[i].駄目語,
                source
            );
        }
    }
    return  減点 ;    
}
static int ファイル検索(char *filename){
    FILE *fp = fopen(filename,"r");
    if(fp == NULL){
        perror(NULL);
        exit(1);
    }
    int 減点 = 0;
    char    source[BUFSIZ];
    while(fgets(source,BUFSIZ,fp) != NULL){
        減点 += 行検索(source);
    }
    fclose(fp);
    return  減点 ;
}
int main(int argc,char *argv[]){
    if(argc < 2){
        printf("Usage:./a.out f1.c f2.c ....\n");
        exit(1);
    }
    for(int i = 1;i < argc;i++){
        printf("▼解析開始:%s\n",argv[i]);

        int 減点 = ファイル検索(argv[i]);
        if(減点){
            printf("%d点 %s の解析終了▲\n",減点,argv[i]);
        }
    }
}
./a.out  bug.c
▼解析開始:bug.c
        1000点:roop             :    {"roop",            1000},  //誤字⇒一度もレビューを受けていない
         200点:loop_counter     :    {"loop_counter",    200},   //局所変数に長い名前は読みにくい
          10点:var2             :    {"var2",            10},
          50点:info2            :    {"info2",           50},
         100点:data2            :    {"data2",           100},
         500点:flag2            :    {"flag2",           500},
          10点:tmp2             :    {"tmp2",            10},
          10点:Todo             :    {"Todo",            10},    //受け入れ試験直前で残っているのはオカシイ
          50点:多分             :    {"多分",            50},    //断定してください
          50点:はず             :    {"はず",            50},    //断定してください
          50点:かも             :    {"かも",            50},    //断定してください
         200点:開放             :    {"開放",            200},   //誤字:X資源の開放⇒〇資源の解放
2230点 bug.c の解析終了▲

駄目語録[]の単語は開発環境で異なります。
ご自身の環境に応じて追加削除してください。

参考:「はず/かも」チェック