• Tidak ada hasil yang ditemukan

計算機言語 I 第 10 回関数と配列 , ポインタ

N/A
N/A
Protected

Academic year: 2025

Membagikan "計算機言語 I 第 10 回関数と配列 , ポインタ"

Copied!
4
0
0

Teks penuh

(1)

計算機言語 I 10 回 関数と配列 , ポインタ

この資料: http://www.math.u-ryukyu.ac.jp/~suga/gengo/2022/10.pdf

レポートについて

今回のレポート問題にも関連しますが. ポインタ変数に対する足し算や引き算の結果は,「そのポインタ変 数が何を指しているか」で値が異なります. そうする理由は,プログラマに対して便利だからです.

変数のアドレス値も注意してほしいのですが,動作中のプログラムは, 247までのアドレスを取れるように見 えます. 現実には,このような大きなアドレスを持つほどのメモリを, PCは装備しておりません. みなさんが 利用しているシステムだと, 234くらいです. C の処理系やOSは, 247バイトのモリを使えるように,プログ ラマに見せているわけです. これを実現しているのが,「仮想記憶」というものです.

もちろん, OSが認識しているメモリ以上の記憶領域を要求するプログラムを走らせると, エラーが発生し て,そのプログラムは停止させられます.

1

(2)

配列型だけの特別扱い ( 教科書 p. 109, 配列と関数 )

今回は,ポインタの続きです.

Cには,char,intなどの基本変数型, ポインタ型, これらから派生する配列や構造体(後の講義で述べる) などの様々な変数の型があります. その中で,配列型だけが特殊な扱いを受けます. 前回述べた,

• 配列名の参照によってその配列の先頭要素へのポインタが得られる. は,そのひとつです. これ以外にも(上の言語仕様が理由で),

• 配列を代入によってコピーすることができない.

• 配列を関数の返り値にできない.

• 関数引数に配列を用いたときには,上の配列名参照によるポインタ渡しになる(教科書p. 109).

があります. 他の型(ポインタや構造体も)は上の3つが全てできますので,配列だけが何故か例外になってい ます.

このようになった理由は,おそらく次だと想像しますが, 何故そうなったかを記した文献を私は知りません.

• 配列のコピーは手間がかかり,プログラムの動作が遅くなる.

• 配列の先頭アドレスが配列名の参照で得られることに対する整合性

Cでは,関数を利用して配列の値を変更するには, 元の配列をそのまま利用するプログラムが基本となりま す. 上で述べたように, 配列のコピーは手間がかかるので, OS開発においてはそのような操作はできる限りし ないようにしたわけです. 同様のことは構造体でも起こり得るわけですが, こちらはそうしていないところが 謎なわけです. ちなみに,構造体を利用したプログラムにおいても,「構造体のコピー」を実行しているプログ ラムは多くありません. 配列の時と同じように,ポインタ経由の間接参照で「元の構造体の値を変える」とい う形のプログラムが通常です.

2

(3)

「関数に配列を渡すときには, ポインタ渡しになる」は,次の大きな欠点を持ちます.

• 配列(の先頭アドレス)を引数で受け取る関数は,元の配列の大きさがわからない.

Cでは,上のことはプログラマが責任を持つことになっています. ここを間違えると, 配列の境界を超えたメ モリにアクセスして,セグメント例外(Segmentation Fault)を起こすプログラムが出来上がります. 前回述べ た,「文法的には正しいが動かないプログラム」がここでも作成できてしまうのです.

セグメント例外(Secmentation Fault)は, プログラムが,メモリの中で参照できない場所(システムに より保護ざれていたり, 存在しなかったりする場所)を参照(読み書き)しようとした時に起こるシス テム上のエラーです. いまのOSでは,セグメント例外が起こると, そのプログラムの実行は中止され, OSからセグメント例外が起こったという通知が来るようになっています.

プログラム7. 6では,sizeof()を利用して配列の大きさを調べて, 関数にその大きさを渡しています. こ のように,配列引数があれば,何らかの形で配列の大きさを関数に渡すのが基本です.

sizeof()

sizeof()というのは, Cの処理系だけで意味を持つ関数で,その処理系での変数のメモリの利用量を出力

するものです. 現在ではほとんどの場合,その値は「バイト数」になっています.

多次元配列の関数引数

2次元配列の時に述べましたが,多次元の配列は,通常の(1次元)配列を途中で区切ったものです. 上で述べ たように, 関数に渡る際にはその先頭アドレスが渡ります. その時に,区切りの位置を関数に知らせないと,配 列の大きさがわからないのです. その知らせる方法が,教科書p. 111 です.

