FukuRiko's WebSite

HOME | はじめに | プロフィール | フリーソフト | シェアウェア | Programming Tips | C言語 | 開発中のソフト
掲示板 | Blog | サイトマップ | 問い合せ | リンク

C言語ポイント学習

C言語初心者向けのページです。
づまづきやすい、「ポインタと配列」についてまとめてみました。
内容は少ないですが随時ふやしていきたいと思っています。
  1. 配列とポインタ(その1)
  2. 配列とポインタ(その2)
  3. 文字列・ポインタと配列
  4. 文字列と2次元配列
  5. 文字列の比較
【プログラムの拡張】  
前回の名簿のプログラムを少し拡張していきます。
今回は、ユーザから入力された名前が名簿に存在するかどううか?を
調べる機能を追加します。


                                   ・名簿
                                    ┏━━━━━━━━━━━━━━━━━━━━━┓
     ┏━━━━━━━┓ 問い合わせ  ┃Asano                                     ┃
     ┃              ┃─────→ ┃Fukushima                                 ┃
     ┃ 文字列の入力 ┃             ┃Furuichi                                  ┃
     ┃              ┃←───── ┃Hirao                                     ┃
     ┗━━━━━━━┛    結果     ┃Nanbo                                     ┃
                                    ┗━━━━━━━━━━━━━━━━━━━━━┛

文字列の入力は scanf関数 でしたね!
(まぁ、他にも文字列の入力を促す関数はあるのですがここでは scanf関数を使って話しを進めます)

例えば。

   例)文字列の入力を促すプログラム
  ┏━━━━━━━━━━━━━━━━━━━━━┓
  ┃  char buf[32];                           ┃
  ┃                                          ┃
  ┃  printf("名前を入力してください。> ");   ┃
  ┃  scanf("%s",buf);                        ┃
  ┗━━━━━━━━━━━━━━━━━━━━━┛

と、すれば、入力された文字列が 配列 buf に入ります。
ただし、入力文字数は ヌル文字が最後に入ることを考慮すると31文字以下。
32文字以上の文字を入力されると、配列をオーバーしてしまいプログラムが
暴走します。ここでは、32文字以上の入力は無いものとします。


 
文字列の比較  
 いきなりですが、回答例のプログラムです。

  例)名簿の内容を検索するプログラム 
      (左側の数字は行番号で、プログラムには関係ありません。)
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃01:#include <stdio.h>                                     ┃
┃02:#include <string.h>                                    ┃
┃03:                                                       ┃
┃04:void main()                                            ┃
┃05:{                                                      ┃
┃06:   char buf[32];                                       ┃
┃07:   int i;                                              ┃
┃08:   int flg;                                            ┃
┃09:                                                       ┃
┃10:   char* Meibo[5] = { "Asano"                          ┃
┃11:                    , "Fukushima"                      ┃
┃12:                    , "Furuichi"                       ┃
┃13:                    , "Hirao"                          ┃
┃14:                    , "Nanbo" } ;                      ┃
┃15:                                                       ┃
┃16:   printf("名前を入力してください。> ");               ┃
┃17:   scanf("%s",buf);                                    ┃
┃18:                                                       ┃
┃19:   flg = 0;                                            ┃
┃20:   for (i = 0 ; i < 5 ; i++)                           ┃
┃21:   {                                                   ┃
┃22:      if (strcmp(Meibo[i],buf) == 0)                   ┃
┃23:      {                                                ┃
┃24:         flg = 1;                                      ┃
┃25:         break;                                        ┃
┃26:      }                                                ┃
┃27:   }                                                   ┃
┃28:                                                       ┃
┃29:   if (flg == 1)                                       ┃
┃30:   {                                                   ┃
┃31:      printf("%s さんは名簿にあります!\n",buf);       ┃
┃32:   } else {                                            ┃
┃33:      printf("%s さんは名簿にありませんでした\n",buf); ┃
┃34:   }                                                   ┃
┃35:}                                                      ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛


