構造体のプログラムで、
#include<stdio.h>
struct example{
char str[4];/* 文字列*/
int num;/* 番号*/
};
int main()
{
struct example data[5];/* 全て0で初期化されているとする*/
struct example *ps;
ps = &data[2];
ps->str[3]='A';/* (1)この処理でどこが書き変わるか?*/
ps += 2;
(*ps).num = 15;/* (2)この処理でどこが書き変わるか? */
ps -= 4;
ps->str[0] = 'z';/* (3)この処理でどこが書き変わるか? */
}
と、いうものがあるのですが、質問が、「上のようなプログラムのような処理を行った場合に、ポインタ変数psの中身はその時点でどのようになるか。 構造体変数data[]のアドレスは0x1000、0x1000、0x1010、0x1018、0x1020であるとする。」
という問題で、それぞれ、printf文を使ってpsの変化を実際に見てみればよいと思ったのですが、問題文の意図がよく分からないことと、仮にprintf文を入れた場合、どこにどのような中身で入れたら良いのか教えて欲しいと思っています。
お願いします。
A 回答 (7件)
- 最新から表示
- 回答順に表示
No.7
- 回答日時:
★もう24日ですが、締め切られていないので私のアドバイス(解説)を追加します。
・まず最初に回答者 No.2、No.3 さんのご指摘どおり質問のアドレスがおかしいです。
その後に質問者 No.4 さんの通りに2番目の構造体アドレスが 0x1008 ならば
納得します。→入力のタイプミスですね。
・ここで問題をもう一度整理します。
正しい質問:
・上記の構造体変数 data[] のアドレスが 0x1000、0x1008、0x1010、0x1018、0x1020 としたとき
ps というポインタで変更した箇所がどこなのかを printf 文で確認して見たい。
・ということですよね。
最初に:
・まずは構造体変数 data を初期化しましょう。質問者さんはコメントでは『0で初期化されている』
と記述していますが、回答者 No.4 さんの『回答へのお礼』で恐らくは初期化していません。
・そこで、宣言を『static struct example data[5];』という風にします。→『static』で 0 に初期化される
・私は printf 文をどこに入れて確認すればよいかの回答はしません。
・メモリ・イメージだけで解説します。
解析:
(1)ps = &data[2]; [0x1010]{[\0][\0][\0][\0],0}{[\0][\0][\0][\0],0}『[\0][\0][\0][\0],0』{[\0][\0][\0][\0],0}{[\0][\0][\0][\0],0}
(2)ps->str[3]='A'; [0x1010]{[\0][\0][\0][\0],0}{[\0][\0][\0][\0],0}『[\0][\0][\0][A ],0』{[\0][\0][\0][\0],0}{[\0][\0][\0][\0],0}←(1)の時点
↑
(3)ps += 2; [0x1020]{[\0][\0][\0][\0],0}{[\0][\0][\0][\0],0}{[\0][\0][\0][A ],0}{[\0][\0][\0][\0],0}『[\0][\0][\0][\0],0』
(4)(*ps).num = 15; [0x1020]{[\0][\0][\0][\0],0}{[\0][\0][\0][\0],0}{[\0][\0][\0][A ],0}{[\0][\0][\0][\0],0}『[\0][\0][\0][\0],15』←(2)の時点
↑
(5)ps -= 4; [0x1000]『[\0][\0][\0][\0],0』{[\0][\0][\0][\0],0}{[\0][\0][\0][A ],0}{[\0][\0][\0][\0],0}{[\0][\0][\0][\0],15}
(6)ps->str[0]='z'; [0x1000]『[z ][\0][\0][\0],0』{[\0][\0][\0][\0],0}{[\0][\0][\0][A ],0}{[\0][\0][\0][\0],0}{[\0][\0][\0][\0],15}←(3)の時点
↑
解説:
・上記の{}で囲った部分が、1つの構造体データを表します。
・上記の『』で囲った部分が、ポインタ(ps)の位置を表します。
・上記の[]で囲った部分が、ポインタ(ps)のアドレスを表します。
・上記の矢印が変更された部分を表します。→画面の解像度からずれるかも。注意。
・『(*ps).num』という指定は『ps->num』と同じ動作になります。→記述の違いだけです。
最後に:
・画面の関係上で折り返されていたらごめんなさい。
・過去に似たような質問がありました。
・http://oshiete1.goo.ne.jp/qa2627072.html→『ポインタの基礎について』回答者 No.4
・こちらも参考にして下さい。
・以上。おわり。→何か感想をお願いします。場合によってはまた回答しますよ。
No.6
- 回答日時:
基本的なところからの理解が必要ということですね。
方眼用紙を用意してください。(方眼用紙って古いか…、エクセルシートでかまいません)
横8マス、縦5マスの大きさに切ってください。
左上のマスを起点として、横書きの方向で0から39まで順に数字で埋めてください。
それぞれのマスにいろいろな色を付けてください。
一応、メモリマップのつもりです。
マスがメモリを表します。1マスで1バイトです。
数字がメモリを識別するためのアドレスです。
色はメモリに格納された値を意味します。
「上から3段目、左から4番目のマスを赤色で塗りました、そのマスに書いてある数字は何ですか?」
というのが(1)の質問内容です。
> 「(1)アドレス0x1008の値が2293584に書き換わる
> (2)アドレス0x1018の値が2293600に書き換わる
> (3)アドレス0x1020の値が2293568に書き換わる」
psの値が3つありますが、それぞれから 2293568 を引いて見てください。
方眼の1段は、struct example 1レコードを意味します。
char str[4]; のサイズは4バイトです。
int num; のサイズは4バイトです。(とする)
左上マスのアドレスは 0x1000 ということになります。
念のために補足しておきます。
0x1000 は16進数です、10進数に直すと 4096 です。
C言語では、配列の添え字は0から始まります。
これで、理解してもらえるといいのですが…。
以下、独り言です。
(2)はエンディアンの問題があって、2通りの答えが考えられますねぇ。
課題を出した人は、そこまで考慮しているのやら…。
No.5
- 回答日時:
ANo.2 = Interest です。
> > 構造体変数data[]のアドレスは0x1000、0x1000、0x1010、0x1018、0x1020であるとする。
> の部分についてですが、多分2番目は「0x1008」の間違いと思われます。
これならわかります。
> 答えとして、
> 「(1)アドレス0x1008の値が2293584に書き換わる
> (2)アドレス0x1018の値が2293600に書き換わる
> (3)アドレス0x1020の値が2293568に書き換わる」
> は合っていますか??
違います。出題者はそういうことを聞きたかったんじゃなくて、「ポインタってなんなの?どういう仕事をするかわかる?」と聞きたかったんだと思いますよ。
ポインタのイメージは、「仮につけられた名前」のようなものです。
例えば。
0番目の人:xiamei723さん
1番目の人:yonfaさん
2番目の人:Interestさん
3番目の人:nerosukeさん
として、Aさん(誰かを指し示す)というポインタを作ったとします。
>ps = &data[2];
Aさん=2番目の人; として
>ps->str[3]='A'; /* (1)この処理でどこが書き変わるか? */
Aさんはアホだ。 といった場合、誰がアホでしょうか?
と聞いてるわけです。
ポインタを進める/戻すということは、Aさんの次の人/前の人ってことですね。
「アドレス0x1013の値が書き換わる」は、わかっている人には伝わると思いますが、構造体の配列がどのようにメモリに割付けられるかイメージできないと誤解を生みそうです。(アドレスが書き換えられるんじゃなくて、アドレスに格納されている値が書き換えらえるんです。)
0x1000 : data[0]
0x1008 : data[1]
0x1010 : data[2]
(以下省略)
> ps = &data[2];
> ps->str[3]='A';
なので、0x1010 + 3 のアドレスに 'A' が入った。これが
「アドレス0x1013の(に格納されている)値が書き換わる」
という意味です。
No.4
- 回答日時:
> 答えが数値でも良いのでしょうか?
ポインタ変<数>はメモリ上のアドレスを示すものですので、数値となります。
> 構造体変数data[]のアドレスは0x1000、0x1000、0x1010、0x1018、0x1020であるとする。
の部分についてですが、多分2番目は「0x1008」の間違いと思われます。
「~であるとする」というのは、あくまでも仮定の話なので、実際にプログラムを作成して実行すると、実行するたびに異なる値となるはずです。
実際に実行してみて、変数psの値はどうだったでしょうか?
絶対値は大きな数値になったと思いますが、変動の差分を追ってみるとなんとなく法則みたいなものが見えるのではないでしょうか?
求められる回答としては、ps への代入が行われた後の ps の値を「0x1000、…」から選択してあげればよいと思います。
たぶん、(1)の答えは、「アドレス0x1013の値が書き換わる」というような感じになるのではないでしょうか。
ありがとうございます。
間違ってたらすみません。
答えとして、
「(1)アドレス0x1008の値が2293584に書き換わる
(2)アドレス0x1018の値が2293600に書き換わる
(3)アドレス0x1020の値が2293568に書き換わる」
は合っていますか??
No.3
- 回答日時:
>構造体変数data[]のアドレスは0x1000、0x1000、0x1010、0x1018、0x1020であるとする。
これは明らかにおかしいですね。
理由はNo2さんが回答している通りです。
でも、とりあえずprintfで出力してみれば、わかるんじゃないですか?
とりあえず、構造体の配列を0で初期化します。
<初期化例>
memset(&data[0], 0, sizeof(struct example)*5);
単純に全てに0を代入してもいいです。
これは前提じゃなくてちゃんと実装しないと、不具合がでますよ
最後に構造体の内容を表示すればどの構造体に値が反映されているか
わかります。 それで影響のあったところを纏めればお終いです。
for(i=0; i<5; i++){
printf("data[%d] >> ",i);
//ちなみに1文字づつ出力しているのは、0クリアされているからですよ。
for(j=0; j<4; j++){
printf(" str[%d]==%c", j,data[i].str[j] );
}
printf(" num==%d\n",data[i].num);
}
No.2
- 回答日時:
これは printf で表示させてもダメかな。
というのは、設問に
> 構造体変数data[]のアドレスは0x1000、0x1000、0x1010、0x1018、0x1020であるとする。
と書いてあるものを実際のプログラムに入れるわけには行かないから。
と思ったら。構造体のアドレスがこれだと、設問が変じゃないですか?
配列なのにメモリ空間に連続で割り当てられていないというか、同じアドレスを指す要素があるとか。intを32bit、構造体の「穴(※)」なしと仮定したら、8Byteずつアドレスが大きくなるんじゃないかと思います。<設問のアドレス変だよって話です。
※穴・・・構造体の記憶領域割り当ては構造体メンバのそれぞれのサイズを足したものより大きくなることがあります。このとき、メンバに割り当てられていない部分を「穴」と呼んでいます。
> 問題文の意図がよく分からないことと
(1)の要点「ポインタはアドレスを保持する」
(2)の要点「ポインタを1進めると、型の大きさ分だけ先のアドレスを指す」
(3)の要点=(2)の要点の引き算バージョン
でOK?
何を言っているのか分からないようでしたら、次のように問題を読み替えてください。
char data[5] = {0, 0, 0, 0, 0};
char *p;
p = &data[2];
*p = 1; /* (1)この処理でどこが書き変わるか? */
p += 2;
*p = 2; /* (2)この処理でどこが書き変わるか? */
p -= 4;
*p = 3; /* (3)この処理でどこが書き変わるか? */
これがわかったら、あとは char を struct example に換えれば・・・もう答えは出てますね。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分 1 2022/07/19 17:03
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 malloc関数を使ってください!お願いします! 最 1 2022/07/21 09:28
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
セグメントエラー
-
init関数の意味
-
Run-Time Check Failure #3とい...
-
アプリを32bitから64bit移行
-
DLL<->VB間での受け渡し(文字...
-
C言語のポインタに直接アドレス...
-
LPSTR型の初期化について
-
参照型で受け取った引数をポイ...
-
戻り値で構造体を返すことは可...
-
構造体とfscanf
-
fopne で失敗する原因
-
NASMかNASKの文法の本
-
関数ポインタの高速化のメリット
-
自作関数の引数
-
Cで作成したDLL関数をVBから呼...
-
popenした子プロセスのプロセス...
-
#define NULL ((void *)0) の弊害
-
C言語のプログラムをJavaに...
-
visual studioのエラーについて
-
x64プログラムでアドレスが32bi...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
セグメントエラー
-
C言語のポインタに直接アドレス...
-
init関数の意味
-
戻り値で構造体を返すことは可...
-
fopne で失敗する原因
-
C言語の関数と配列に関する質問
-
Run-Time Check Failure #3とい...
-
LPSTR型の初期化について
-
ExcelVBAでのkernel32(64bit)
-
main(int argc,char **argv[])...
-
アプリを32bitから64bit移行
-
ハンドルはポインタか
-
連結リスト 要素の入れ替え
-
C言語でのconstを返す関数
-
Cで作成したDLL関数をVBから呼...
-
NULLとブランクの違い
-
エラーの意味
-
ハンドル、アドレス、ポインタ...
-
DLL<->VB間での受け渡し(文字...
-
【C言語】戻り値が構造体の関数
おすすめ情報