• Tidak ada hasil yang ditemukan

計算機言語 I 第 13 回 動的なメモリの確保

N/A
N/A
Protected

Academic year: 2024

Membagikan "計算機言語 I 第 13 回 動的なメモリの確保"

Copied!
5
0
0

Teks penuh

(1)

計算機言語 I 13 動的なメモリの確保

この資料: http://www.math.u-ryukyu.ac.jp/~suga/gengo/2023a/13.pdf

レポートへのツッコミ

2乗を計算するのにライブラリ関数pow()を使う人がいますが, 2乗くらいだと積を,つまりa2の計算を, a*aと書くのが普通です. 関数呼び出しは,幾らかの処理(前処理,後処理)をプログラムに要求しますが,a*a は,即座に計算できます. CPUが速くプログラムが小さいので, この講義でのプログラムでは気になりません が,大きなプログラム(例えば, Firefox のようなグラフィカルなWeb ブラウザや, 画像編集ソフト)では,こ のような細かいチリが積もって山となります. もちろん, 100乗を計算するときには,pow()を使います. 「臨 機応変」を意識してください.

分散の計算は, V(X) =E(X2)−E(X)2 を利用します(V(X)はX の分散,E(X) はX の平均). 分散の 定義式E((X−E(X))2)では,平均を計算した後で,再びデータを最初から読んで足し算しなければなりませ んが,E(X2)−E(X)2ではそれをする必要がありません.

絶対評価で, 20で割った商の値score/20で評価点A, B, C, D, Eを決める方法では, 100点満点の時の商 が5 になることを忘れてはいけません. 例えば,次のような初期化をしておかないと, 100点の人に対する評 価はおかしくなります.

char estimate[] = "EDBCAA";

今回,「明らかにきちんと動作しないプログラム」と「何をプログラムしたのかわからないもの」がありまし た. プログラムを書いたら,必ず実行して何が起こるかをチェックしてください. これは,プログラミングの基 本中の基本です.

動的なメモリ確保 ( 教科書 10 章 )

今回の内容は割に難しいとされる事です. 少し,細かい話をします.

プログラムには, 実行時にならないとデータの大きさが決まらないことがよくあります.

例えば, この講義で使っているテキストエディタですが, どのくらいの大きさのファイルを編集するのかは, 実行するまでわかりませんし, 入力をどんどんしていくと必要なメモリもどんどん増えていきます. テキスト エディタの最初の回(情報科学演習)のときに述べましたが,入力画面に表示されている内容は, 一次記憶装置

(2)

求してもらってくる」という動作の事です. 実用的なプログラムを作成しようとすると,このような仕組みが 必要であり,そのプログラムを記述するプログラミング環境も, このような仕組みが利用できるようにしてあ ります. 今回は, Cにおけるその仕組みの使い方です.

これまででは,「変数宣言」という形で, プログラム内では必要なメモリを確保してきました. しかし,これ までのメモリ確保の方法は,プログラム実行前に必要な変数の量が決まっているときだけです.

ポインタの復習

動的なメモリの確保では,ポインタを多用します. ポインタについてもう一度復習します.

Cのプログラムでは,一部の例外を除いて,識別子(名前,関数や変数の名前のこと)には,実行時に一次記憶 内でのアドレスが付与されることになっています. 実行時に定まる識別子のアドレスのことを,その識別子へ のポインタ(pointerは何かを指し示す物という意味の英語)と言います.

アドレス演算子&は,識別子に作用させることができ,その値は,その識別子を指すポインタになります. Cでは,ポインタ(アドレス)の値を保持するための変数型,「ポインタ型」を使うことができます. 例えば,

double *dp;

という宣言は, 次のように読みます. (下で「アクセス」と書いてある部分は, 代入や値を取り出すという意味 です.)

• dpはポインタ(アドレス)の値を保持するための変数であり,この識別子でアクセスできる値は,何らか のアドレスである. また,この宣言で定義されるのはdpという変数である.