このプログラムは大まかに分けると下記のようになります。

 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 ┃ 0. 使用する変数の宣言( 6 - 14 行目)                             ┃
 ┃ 1. ユーザに検索する名前を入力してもらう部分(15 - 17 行目)       ┃
 ┃ 2. 名簿から入力された名前が存在するか検索する部分 (19 - 27 行目) ┃
 ┃ 3. 検索結果の表示 (29 - 34 行目)                                 ┃
 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

 1.の名前を入力する部分は先ほど説明したので 2.の検索する部分から説明します。

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃18:               :                                       ┃
┃19:    flg = 0;                                           ┃
┃20:    for (i = 0 ; i < 5 ; i++)                          ┃
┃21:    {                                                  ┃
┃22:       if (strcmp(Meibo[i],buf) == 0)                  ┃
┃23:       {                                               ┃
┃24:          flg = 1;                                     ┃
┃25:          break;                                       ┃
┃26:       }                                               ┃
┃27:               :                                       ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

18行目からの抜粋です。最終的な検索結果を下記のように保持します。

 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 ┃ 入力された名前が見つかった       →  変数 flg を 1 にする。 ┃
 ┃ 入力された名前が見つからなかった →  変数 flg を 0 にする。 ┃
 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

プログラムでは見つかった場合に 変数flgを1にすれば良いので 19 行目で
変数flg を0にしています。

文字列の比較は 22行目で行っています。
ちなみに文字列の比較を行うときに

    例)間違った文字列の比較方法
   ┏━━━━━━━━━━━━━━━━━━┓
   ┃ if (Meibo[i] == buf)               ┃
   ┃ {                                  ┃
   ┃       :                            ┃
   ┗━━━━━━━━━━━━━━━━━━┛

とすることはできません。これだとポインタ(アドレス)どうしの比較になって
しまうからです。

  図は仮の番地で示したメモリイメージです。
 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 ┃                       ┌─ buf[32]には 入力した文字列が格納される。                      ┃
 ┃                       │                                                                 ┃
 ┃ アドレス   配列 buf      │           配列 Meibo                                            ┃
 ┃      ┏━━━━━┓   │         ┏━━━━━┓                                          ┃
 ┃ 1000 ┃   'x'    ┃ ←┘         ┣          ┫   ← Meibo[0] には 文字列 "Asano" の     ┃
 ┃      ┣━━━━━┫              ┣   100    ┫      先頭アドレスが入っている。          ┃
 ┃ 1001 ┃   'x'    ┃              ┣          ┫                                          ┃
 ┃      ┣━━━━━┫              ┣━━━━━┫                                          ┃
 ┃ 1002 ┃   'x'    ┃              ┣          ┫   ← Meibo[1] には 文字列 "Fukushima" の ┃
 ┃      ┣━━━━━┫              ┣   200    ┫                                          ┃
 ┃   :  ┃    :     ┃              ┣          ┫                                          ┃
 ┃   :  ┃    :     ┃              ┣━━━━━┫                                          ┃
 ┃      ┣━━━━━┫              ┃    :     ┃                                          ┃
 ┃ 1031 ┃          ┃              ┃    :     ┃                                          ┃
 ┃      ┗━━━━━┛              ┃          ┃                                          ┃
 ┃                                                                                          ┃
 ┃                                                                                          ┃
 ┃     ※ 例えば、buf == Meibo[0] をすると配列の中身ではなく                                ┃
 ┃        アドレスの比較(図では 1000 と 100 の比較)になってしまいます。                   ┃
 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

  文字列の内容の比較は strcmp関数を使って行います。
  この関数は string.h に定義されています。

実は、2行目で
 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 ┃ #include <string.h>                                      ┃
 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
としているのは strcmp 関数を使うための前準備なのです。
strcmp 関数の定義は下記のようになっています。

    strcmp 関数の定義
   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
   ┃ 文字列を比較します。                                                           ┃
   ┃                                                                                ┃
   ┃    int strcmp( char *string1, char *string2 );                                 ┃
   ┃                                                                                ┃
   ┃ 戻り値                                                                         ┃
   ┃    string1 と string2 を辞書式の順序で比較して、以下の関係を示す値を返します。 ┃
   ┃                                                                                ┃
   ┃  ┌──┬────────────────┐                                    ┃
   ┃  │ 値 │意味                            │                                    ┃
   ┃  ├──┼────────────────┤                                    ┃
   ┃  │ 負 │string1 が string2 より小さい   │                                    ┃
   ┃  ├──┼────────────────┤                                    ┃
   ┃  │ 0  │string1 と string2 は等しい     │                                    ┃
   ┃  ├──┼────────────────┤                                    ┃
   ┃  │ 正 │string1 が string2 より大きい   │                                    ┃
   ┃  └──┴────────────────┘                                    ┃
   ┃                                                                                ┃
   ┃ 引数                                                                           ┃
   ┃  string1、string2   比較する NULL 終端文字列                                   ┃
   ┃                                                                                ┃
   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

  このように、C言語に標準で実装されている関数群のこのと標準関数≠ニいいます。
  printf 関数や scanf 関数も標準関数≠フ一種なのです。#include  と
  最初に記述しているのは、printf関数やscanf関数を使用するための前準備だったのです。
  標準関数にはその機能に応じてカテゴリ分けされています。

  ┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
  ┃  主な関数                ┃必要なインクルードファイル    ┃
  ┣━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━┫
  ┃  printf関数,scanf関数 等 ┃stdio.h (標準入出力)         ┃
  ┣━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━┫
  ┃  strcmp関数 等           ┃string.h (文字列操作)       ┃
  ┣━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━┫
  ┃       :                  ┃             :                ┃


ソースの説明に戻ります。
strcmp 関数は比較した文字列が一致した場合に 0を返すので
if文で返り値を判定(22行目〜)し変数flg を1に設定し 
break(for文のループを脱出)しています。

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                      :                                  ┃
┃22:      if (strcmp(Meibo[i],buf) == 0)                   ┃
┃23:      {                                                ┃
┃24:         flg = 1;                                      ┃
┃25:         break;                                        ┃
┃26:      }                                                ┃
┃                      :                                  ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

そして最後にflgの値を判定して(29行目〜)検索結果を表示しています。
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                      :                                  ┃
┃29:   if (flg == 1)                                       ┃
┃30:   {                                                   ┃
┃31:      printf("%s さんは名簿にあります!\n",buf);       ┃
┃32:   } else {                                            ┃
┃33:      printf("%s さんは名簿にありませんでした\n",buf); ┃
┃34:   }                                                   ┃
┃                      :                                  ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛


以上で、プログラムの終了です。
プログラムのソースが入っていたので文章がちょっと長くなってしまいましたが
どうだったでしょうか?
for や break や if の構文を忘れてしまっていた人は
自分で復習してみてください!

あと、このプログラムは起動して検索が終わるとすぐに終わってしまいます。
余裕のある場合は、例のようにプログラムを拡張してみましょう。
きっと、今までの復習になると思います。

  プログラムの改良例)
 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 ┃・検索がヒットするまで終わらないようにする。                      ┃
 ┃・特定の文字列(end など)が入力されるまで終わらないようにする。  ┃
 ┃・検索時に大文字と小文字の区別をしないようにする。                ┃
 ┃                         :                                        ┃
 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