応用情報技術者 2019年 春期 午前2 問09
問題文
同一メモリ上で転送するとき、転送元の開始アドレス、転送先の開始アドレス、方向フラグ及び転送語数をパラメタとして指定することによってブロック転送ができるCPUがある。図のようにアドレス1001から1004の内容をアドレス1003から1006に転送するとき、パラメタとして適切なものはどれか。ここで、転送は開始アドレスから1語ずつ行われ、方向フラグに0を指定するとアドレスの昇順に,1を指定するとアドレスの降順に転送を行うものとする。


選択肢
ア:
イ:
ウ:
エ:(正解)
🔒 解説は解答すると表示されます
同一メモリ内ブロック転送【午前2解説】
正解の理由
設問は、転送元領域(アドレス1001~1004)を同一メモリ上の転送先領域(アドレス1003~1006)へ上書きせずに正しく移すためのパラメタ指定を問うています。転送元と転送先が重なっており、転送元の開始アドレス(1001)が転送先の開始アドレス(1003)より小さい()場合、後ろ(大きいアドレス側)から前へ順にコピーする必要があります。つまり方向フラグは降順(1)にし、転送の開始点を各領域の末尾(転送元の最後=1004、転送先の最後=1006)に置いて上から下へ(1004→1006, 1003→1005, …)コピーする方法で上書きを防げます。ここで示す条件を満たすのは選択肢のうち エ です(転送元開始1004、転送先開始1006、方向フラグ1、転送語数4)。
解法ステップ
- 転送元と転送先の範囲が重なっているか確認する。
- 今回は転送元 1001–1004、転送先 1003–1006 で重なりあり。
- 転送元開始アドレスと転送先開始アドレスを比較する。
- なので「転送元の開始アドレスが小さい」。
- 上書きを避けるための方向を決定する。
- 転送元開始 < 転送先開始 のときは後ろから前へ(降順)で転送する=方向フラグ = 1。
- 例: 降順(1)で、転送は各領域の末尾から開始する。
- 開始アドレスと語数を設定する。
- 降順で末尾から転送するため、転送元開始を1004、転送先開始を1006、転送語数を4とする(選択肢 エ)。
- 実際の転送順序(確認)
- 1004 → 1006
- 1003 → 1005
- 1002 → 1004
- 1001 → 1003
簡単なシミュレーション(順序確認用、pseudo):
src = {1001:'A',1002:'B',1003:'C',1004:'D'}
dst = {} # same memory, but we simulate writes to addresses 1003..1006
# 降順で開始を末尾に合わせる(選択肢 エ)
for offset in range(0,4):
s_addr = 1004 - offset
d_addr = 1006 - offset
dst[d_addr] = src[s_addr] # 実メモリでは同一空間へ安全に上書きされる
# 結果: dst[1003]='A', dst[1004]='B', dst[1005]='C', dst[1006]='D'
選択肢別の誤答解説
- ア(転送元1001/転送先1003/方向0/語数4)
方向0(昇順)で開始アドレスがそれぞれ先頭(1001→1003)だと、最初に 1001→1003 と書き込むことでアドレス1003の元のデータ(転送元の一部)を破壊してしまい、その後に読むべき転送元(例えば1003)の正しい値が失われます。結果として正しくコピーできない。 - イ(転送元1001/転送先1003/方向1/語数4)
方向1は降順だが、開始点が先頭(1001)で降順にすると 1001,1000,... の順に読み書きすることになり、問題で指定された「1001~1004 を 1003~1006 に移す」という意図に沿った連続4語のコピーになりません(範囲がずれる・存在しないアドレスを参照する可能性がある)。 - ウ(転送元1004/転送先1006/方向0/語数4)
開始点を末尾にしているが方向が昇順(0)だと 1004→1006、次に1005→1007… と読み書きが進み、転送元の範囲外(1005,1006,1007)を読もうとするか、正しい元の4語(1001–1004全体)を順に移せません。重なりの影響も解消できない。 - エ(転送元1004/転送先1006/方向1/語数4)
開始点を末尾にして降順で転送するため、上書きを起こさずに正しく4語を移動できる。したがってこの選択が正しい。
よくある誤解
- 「方向フラグ1は『転送先アドレスが大きい時に使う』」ではなく、判定は転送元開始アドレスと転送先開始アドレスの大小関係に基づきます。転送元開始 < 転送先開始 のときは降順(1)にする、逆なら昇順(0)にします。
- 「開始アドレスは常に範囲の先頭を指定する」と思い込む誤り。降順で転送する場合は各領域の末尾を開始アドレスにしなければならない点を忘れがちです。
- 「重なりがなければ方向はどうでもよい」と考えるが、非重複でも実装や性能面で昇順を選ぶことが一般的で、誤って範囲外を参照しないよう注意が必要です。
補足コラム
実際のCPU命令(例えば文字列/ブロック転送命令)でも、方向フラグやインクリメント/デクリメントの制御で同様の問題に対処します。重なりがあるメモリコピーでは、単純な先頭→先頭の逐次コピー(昇順)と、末尾→末尾の逆順コピー(降順)とで結果が大きく変わるため、アルゴリズム設計時には必ず開始位置と方向を組み合わせて検討することが重要です。
FAQ
Q1. 転送元開始アドレスが転送先開始アドレスと等しい場合は?
A1. 同じ範囲を同じ位置に転送することになり、実質的に何も変化しません(方向は結果に影響しない)。ただしシステムによっては無駄な動作になるため最適化で転送をスキップすることがあります。
A1. 同じ範囲を同じ位置に転送することになり、実質的に何も変化しません(方向は結果に影響しない)。ただしシステムによっては無駄な動作になるため最適化で転送をスキップすることがあります。
Q2. 転送元開始 > 転送先開始 の場合はどうする?
A2. この場合は前述と逆で、昇順(方向フラグ = 0)で先頭から順にコピーすると上書きを避けられることが多いです。例:転送元1003–1006 を 1001–1004 に移すなら転送元開始1003、転送先開始1001、方向0(昇順)で開始する方法が安全です。
A2. この場合は前述と逆で、昇順(方向フラグ = 0)で先頭から順にコピーすると上書きを避けられることが多いです。例:転送元1003–1006 を 1001–1004 に移すなら転送元開始1003、転送先開始1001、方向0(昇順)で開始する方法が安全です。
Q3. 範囲が重ならない場合は方向フラグは気にしなくて良い?
A3. 技術的にはどちらでも正しく動きますが、実装の安全性(誤った開始アドレスの設定ミス)や性能面を考えると「常に開始は小さい方、方向は昇順」に揃えるなどのルールを設けるとミスが減ります。
A3. 技術的にはどちらでも正しく動きますが、実装の安全性(誤った開始アドレスの設定ミス)や性能面を考えると「常に開始は小さい方、方向は昇順」に揃えるなどのルールを設けるとミスが減ります。
関連キーワード: ブロック転送、方向フラグ、オーバーラップ転送、メモリコピー、開始アドレス決定

\ せっかくなら /
応用情報技術者を
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

