• 検索結果がありません。

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

N/A
N/A
Protected

Academic year: 2021

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

Copied!
4
0
0

読み込み中.... (全文を見る)

全文

(1)

計算機言語

I

13

動的なメモリの確保

この資料

: http://www.math.u-ryukyu.ac.jp/~suga/gengo/2019-1/13.pdf

レポートへのツッコミ

2

乗を計算するのにライブラリ関数

pow()

を使う人が多いですが

, 2

乗くらいだと積を

,

つまり

a

2の計算

, a*a

と書くのが普通です

.

関数呼び出しは

,

幾らかの処理

(

前処理

,

後処理

)

をプログラムに要求しますが

, a*a

,

即座に計算できます

. CPU

が速くプログラムが小さいので

,

この講義でのプログラムでは気になりま せんが

,

大きなプログラム

(

例えば

, Firefox

のようなグラフィカルな

Web

ブラウザや

,

画像編集ソフト

)

では

,

このような細かいチリが積もって山となります

.

もちろん

, 100

乗を計算するときには

, pow()

を使います

.

「臨機応変」を意識してください

.

動的なメモリ確保

今回の内容は割に難しいとされる事です

.

少し

,

細かい話をします

.

プログラムには

,

実行時にならないとデータの大きさが決まらないことがよくあります

.

例えば

,

この講義で使っているテキストエディタですが

,

どのくらいの大きさのファイルを編集するのかは

,

実行するまでわかりませんし

,

入力をどんどんしていくと必要なメモリもどんどん増えていきます

.

テキスト エディタの最初の回

(

情報科学演習

)

のときに述べましたが

,

入力画面に表示されている内容は

,

一次記憶装置 の中に保存されており

,

その内容は実行しているプログラムが管理しています

.

タイトルにある「動的なメモリの確保」とは

,

「実行中にプログラムが必要となったメモリをシステムに要 求してもらってくる」という動作の事です

.

実用的なプログラムを作成しようとすると

,

このような仕組みが 必要であり

,

そのプログラムを記述するプログラミング環境も

,

このような仕組みが利用できるようにしてあ ります

.

今回は

, C

におけるその仕組みの使い方です

.

これまででは

,

「変数宣言」という形で

,

プログラム内では必要なメモリを確保してきました

.

しかし

,

これ までのメモリ確保の方法は

,

プログラム実行前に必要な変数の量が決まっているときだけです

.

ポインタの復習

動的なメモリの確保では

,

ポインタを多用します

.

ポインタについてもう一度復習します

.

C

のプログラムでは

,

一部の例外を除いて

,

識別子

(

名前

,

関数や変数の名前のこと

)

には

,

実行時に一次記憶 内でのアドレスが付与されることになっています

.

実行時のある識別子のアドレスのことを

,

その識別子への

ポインタ

(pointer

は何かを指し示す物という意味の英語

)

と言います

.

1

(2)

アドレス演算子

&

,

識別子に作用させることができ

,

その値は

,

その識別子を指すポインタになります

. C

では

,

ポインタ

(

アドレス

)

の値を保持するための変数型

,

「ポインタ型」を使うことができます

.

例えば

,

double *dp;

という宣言は

,

次のように読みます

. (

下で「アクセス」と書いてある部分は

,

代入や値を取り出すという意味 です

.)

dp

はポインタ

(

アドレス

)

の値を保持するための変数であり

,

この識別子でアクセスできる値は

,

何らか のアドレスである

.

*dp

という形でアクセスを行う際には

, dp

の値の場所には

, double

型の値を保持するだけのメモリが すでに確保されており

,

アクセスできる値は

,

その場所にある

double

型の数値である

.

上の事から

,

ポインタ型変数に対する

*

dereference operater(

意訳して間接参照演算子

)

と言ったりしま

.

ポインタ値

(

アドレス値

)

を経由して

,

その場所にある値をアクセスするからです

.

上の宣言では

, dp

には

,

アドレスとしての意味を持てば

, (

例えば整数値を

)

代入することができます

.

従っ

,

プログラム的にアクセス出来ない場所の値を

dp

に代入しても

,

「文法エラー」にはならず

,

「実行時エラー」

になります

.

また

,

このようなプログラムでも

,

実行時エラーが発生しないこともあり

,

「隠れたバグ」がプロ グラムに残ることも

,

数多く発生しています

.

これは

, OS

開発用に作られた

C

の仕様

(

特徴

)

であり

,

プログ ラマがその辺の責任を持つ必要があります

.

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

NULL

ポインタ

. Null Pointer(

ナルポインタ

,

ヌルポインタ

)

と呼ばれるもので

,

「何も指していないという