• *dpという形でアクセスを行う際には, dpの値が指すの場所には, double型の値を保持するだけのメ モリがすでに確保されており,アクセスできる値は,その場所にあるdouble型の数値である. *dpとい う変数の宣言ではない.

上の事から, ポインタ型変数に対する * をdereference operater(意訳して間接参照演算子)と言ったりしま す. ポインタ値(アドレス値)を参照(refer)して,その場所にある値をアクセスするからです.

上の宣言では, dpには, アドレスとしての意味を持てば, (例えば符号無し整数値を)代入することができま す. 従って,プログラム的にアクセス出来ない場所の値をdpに代入しても,「文法エラー」にはならず,「実行 時エラー」になります. また, このようなプログラムでも,実行時エラーが発生しないこともあり, 「隠れたバ グ」がプログラムに残ることも,数多く発生しています. これは, OS開発用に作られたCの仕様(特徴)であ り,プログラマがその辺の責任を持つ必要があります.

2

(3)

これまでの事に関する補足

NULLポインタ. Null Pointer(ナルポインタ, ヌルポインタ)と呼ばれるもので, 「何も指していないという

ことが確定している」ポインタ値です. 大文字のNULL で参照されますが,ヘッダファイルに何がしか の値が,マクロ置換で与えられています. その値は, 処理系依存です.

式には値がある. プログラムでは,例えば,

a = b + c;

のようにして,色々な変数の値を変化させて行きます. 上のような物を「式(expression)」と言います. Cでは,式そのものが値を持ち,その値は左辺値です. 前回のプログラムで,

if ( ( fp = fopen("input.txt", "r")) == NULL)

という記述がありました. これは, 2番目のカッコ内の式( fp = fopen("input.data", "r"))が先 に実行されます. そして,この式の値がNULL か否かをチェックしているわけです.

(4)

変数のキャストに関する補足

教科書には,変数を別の型に変換するキャストの方法が書かれています.

このように,明示的に変数の型を変えるキャスト以外にも「暗黙のキャスト」があります. 例えば,異なる型 の変数の計算の際にこれは起きます.

double a = 1.0;

int b = 2;

double c;

c = a + b;

のようなプログラムです. 上のcの計算では,bの値がdouble型に変換されて,計算が実行されます. このよ うな時の暗黙のルールは,次です.

char < int < float < double

これは,異なる型の計算があったら,より右にある型にキャストして計算が実行されるという意味です. この講 義で使っている処理系では,int,floatがともに32bitなので,int型からfloat型へのキャストでは,情報 落ちが起き得ます. float型では,指数部を情報として持つため, 仮数部の有効桁数は23bitしかありません.

また, 皆さんが好きな,pow()というライブラリ関数も,本来の引数は double型ですが,int型を渡しても

double型に変換して,べき乗を計算してくれます. これは, ライブラリ関数がそのようにプログラムされてい

るのです.

malloc(), free() に関する補足

malloc()で確保したメモリ領域は,目的の型のポインタにキャストしないと, warning(警告)が出る処理系

が多いと思います. warning(警告)とエラー(error)の意味の違いに注意してください. warning は,「Cの文 法的には許容されるが,実行時エラーが起きる可能性がある.」というときに出されます. errorは文法上の間違 いで,コンパイラが処理できないということです. したがって, errorがあると,実行ファイルが作られません.

free()関数ですが, fclose()と似たようなことがあります.

プログラムが終了するときに, malloc() で確保されたメモリは,自動的にシステムに返されます. 従って,こ の講義で書くようなプログラムでは, free()を使わなくても問題になる事はありません. ただし,コンピュータ

の中には, networkサービスを実行するプログラムのように, 24時間365日動き続けることを想定しなければ

ならないプログラムもあります. このようなプログラムでは, malloc()で確保したメモリは,要らなくなった

らfree()でシステムに返却しないと,使える記憶域が無くなって,システム全体が停止してしまいます.

教科書, プログラム10.3で注目すべきは, malloc()で確保した連続したメモリは, 配列のようにアクセスで きることです.

