joho1-2017の日記

joho1-2017の日記

情報処理実習1の解説ブログです.皆さんが課題を解く時の助けになれば幸いです.

データ型

第6回の6組の授業では,データ型について勉強しました.

我々人間と,コンピュータでは扱えるデータには違いがあり,これを理解せずプログラムすると,意図しないエラーが起こることもあります.
そして,これは経験上ですが,この手のエラーはコンパイルは通ってしまい,実行時に生じることが多々あり,デバッグが非常に厄介だったりします.今回の授業の内容は全て覚えるのはなかなか難しいですが,今後PCを使おうと思ってる人には是非知っていて欲しい内容です.

ビット(bit)とバイト(Byte)

コンピュータの記憶容量を数える際に使う単位で,ビット(bit)はその最小単位になります.そしてコンピュータは0と1の2値しか記憶しないので,1bitで表現できる数は,0か1になります.また,このbitを8つ集めたものをバイト(Byte)になります.

8bit = 1Byte
進数

我々が主に扱う0~9までの数字で数を表現するものを,「10進数」と呼びます.これに対し,コンピュータは0と1のみの「2進数」で記憶を行います.そして,あまり馴染みがないかもしれませんが,0~Fまでの「16進数」というものもあります.コンピュータの2進数を表記すると人間にはとても理解しにくいので,わかりやすい表現として16進数が扱われます.

変数

これまでの講義で扱ってきた変数も,割り当てられた要領だけメモリが確保されています.表は講義ページを参照してください.この事から,割り当てられた変数で表現できる以上の数を代入しても,正しい数は得られないため,エラーが起こります.しばしばエラーという形ではなく,正しくない数を返してくる事もあります.この場合は非常に厄介ですね...こんな事が起こらないようにするためにも,各変数に割り当てられたメモリのサイズ表は定期的に確認しておきましょう!

変数のスコープ,auto変数とstatic変数,グローバル変数は講義ページの通りです.長くプログラムを書く先輩としてアドバイスするならば,同一プログラム内に同名の変数があるのは,一部の例外(for文のカウンタ変数iなど)を除いて避けるべきです.例えそれがauto変数であっても,作った直後でない限り混乱しやすくなり,無駄にプログラムを読み返す時間を増やすことになるでしょう.

定数

変数と違って,値が変化しないものとして,定数がある.これらは講義ページにあるように,数値定数文字定数文字列定数と言うものがあります.ところで,この記事の最初の方で述べていますが,コンピュータは0か1しか記憶しません.なのに,文字を扱えるのはなぜでしょうか?
答えは,「文字を数で表現し,その数を記憶している」からです.そして,数と文字の対応を表にしているものがアスキーコード表なのです.この表は16進数で表現されていますが,これは1桁が4bit=

=16で表現されるため,16進数表記なのです.

型変換

(1)代入時の型変換
左辺と右辺の型が異なる場合,左辺の型に変換される.

int a;
double b = 3.14159265358;
a = b;         //これはint型に変換
実行結果:
3

(2)式中の変換
式中の型が異なる場合,制度の高い型に統一される.

精度高 double > float > long > int > char 精度低

(3)キャスト
型を一時的に強制変換できる方法もあります.

float x = 3.14159265358;
int y = (int)x;       //float型のxは一時的にint型に変換された!
独自の型作成

C言語では,ユーザ自身が独自に変数型を作成できる.これは後々プログラミングをとても楽かつ見やすくしてくれるものなので,是非覚えておいてもらいたい.書き方は講義ページを参照してください.

第6回の5組の授業では,配列について勉強しました.

学生の皆さんは,これまでのプログラミングで,何度も変数を宣言し,それらに値を代入するのは面倒だと思ったことはありませんか?
そして今後は,それではソースコードがとても長く,読み難くなる場合が出てきます.
こういった事を解決するものに,「配列」というものがあります.

1次元配列

配列とは変数のリストであり,1度で複数の変数を宣言できます(ただし,型が違う変数はそれぞれ宣言しなければならない).
1次元の配列は,

型 変数名[要素の個数];
 例: int days_of_month[12];