ことが確定している」ポインタ値です

.

大文字の

NULL

で参照されますが

,

ヘッダファイルに何がしか の値が

,

マクロ置換で与えられています

.

その値は

,

処理系依存です

.

式には値がある

.

プログラムでは

,

例えば

,

a = b + c;

のようにして

,

色々な変数の値を変化させて行きます

.

上のような物を「式

(expression)

」と言います

. C

では

,

式そのものが値を持ち

,

その値は左辺値です

.

前回のプログラムで

,

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

という記述がありました

.

これは

, 2

番目のカッコ内の式

( fp = fopen("input.data", "r"))

が先 に実行されます

.

そして

,

この式の値が

NULL

か否かをチェックしているわけです

.

2

(3)

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

教科書には

,

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

.

このように

,

明示的に変数の型を変えるキャスト以外にも「暗黙のキャスト」があります

.

例えば

,

異なる型 の変数の計算の際にこれは起きます

.

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)

の意味の違いに注意してください

. worning

,

C

の文 法的には許容されるが

,

実行時エラーが起きる可能性がある

.

」というときに出されます

.

free()

関数ですが

, fclose()

と似たようなことがあります

.

プログラムが終了するときに

, malloc()

で確保されたメモリは

,

自動的にシステムに返されます

.

従って

,

の講義で書くようなプログラムでは

, free()

を使わなくても問題になる事はありません

.

ただし

,

コンピュータ

の中には

, network

サービスを実行するプログラムのように

, 24

時間

365

日動き続けることを想定しなければ

ならないプログラムもあります

.

このようなプログラムでは

, malloc()

で確保したメモリは

,

要らなくなった

free()

でシステムに返却しないと

,

使える記憶域が無くなって

,

システム全体が停止してしまいます

.

教科書

,

プログラム

10.3

で注目すべきは

, malloc()

で確保した連続したメモリは

,

配列のようにアクセスで きることです

.

ベクトルの添字の値をずらすのは

,

プログラマの慣れがあれば不要だと思いますので

,

プログラム

10.4

は飛 ばします

.

3

(4)

ポインタへのポインタ

「ポインタ型変数」も識別子である

.

という認識は重要です

.

また「ポインタ型変数の配列」も

C

では多く 現れます

.

レポート問題

:

締め切り

, 7

22

(

) 10:00 AM

今回は

,

適切なレポート問題を設定できなかったので

,

次をレポート問題にします

.

前回の授業で

, 40

人分の成績を構造体

seiseki_t

の配列に読み込むプログラムを書きました

.

この読み込 むプログラムに追加して

, seiseki_t

の配列を変数

score

の降順

(

大きい方から小さい方に並ぶよう

)

に並び 替えるプログラムを書け

(

つまり

,

成績の良い順に配列を並び替える

).

並び替えの方法は

,

6

回の講義で解 説したバブルソートで良い

.

より効率的なアルゴリズムを知っていれば

,

それを利用しても良い

.

プログラム では

,

並び替えた結果を出力する部分も含める事

.

件名

: gengo2019-1 report 13-1.

上のレポート問題をこれまでの講義で述べた方法だけで実装するなら

,

それはあまり 効率良いプログラムではありません

.

次回

, C

のエキスパートが書く

,

より効率の良い実装について述べます

.

4

参照

関連したドキュメント

教科書に対するコメント プログラム11.2 教科書, プログラム11.2 はわかりづらいソースの典型例で, このようなプログラムを書いてはいけません し,現在では, 実際上書くこともありませんプログラム 11.4のようなものを利用する... なにが分かりづら いかというと,プログラムのfor文の中のif文 if str2[i]=str1[i] == ’\0’

2 OMPCUDA コンパイラでの実行 [行列‐行列積] OMPCUDA の現在のバージョンの実装制約から,2 次元配列で記述した図

このことを利用して list 8–9 と同じ動作をするプログラムを書くと , list

このソースにある main() 以外の 関数は , 線形代数 ( 行列 ) をプログラムする上で便利な関数が多く記述されています... やはり ,

上の search 関数の while 文を while(p-&gt;info !=x &amp;&amp; (p!=NULL)) に変えると , 見つからない値 を探すと実行時エラーになる. 上のプログラムで

exit() は引数値を shell 変数 status に返してプログラム を終了するライブラリ関数です .... /*

75, プログラム

char moji=65; これは, char型の変数moji にAscii値が65の文字大文字のAを代入して初期化するという, Cの仕様と しては正しい記述です.. しかし, char型の変数に整数値を代入しているわけですから,意味的には変です.「文 法的には正しいが,冷静に考えると意味がおかしい.」というような仕様は,本来策定すべきではありませんが,