Lecture 10 ポインタ

Assignment(課題)10(以下の手順に則り提出して下さい)

【課題提出における注意】
  • すべてのプログラムは,必ずコンパイル&実行し,正しく機能することをチェックしてから提出すること.
  • プログラムは正しくインデントさせること.


    1. キーボードから一文字ずつ入力し,その文字をそれまで入力した文字列の 最後に追加するプログラムを作りなさい.文字列の最後を覚えておくポインタを 用いなさい.一文字ずつ入力する度に画面に文字列を表示し,10文字入力した時点で終わること.
      プログラムのファイル名を学籍番号10桁-10-1.cppとせよ.

      実行例

      $ catchar
      > M
      M
      > e
      Me
      > i
      Mei
      > j
      Meij
      > i
      Meiji
      >  
      Meiji 
      > U
      Meiji U
      > n
      Meiji Un
      > i
      Meiji Uni
      > v
      Meiji Univ
      

      【ヒント】
      キーボードから一文字をうまく入力するには, 以下の様に,改行文字を読み飛ばす必要があります.
      char moji;
      scanf("%c%*c",&moji);
      

      解答例 A10-1



      解説

      • 文字列を格納するバッファを用意します(6行目).
      • 文字列を示すポインタを用意し,上記バッファの先頭アドレスで初期化(7行目)
      • そのポインタの位置に一文字を入力(11行目).入力後にポインタを移動.
      • 文字列として完成させるために終端文字をセット(12行目)
      • 繰り返す



    2. 文字列の中をスキャンして,キャラクタコード番号の 小さい順に1文字ずつ拾い,画面にプリントするプログラムを作りなさい. 表示するタイミングは,上記の10文字入力が終わった後(最後)とする. ソートを使わず,あくまでポインタを使ってスキャンして実現してください. プログラムのファイル名を学籍番号10桁-10-2.cppとせよ.

      実行例

      $ seekchar 
      Keyin some words: 09876 432 asdf kl;:
      Input:09876 432 asdf kl;:
      Output:   02346789:;adfkls
      

      解答例 A10-2



      解説

      • strに格納されている文字列から,文字をコード表順に探して行き, 見つけたら新しい文字列変数destに入れていきます.
      • 文字コード順に(目で読める文字がある範囲は0x20〜0x7F)スキャンします(8行目)
      • str中にその文字コードがあるか,先頭から最後までスキャンして探します.
      • 見つけたらdestにコピーします.その後ポインタを一つ動かします. 「*dest++ = c;」という表現は,*destにcを代入してから,destポインタを一つ動かす,という操作です.



    3. 入力した文字列の中から英数字以外の文字(記号)のみを表示するプログラムを作成せよ. ただし,文字列のスキャニングにはポインタを用いること. また,配列の要素を示す括弧( [ ] ) は定義のとき以外で使用しないこと.
      プログラムのファイル名を学籍番号10桁-10-3.cppとせよ.
      void input(char* st){ 
          printf("文字列を入力: "); 
          scanf("%[^\n]",st); 
      } 
      
      int main(void)
      {
          char str[100], dest[100];
          input(str);
          search_symbols(dest,str); 
          printf("%s¥n",dest);
      }

      //実行例 
      文字列を入力: C++ & 'Oh-o!' "Meiji!" No.1; 
      記号: ++ & '-!' "!" .;
      

      解答例 A10-3



      解説

      • 記号とは,英数字以外のことなので,英数字を見つけます.
      • 英文字だけに反応する isalpha(), 数字だけに反応する isnumber() をそれぞれ作ります.
      • 2つを複合して isalnum() を作ります.
      • isalnum()を用いて,それ以外のものをコピーし(18-19行目),



    4. ポインタの2次元配列を用いて, 月の英語名称,和名のデータテーブルを作り, 月の番号(1,2,・・・,12)を入れると英名と和名が, 英名を入れると月番号と和名が表示されるようにせよ. また,存在しない月番号や英名を入力すると,誤りを指摘するようにエラー処理を行え.
      プログラムのファイル名を学籍番号10桁-10-4.cppとせよ.
      char* month[][2] = {
          {"January", "睦月"},
          {"February", "如月"},
          {"March", "弥生"},
          {"April", "卯月"},
          {"May", "皐月"},
          {"June", "水無月"},
          {"July", "文月"},
          {"August", "葉月"},
          {"September", "長月"},
          {"October", "神無月"},
          {"November", "霜月"},
          {"December", "師走"}
      };



      解答例 A10-4


      解説

      • 難しいことはせず,月番号の入力(L.86)と月e名称の入力(L.89)とは分けました.
      • 月番号の入力関数(L.32)は,1-12の番号を入力させ,それ以外ならやり直させます. ただし,重要なのは,データベース中の番号は0-11なので,その違いはこの関数の中で解消します (つまりこのプログラム中では常に0-11で取り扱う戦略).
      • print_a_month()関数は,同名で2種類あります.同名の関数が作れる機能はC++の特徴です (純粋なC言語の処理系では関数名はユニークである必要がある).関数の名称が同じ場合,引数 は異なっている必要があります.
      • 月e名称で検索する関数(L.48)は,e名称を入力したあと,データベースにあるどのe名称と 合致するかを探索します(ismonthname関数).ただ,配列が0始まりであることが災いして, falseを0として扱うことができず,-1としています.とてもトリッキーでわかりにくいので, 本来は月番号と配列番号は合わせた方が良いかも知れませんね(0は使わない). すなわち,以下のように変更するとわかりやすくなります.
        char* month[][2] = {
            {"dummy", "ダミー"},	// ここはダミーで使用しない.
            {"January", "睦月"},
            {"February", "如月"},
            {"March", "弥生"},
            {"April", "卯月"},
            {"May", "皐月"},
            {"June", "水無月"},
            {"July", "文月"},
            {"August", "葉月"},
            {"September", "長月"},
            {"October", "神無月"},
            {"November", "霜月"},
            {"December", "師走"}
        };






    5. 文字列をキーボードから istr に入力し, 大文字を抜き出す関数 find_capital(), 小文字を抽出する関数 find_small() を作成せよ.
      抽出した大文字の文字列は cstr に,小文字の文字列は sstr に それぞれ格納し,画面に出力せよ. 但し,配列へのアクセスはポインタを用いること. また,string.h に用意された関数を用いてはならない.
      プログラムのファイル名を学籍番号10桁-10-5.cppとせよ.
      void input(char* str) {
          printf("文字列入力:"); 
          scanf("%[^\n]",str); 
      }
      
      int main(void)
      { 
          char istr[100] = {0};
          char cstr[100] = {0};
          char sstr[100] = {0};
      
          input(istr);
          
          // ... ここを作る! 但しここで処理は行わず,自作の関数をコールすること。
      
          printf("Input string: %s\n", istr);    
          printf("Capital  letter string: %s\n", cstr);    
          printf("Smallcap letter string: %s\n", sstr);    
      }
      

      解答例 A10-5


      解説

      • find_capitalができれば,find_smallはほぼ同じなのでできますね.
      • src(istr)をスキャンして,大文字を探します(L.12-18). 見つかったらdestにコピー,大文字でない文字は読み飛ばします(L.17).