[TA] C言語: 課題プログラムの修正

[TA] C言語: 課題プログラムの修正 - TODO

提出してもらったプログラム

以下に,提出してもらったプログラムを示します.

#include <stdio.h>
#include <string.h>
#define N 10

struct card {
   char *name;
   int age;
};

struct card meibo[N] = {
   "Takahashi", 14,
   "Kobayashi", 15,
   "Hosokawa",  17,
   "Sugimoto",  18,
   "Sawai",     19,
   "Itou",      20,
   "Kawai",     22,
   "Ishikura",  24,
   "Oda",       25,
   "Nakamura",  28
};

int main(void) {
   int i;
   char* str1;
   char* str2;
   char *name;
   printf("name? : ");

   while (scanf("%s",name) != EOF) {
      for(i=0;i<=10;i++) {
         char* str1 = name;
         char* str2 = meibo[i].name;
         if(strcmp(str1,str2)==0) break;
      }

      if (strcmp(str1,str2)==0) {
         printf("name:%s age:%d\n",meibo[i].name,meibo[i].age);
      } else{
         printf("not found\n");
      }

      return(0);
   }
}

セグメンテーション違反の原因となりそうな箇所は2つあります.

  1. main関数内で宣言されるstr1,str2,nameに領域を割り当てていない
  2. main関数内,探索を行うfor文の実行条件が「i<=10」となっている
    • 0から10まで,合計で11回ループすることになる

他に目に付いた問題点を列挙します.

  • main関数に対するreturnがループ内にあるため,いかなる場合もwhileループは1回しか回らない
  • main関数の先頭で宣言したstr1とstr2を,探索を行うfor文の中でさらに宣言している
    • この副作用により,for文終了時にstr1とstr2はメモリから消える恐れがある

修正案

以下にプログラムの修正案を示します.解説は後述します.

#include <stdio.h>
#include <string.h>
#define N 10

struct card {
   char *name;
   int age;
};

struct card meibo[N] = {
   "Takahashi", 14,
   "Kobayashi", 15,
   "Hosokawa",  17,
   "Sugimoto",  18,
   "Sawai",     19,
   "Itou",      20,
   "Kawai",     22,
   "Ishikura",  24,
   "Oda",       25,
   "Nakamura",  28
};

int main(void) {
   int i;
   char name[20];

   printf("name? : ");

   while (scanf("%s",name) != EOF) {
      for(i=0; i<N; i++) {
         printf("  process: compare %s with %s\n", name, meibo[i].name);
         if(strcmp(name, meibo[i].name) == 0) break;
      }

      if (i == N) {
         printf("not found.\n");
      } else {
         printf("found !\n");
         printf("%s is %d years old.\n", meibo[i].name, meibo[i].age);
      }

      printf("name? : ");

   }

   return(0);
}

修正点を列挙します.

  • for文の実行条件を「i<=10」から「i<N」に変更した.「=」をつけるのは間違い.また,トップレベルで定義したNを用いるべき.用いないのならNを定義する意味がない</li>
  • 文字列型変数str1とstr2を削除した.不必要な変数はなるべく宣言しない
  • main関数のreturnをwhileループの外に出した.これでCtrl+Dが入力されるまで探索できるようになる
  • 「name? :」と問い合わせを表示する処理をwhileループ内に追加した.2度目以降の探索時にも表示がなされる
  • 見つかったか見つからなかったかの判定に「i == N」を利用するようにした.for文を抜けるパターンは2パターンで,見つかってbreakするか,最後まで探索して見つからないかのどちらか.見つからなかった場合,iは必ずNであることに気付いてほしい
[Good Job!]