わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

4択3問

いきなりですが問題です.適切な文になるよう,____に当てはまる語句を1つ選んで答えなさい.

(1) structとtypedefを組み合わせれば,1つの文で____を同時に宣言できる.

  1. グローバル変数とローカル変数
  2. 構造体と変数
  3. 関数原型とその実体
  4. 複数の型

(2) ある構造体型のポインタpと,その構造体のメンバmについて,____は等価である.

  1. p->mと(*p).m
  2. p->mと*p.m
  3. p.mと*p->m
  4. p.mと(*p)->m

(3) バッファには,____の意味合いがある.

  1. ある時点の使用中のメモリ
  2. 予定よりも大きめに用意されたメモリ
  3. ほんの一瞬だけ格納されるメモリ
  4. 過去のある一時点で存在したメモリ

さっそくですが解答です.まず(1)ですが,正解は「複数の型」です.まず,typedefなしで

struct Point {
  double x, y;
} point;

と書いたら,「Point構造体」とも呼ばれる「struct Point」型と,その型の変数pointを宣言することになります.この宣言文のはじめにtypedefを置いて,

typedef struct Point {
  double x, y;
} point;

とすると,このときpointは変数名ではなく,型名となります.struct Point型を宣言しますよというのと,pointはstruct Pointと同じ型ですよという指示を,1つの文で行っています.
このように,問題文や選択肢の言葉だけだと紛らわしいとき,1つか2つ,プログラムコードを書いてみることをお勧めします.試験だけでなく,本を読んだり,友人や家族と会話したりするときにも,事例を挙げることを,活用してみてください.
(2)については,正解は最初の選択肢,「p->mと(*p).m」です.これは消去法で解けます.
アロー演算子「->」も気になりますが,むしろ「.」の演算子に着目します.この演算子の左に来るのは,構造体オブジェクトであり,ポインタではありません.ここに注意すると,3番目と4番目に含まれている「p.m」は構文的に間違いとなり,選択肢から外せることが分かります.
これで2つに絞り込めました.さて,2番目の選択肢にある「*p.m」を見てみましょう.この式には,間接参照演算子の「*」と,メンバアクセス演算子の「.」が入っています.
1つの式に複数の演算子があったら,優先順位をチェックしましょう.今回の場合はというと,「*」は単項演算子なので上から2番目であり---忘れた人は演算子の表*1を見直してください---,「.」は最上位ですので,優先順位は「.」が高くなります.だからカッコを付けて書くと,「*p.m」は「*(p.m)」と同じです.
するとここにも,先ほど間違いと言った,「p.m」の式が入っているので,やはり間違いと,判断することができます.
(3)は,参考書の自習範囲からの出題です.正解を先に言うと「予定よりも大きめに用意されたメモリ」です.なぜなのか…
もしかしたら,学科の他の授業でも教わったかもしれませんが,今から私が言うことをかいつまんで,理解をしてください.
バッファという言葉にはまず,「緩衝材」という意味があります.英和辞書で,bufferを引けばたぶん,載っています.衝撃を和らげる素材であり,仕組みです.プログラミングで「衝撃を和らげる」のは何かというと,入出力です.
本日と次回の授業で,1バイトずつ読み出すプログラムを例題に使う予定ですが,ファイルを開いてから,1バイトずつ読み出すのを,その都度,ハードディスクにアクセスしているのでは,ディスクへの物理的な負担が,無視できません.その上,読み出し完了までの,ハードディスクとOSとのやりとりに要する時間もかかります.
そこで,例えば4096バイトだとか取っておいて,これを1ブロック分とします.ハードディスクと実行環境とのやりとりでは,1ブロック分を一括して,物理的に読み出します.あとは,fgetcなら1バイト分,別の関数ならそれに応じたサイズだけ,メモリ内で受け渡しします.何文字,読み出し処理に使ったかを管理しておき,読み出し分がなくなったら,おかわりをします.
この1ブロック分にあたるメモリ領域を,バッファと言います.4096は処理系によって異なりまして,512だとか,8192だとかになるかもしれませんが,1バイト分や,1行分よりは,大きくとるのが一般的です.
バッファは「緩衝材」を情報処理に転用したものであり,「大きめに用意されたメモリ」という意味合いになるのを,知っておいてください.
残りの選択肢ですが,「ほんの一瞬だけ格納されるメモリ」は,参考書にも載っていて,これは「テンポラリ」のことです.以前の授業で,tmp = x; x = y; y = tmp;によって,2つの変数の値を交換するという処理を取り上げましたが,この変数名tmpは,テンポラリ(temporary)が語源です.
Cのプログラミングから離れた,使われ方もあります.UnixLinuxには,/tmpというディレクトリがありますし,Windowsの場合は,環境変数TEMPが活用されています.だからメモリというのは重要ではなく,テンポラリは「一時使用」と覚えておきましょう.
あと2つの間違い選択肢は,参考書の範囲外です.「ある時点の使用中のメモリ」は「コアメモリ」,略して「コア」と呼ばれます.我々のプログラミングでも,出てくるかもしれません.というのも,実行時にエラーが出て「Core dumped.」と出てきたら,それは,エラー発生時点のメモリ内容をファイルに書き出したので,原因の分析に使ってください*2というメッセージになります.
最後の選択肢,「過去のある一時点で存在したメモリ」は---「ある時点の使用中のメモリ」と非常に似ていますが---コアと別の用語を割り当てることができて,それは「スナップショット」です.1台のPCの中で,通常のOSのほかに,仮想OSを動かしていて,その仮想OSをシャットダウンすることなく,いったん停止させ,次回起動時にすぐに復旧しようというとき,保存するメモリ状態のことを,スナップショットと言います.
授業で,コンピュータの使用で,Web上の情報で,本を読んでいて,そして日常生活で,見かける用語の関連付けを,習慣としてください.それぞれの知識や概念を自分の中で明確にするのにも,友人をはじめ周囲の人とのコミュニケーションをより良くするのにも,役立つはずです.

おまけ

構造体宣言と,その構造体を戻り値とする関数の定義は,以下のように1つの文で行えます.エラーも警告も出ません*3

#include <stdio.h>

struct point {
  double x, y;
} create_point(double x, double y) {
  struct point p;

  p.x = x;
  p.y = y;

  return p;
};

int main(void)
{
  struct point p = create_point(3.14, 0.00159);

  printf("p.x = %g\n", p.x);
  printf("p.y = %g\n", p.y);

  return 0;
}

*1:演算子の表の上から2番目(単項演算子)と下から2番目(代入演算子)を覚えておくのが便利なことは,演算子の授業で,また後置の++と--は例外的に最優先になることは,2つの式「*p++;」「(*p)++;」を用いてポインタの授業で,それぞれ説明しています.

*2:プログラミング授業の範囲内では,ソースコードをよく見直すこと,実行中の一時停止や変数の値の確認にはデバッグを用いることを指導すべきであり,コアファイルの分析は,やるとすれば自習課題かなあとも思いますが.

*3:関数の引数に,構造体宣言を入れた変数名を書き,GCCコンパイルしてみると,その構造体型のスコープは関数定義・宣言に限られるという警告が出たものの,実行ファイルは作られました.