ベクトルの添字の値をずらすのは,プログラマの慣れがあれば不要だと思いますので,プログラム10.4は飛 ばします.

4

(5)

ポインタへのポインタ

「ポインタ型変数」も識別子である. という認識は重要です. また「ポインタ型変数の配列」もCでは多く 現れます.

レポート問題 : 締め切り , 7 24 ( ) 10:00 AM

今回は,適切なレポート問題を設定できなかったので,次をレポート問題にします.

前回の授業で, 40人分の成績を構造体 seiseki_tの配列に読み込むプログラムを書きました. この読み込 むプログラムに追加して,seiseki_tの配列を変数score の降順(大きい方から小さい方に並ぶよう)に並び 替えるプログラムを書け(つまり, 成績の良い順に配列を並び替える). 並び替えの方法は, 第6回の講義で解 説したバブルソートで良い. より効率的なアルゴリズムを知っていれば,それを利用しても良い. プログラム では,並び替えた結果を出力する部分も含める事.

件名: gengo2023 report 13.

上のレポート問題をこれまでの講義で述べた方法だけで実装するなら , それはあまり 効率良いプログラムではありません .

次回 , C のエキスパートが書く , より効率の良い実装について述べます .

Referensi

Dokumen terkait

は。 fを変化させなu、。 ロ この理由により, file i n凹 tへの出力は騰されない0 8 プログラム パラメタの意味および外務定義 プログラム パラメタは, このPuca lにおいては, プログラムの外留でll:冨されh その プ ログラムで使うものをかく。tex t型またはその他の fileの宜数は, プログラムの中で宜曾

計算の理論 或る問題の「計算が可能」 m その計算を行なうプログラムが存在 ⇓ 計算機の機能 =「計算」のモデル を決めて議論 −→ 代表的な「計算のモデル」を幾つか紹介... 計算の理論 或る問題の「計算が可能」 m その計算を行なうプログラムが存在 ⇓ 計算機の機能 =「計算」のモデル を決めて議論 −→

プッシュダウンオートマトンでは 認識できない言語の例 同じ文字列 2 回の繰返しから成る文字列全体 A={ww w∈Σ∗} 入力を読み直せないのが弱点 −→ より強力な計算モデルが必要 —計算機数学

• NOT, OR, ANDのみで、 全ての Boole 関数が実現できる • NOTがあれば OR, ANDは片方で良い • OR, ANDだけでは 全ての Boole 関数は実現できない • 一種類の論理素子 NORまたは NANDだ けで、全ての Boole 関数が実現できる 以下では、 NOT, OR,

(⇐⇒ 正規でない言語が存在する) 例 : A={anbn n≥0} (a と b との個数が同じ) 実際 wn=anb に対する SLwn が全て異なる 一般には、証明には部屋割り論法 (の一種のpumping lemma) を利用することが多い... 有限オートマトンでの計算可能性問題 非決定性有限オートマトンで認識できない

演習問題 ちょっとしたコツtips : 「後に続く文字列が何だったら受理か」 が全く同じ状態は一つの状態にまとめられる。 これが違う状態はまとめられない。 違う状態として用意する必要あり... その説明の前に、今回は、 ここで現れる色々な概念を 集合・写像などの言葉を用いて記述する練習

演習問題 ちょっとしたコツtips : 「後に続く文字列が何だったら受理か」 が全く同じ状態は一つの状態にまとめられる。 これが違う状態はまとめられない。 (違う状態として用意する必要あり)... その説明の前に、今回は、 ここで現れる色々な概念を 集合・写像などの言葉を用いて記述する練習

共分散、相関 共分散:2つの変数が似たような動きをするかどうかを示す.同じ方向に 動くときに正の値. σXY ≡covX,Y =E[X−µXY −µY] 2.24 相関係数:共分散の単位をそろえたもの.ゼロであるとき,2つの確率変 数は「無相関である」という 「独立」ならば「無相関」 corrX,Y≡ covX,Y √varXvarY = σXY σXσY