ようこそ ゲスト さん、新規登録(無料)して気になる疑問を解決しませんか?

質問

QNo.3988229 C言語超初心者・シフト演算の問題で質問です
質問者:panichead 問題集を読んでいて、突然わからない記号が出てきました。
18行目、25行目の意味がさっぱりわかりません。
自分で調べてみたのですが、左に動くと2倍右に動くと1/2倍というのはどこにも書いてあり、理解できたのですがそれがどうこの問題とつながっていて、回答が1〜3まであるのに、0と1で表現するの?25行目の0x3は、16進数かなぁと思うのですが、それが&と組み合わさると・・・??????とか混乱してました・・・GW中にでもご回答いただけたらと思います。よろしくお願いいたします。

Q.「よい」「ふつう」「悪い」の3択で答えるアンケートが4問ある。アンケートに回答を記録するにあたり、1問の回答を
1つの変数に格納していたのでは効率が悪いので、2ビットに1問ずつ詰め込んで保存する。そうすれば一人分の回答を
保存するのにchar型の変数1つですむ。4つの回答をキーボードから入力して、実行例のように格納しなさい。

■回答の保存

char型変数

7bit6bit(問4の回答)5bit4bit(問3の回答)3bit2bit(問2の回答)1bit0bit(問1の回答)

■実行例

問1:3
問2:2
問3:1
問4:3
回答一覧
問1問2問3問4
 3 2 1 3

1:/************アンケートの回答の記録************/
2:
3:
4:#include<stdio.h>
5:#define N 4
6:
7:main(){
8: //ローカル変数の宣言
9: char ans; //回答を記録する
10: int work; //作業用
11: int i; //回数のカウント
12:
13: //入力と回答の記録
14: ans=0; //初期化
15: for(i=0;i<N;i++){
16: printf("問%d:",i+1);
17: scanf("%d",&work);
18: ans|=(work<<i*2);
19: }
20:
21: //結果の表示
22: printf("\n回答一覧\n");
23: printf("問1問2問3問4\n");
24: for(i=0;i<N;i++){
25: work=(ans>>(i*2))&0x3;
26: printf("%d",work);
27: }
28: printf("\n");
29:}
困り度:
  • 困っています
質問投稿日時:
08/04/30 20:58
この質問に対する回答は締め切られました。

回答良回答20pt

ANo.4 それぞれの値を2進数で表示すると( )のようになります。
問1:3 (00 00 00 11)
問2:2 (00 00 00 10)
問3:1 (00 00 00 01)
問4:3 (00 00 00 11)
これをそれぞれのビット位置に移動するには
問1:3 (00 00 00 11) 0ビット左シフト
問2:2 (00 00 10 00) 2ビット左シフト
問3:1 (00 01 00 00) 4ビット左シフト
問4:3 (11 00 00 00) 6ビット左シフト
のように(問数-1)*2ビットシフトすればいいことになります。
プログラム上では問数は0-3なのでそのまま2倍して大丈夫ですね。
4問を1つにまとめたら
11 01 10 11
になります
ここから2問目の答えを取得する場合さっきとは逆に右に(問数-1)*2ビットシフトします
00 11 01 10
このままですと他の問の答えも含んでいるので一番下の2ビットだけにする必要があります。
それには必要な部分だけ1にした数字で & (and)すればOKです。
00 11 01 10
00 00 00 11 (16進数で0x3、10進数でも3なので同じですが)
この2個を & すると問2の答えの
00 00 00 10
が求められるわけです。
25行目の0x3はこの数字です
回答者:php504
種類:回答
どんな人:一般人
自信:自信あり
回答日時:
08/05/01 09:12
この回答へのお礼へえ〜〜このプログラムにはこんな深い内容が込められているのですね!
なるほど、移動させて&で消すあたり、面白いです☆彡
非常に参考になりました。ありがとうございます!!

回答

ANo.3 絵を使って理解する方がいいかも....
以下, ans を 8ビットと仮定します.
aa, bb, cc, dd を問1〜問4 の回答としたときに
ans = [dd][cc][bb][aa]
と入れたいわけです. すると, 例えば問3 の回答である cc が来たときには
ans = [00][00][bb][aa]
と入っていて, これを
ans = [00][cc][bb][aa]
としたいわけです. すると, 「cc を 4ビット左にシフトして or をとればいい」ということがわかります. 問3 ということは i = 2 だから「2*iビット左シフトする」ということになります.
回答者:Tacosan
種類:アドバイス
どんな人:一般人
自信:参考意見
回答日時:
08/05/01 00:05
この回答へのお礼お返事ありがとうございます!
左にシフトしてorをとることで1つの変数に横一列に保存するのですね。
それとは別に、表示は考えるんですね〜〜。
ですよね??・_・;

回答

ANo.2 >16進数かなぁと
>18: ans|=(work<<i*2);
>25: work=(ans>>(i*2))&0x3;

数の表現の仕方が複数有るだけ。中身は一緒。
現実世界でも有るでしょ。
 1時間=60分=1/24日=3600秒 (単位は違うけど指している値は同一)

空白入れると 判りやすくなるんじゃない?
18:
 ans |= ( work << i * 2 ) ;
25:
 work = ( ans >> (i*2) ) & 0x3 ;
回答者:SAYKA
種類:アドバイス
どんな人:一般人
自信:参考意見
回答日時:
08/04/30 21:48
この回答への補足さっそくのお返事ありがとうございます!!
ans=ans|(work<<i*2)だから、問1はans=0|(work<<2)となって、
論理和だから、どちらかが1なら1か、両方0なら0で・・・
workを2ビット左へ移動するということは・・・下位ビットに0が入って・・・ココからが難しいです><;
この回答へのお礼この回答にお礼をつける(質問者のみ)