double func(double a[][4])

のような書き方,すなわち, 配列の次元の個数だけ[]を書き, 先頭以外の[]の中に配列のサイズを書き込む という形の記述が, プログラムの読みやすさでは良いと思います.

複雑な宣言の読み方

教科書p. 113に複雑な宣言の読み方があります. あまり凝った事をするとプログラムが読みづらくなるの

で,あまり複雑な宣言はしなくて済むようにプログラムを作るのが通常です. ここの例で重要なのは(割と出てくるのは),次の2つです.

double *hairetsu[4]; /* double 型へのポインタ変数 4つの配列, hairetsu[0] はポインタ値 */

double (*func)(int a); /* func は int 型を引数に持つ double 型を返す関数へのポインタ */

3

(4)

関数の値渡しと識別子のアドレス .

上で,関数へのポインタという言葉が出てきました. それを実際に見たプログラムが次です. Cでは, 識別子 (関数名や変数名)には,特別な例外を除いて, アドレス(ポインタ値)が実行時に定まっています. プログラム の実行結果を見ると,関数呼び出しが値渡し,すなわち,値のコピーが渡されていることもわかります.

次のプログラムでは,関数addの値を利用していません. Cでは「関数の値を利用しない」が文法上許され ています. これまでのプログラムでも, 例えば,printf()や scanf()は値を返す関数ですが,その値を利用 していません.

#include <stdio.h>

int add(int x, int y);

int main() {

int a=5;

int b=6;

printf("%p %p %p\n", &a, &b,&add);

add(a, b);

return 0;

}

int add(int x, int y) {

printf("%p %p\n", &x, &y);

return x+y;

}

レポート問題

締め切り6月27日(月) 10:00 JST,件名: gengo2022 report10-1

• sizeof を使ってchar,int, float, double,long double,long longとそれらのポインタ型の大き さを出力するプログラムを書け. さらにchar,double,long double,long longについては,前回の レポート問題であった, これらの配列の要素間のアドレスの差と, データ型のサイズが一致するかどう かをレポートせよ.

4

Referensi

Dokumen terkait

CPUが速くプログラムが小さいので, この講義でのプログラムでは気になりません が,大きなプログラム例えば, Firefox のようなグラフィカルなWeb ブラウザや, 画像編集ソフトでは,こ のような細かいチリが積もって山となります.. 分散の計算は, VX =EX2−EX2 を利用しますVXはX の分散,EX はX

bash-4.4$ ./a.out > input.data 前回のレポートができなかった人は, 上の解答例をコピー&ペーストでソースを作って,コンパイルして,上 を実行してください.. プログラムでのファイルの読み書き ここでは,

bash-4.4$ ./a.out > input.data 前回のレポートができなかった人は, 上の解答例をコピー&ペーストでソースを作って,コンパイルして,上 を実行してください.. プログラムでのファイルの読み書き ここでは,

bash-4.4$ ./a.out > input.data 前回のレポートができなかった人は, 上の解答例をコピー&ペーストでソースを作って,コンパイルして,上 を実行してください.. プログラムでのファイルの読み書き ここでは,

レポート問題 締切: 6月21日月 10:00JST, 件名: gengo2021 report 9-1 char, double, long double, long longのそれぞれの型に対して要素数が 2個の配列を作り,先頭と次 の要素のアドレス値を出力するプログラムを書き,先頭と次の要素のアドレスの差は幾つになったかをレポー

指定した教科書のプログラムは, 添字をずらすなどの操作が入っており,読みづらい https://github.com/okumuralab/algo-c/blob/master/src/matutil.c このソースを上で作った matrixというフォルダにダウンロードしてあるいは, Gedit を用いてプログラ

CPUが速くプログラムが小さいので, この講義でのプログラムでは気になりません が,大きなプログラム例えば, Firefox のようなグラフィカルなWeb ブラウザや, 画像編集ソフトでは,こ のような細かいチリが積もって山となります.. 分散の計算は, VX =EX2−EX2 を利用しますVXはX の分散,EX はX

次の Firefoxを閉じたときに Cookieとサイトデータを消去するにチェックを入れておくと, Firefox が原因で, Disk quotaが問題になることは無くなります... レポート問題では, ヘロンの公式を利用した関数を書いていただきましたが,エラー処理は,「面積の値とし てはあり得ない,