と宣言し,これにより,宣言した型の変数が要素の個数分生成されます(例だと,int型のday_of_monthという変数が12個生成された).
そして,これらの変数に値を代入したり,判定処理をするためにアクセスする時は,

month[0] = 31;

のように,変数名と何番目の要素にアクセスするのかを指定しなければいけません.注意すべき事として,

1.配列の宣言時に要素の個数がNならば,アクセスする時は0~(N-1)まで
//例  
int month[12];  //宣言が12個なら
month[0] = 1;
.
.
.
month[11]=12;  //アクセスは0~11まで
2.for文やwhile文などでまとめて値を代入する際,要素数以上の繰り返し処理をしてもコンパイルエラーは起きない
//例
int month[12];               //宣言は12個
for(int i=0; i<100; i++){  //要素数より多いループ回数!でもコンパイルは通ってしまう!
    month[i] = i+1;
}
3.まとめてのコピーは不可
int num1[12], num2[12];
num1 = num2;                 //これはできない!エラーになる.

1は宣言時とアクセス時で要素の扱う範囲が異なるように見えるので混乱しがちだが,アクセス時の[ ]内の数字は,最初の要素からのオフセットを表すので,1番目はオフセット0だし,今回の例の最期はオフセット11になるので,0~(N-1)となります.
2は実行して初めてミスに気付くとういう,かなり厄介なバグになるので,注意しましょう.
3は配列の特徴であり,C言語では対応していません.1つ1つに代入する事を意識しましょう.

配列とポインタの互換性は,ポインタを習っていない今解説しても混乱するだけなので,ここではしません.

多次元配列

実は1次元配列だけでなく,多次元配列も存在します.例えば2次元配列(3行5列)を作りたい場合,

int matrix[3][5];

と宣言する事で作成できます.
アクセスの場合,例えば1行目の3列目にアクセスしたい場合は,

matrix[0][2] = 12;

のように書きます.
三次元の時も,

int a[2][3][4];

のように,[ ]の数を増やす事で表せる.

 

以上で今回の講義のおさらいは終わりです.以下,各クラスの課題の考え方です. 

 

5組

1.キーボードから実数を10個入力し,全ての値を配列に格納し,そのなかの最大値,最小値を画面に表示せよ.

#include<stdio.h>

int main(void)
{
    const int N = 10;  /* 配列の要素数 */
    float data[N];     /* 実数10個分の配列 */
    
    .../* データ入力 */
    for(...)
        ...
    
    printf("最大値は %f \n", ... );
    printf("最小値は %f \n", ... );

    return 0;
}

この課題は練習問題2練習問題3を参考にすれば,簡単に解くことができると思います.
 ①実数型を用いること
 ②配列へのアクセス時は要素数番号は0~N-1であること
に注意しましょう.

2.キーボードから正の整数を10個入力し配列に格納し,そのなかから奇数の数をカウントして画面に表示せよ.
正でない整数が入力されたらエラーを表示して,正しい値が入力されるまで繰り返し再入力させよ.

実行例:
a[0]= 10
a[1]= -3
入力エラー! 正の整数を入力
a[1]= 0
入力エラー! 正の整数を入力
a[1]= 5
a[2]= 100
a[3]= 2
  .
  .
  .
a[9]= 10

奇数は 4 個ありました.

この課題のポイントは,
 ①入力された数が正の整数か判定
 ②奇数の判定
です.①はdo-while文で入力されるたびに判定すれば良いでしょう.もちろん他の方法でも構いません.②は2で割り切れるか判定すれば良いだけですね.

3.キーボードから 2 以上の整数を10個入力し,その中の素数の個数を数え表示するプログラムを作成せよ.

実行例:
a[0]= 10
a[1]= 1
入力エラー! 2以上の整数を入力
a[1]= 5
a[2]= 11
a[3]= 2
  .
  .
  .
a[9]= 10;

素数は 2, 5, 11 の 3 個ありました.

この課題のポイントは,
 ①入力された数が2以上の整数か判定
 ②素数の判定
①は2と同様にdo-while文で判定できますね.②に関してですが,素数とは,条件「1とその数自身以外の数では割り切れない数」を満たす数のことですね.と言うことは,入力された数nを1からnまで割っていき,余りが0になる数をカウントしていき,上述の条件を満たす時,素数であることを示す返り値を与えれば良いわけです.

<4.キーボードから10個の整数を配列に入力し,1.まず配列の全要素を画面に表示,2.次に大きい順に並べ替えて表示せよ.
ヒント(各自で調査せよ):ソーティング,アルゴリズム,単純ソート,挿入ソート,バブルソートヒープソートなど

a[0]= -2
a[1]= 1
a[2]= 11
a[3]= 2
  .
  .
  .
a[9]= 10;

並べ替え前:-2 1 11 2 ... 10
並べ替え後:11 10 ... 2 1 -2

この課題のポイントは,
 ①配列の並べ替え
です.様々なやり方があると思いますが,配列の要素番号の隣同士を比較して,要素番号が小さい方の中身の数が小さければ大きい方と入れ替える,という作業を要素数だけ繰り返せば,最終的にできた配列は大きい順に並び替わります.これには繰り返し処理のネストが必要になりますね.

5.整数型配列の各要素を全て絶対値に変換して,変換前後の配列の中身をそれぞれ表示せよ.

#include <stdio.h>

int main(void)
{
    const int N = 10;
    int a[N] = {3, -4, -9, 10, -5, 6, 2, 0, -9, 5};   /* 数値は例.値を書き換えても正しく動作すること. */

    ...

    return 0;
}
実行例: 変換前:3, -4, -9, 10, -5, 6, 2, 0, -9, 5
     変換後:3, 4, 9, 10, 5, 6, 2, 0, 9, 5

この課題のポイントは,
 ①整数を絶対値にする
です.C言語には絶対値を計算する関数というものがあります.詳しくは「C言語 絶対値」などでググるとでてきます.この時,いつものstdio.h以外にも他のヘッダーファイルをインクルードしないといけないことにも注意しましょう.
ただ,簡単な条件判定で解くことができるので,わざわざ使う必要はありません.

 

 

6組

1.QUIZ1,2,3 を参考にして,入力した文字が大文字であれば小文字に変換し, 小文字であれば大文字に変換するプログラム作成しなさい. また入力は半角文字のみとする. キー入力と表示以外は組み込み型の関数は使わずに実現して下さい.

実行例:
文字を入力して下さい: M
m
文字を入力して下さい: e
E
文字を入力して下さい: i
I
文字を入力して下さい: j
J
文字を入力して下さい: I
i

この課題のポイントは,
 ①大文字と小文字の認識
です.QUIZ1~3を参考にすればいいので,アスキーコード表を使うことは自明ですね.そしてアスキーコード表を見ると,同じアルファベットの大文字と小文字は下位4bitは同じですね.つまり,上位4bitに対して何かしらの条件処理をすれば,小文字->大文字,大文字->小文字の変換はできますね.

2.QUIZ4を参考にして,一桁の自然数(数値)を引数にとり,文字(数字)を返す関数 toascii() を作れ. 但し変換にprintfなどを用いてはならない.

char toascii(int number)
{
    // write your code down here.
}

int main(void)
{
    for(int i=0; i<10; i++){
        char c = toascii(i);
        printf("%c",c);
    }
    printf("¥n");
}

この課題のポイントは,
 ①数字から文字への変換
です.QUIZ4において,文字としての数字(0x30~0x39)を数値(0~9)に変換はできましたね.そして,その時に,関数atoi( )では,引数に対してどんな処理がされていますか?今回の問題はその逆をやればいいだけですね.

3.QUIZ5 を参考にして,2点の三次元座標A(x,y,z),B(p,q,r)を入力すると,内積を計算する関数 dot_product()と, 外積を計算する関数 cross_product() を作成せよ.

この課題のポイントは,
 ①独自の変数型作成
 ②内積外積計算

です.①はQUIZ5と全く同じで大丈夫なので,省略します.②は,QUIZ5の関数add( )の中身を内積外積の式に則って計算するよう書き換えれば解けますね.

以上で課題の考え方について終わりです.
もう授業では何も言いませんが,命名規則守ってください! 何人か未だに守れていない人がいます.

 

Remove all ads