- ベストアンサー
構造体の配列について
--------------------------------------------------- #include<stdio.h> #include<string.h> struct person{ char name[80]; int height; int weight; }; int main() { struct person dt[10]; strcpy(dt[1].name,"日本太郎"); //// (1) //// dt[1].weight=70; dt[1].height=180; dt[5]=dt[1]; //// (2) //// printf("%s %d %d \n",dt[1].name,dt[1].weight,dt[1].height); return 0; } ----------------------------------------------------- 以上のプログラムは参考書に記述されていたものですが、(1)の部分で、配列名dtに「"日本太郎"」を設定するならわかるのですが、配列の1つの要素「dt[1]」に「"日本太郎"」を設定しているというように見え、これはエラーが出ると感じたのですが出ません。 char dt[10]; strcpy(dt[1],"日本太郎"); 以上のようにしてしまっているというイメージがあります。 後、(2)の部分もよくイメージがわきません。 以上、どのような仕組みになっているのか教えていただければ嬉しいです。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 (1) 既に回答が出ておりますが、補足です。 mufflerさんがイメージしている書き方でも、”今の条件”であれ ば出来てしまいます。 以下、理由です。 まずは、「strcpy(dt[1].name,"日本太郎");」を、説明すると 変数 dt の 配列2番目にある 構造体変数name がさすポインタに "日本太郎" をコピーする。 となります。 変数 dt をメモリ上に置くと(アドレス番地は、仮定です) 変数 アドレス dt &h3000番地 dt[0] &h3000番地 dt[1] &h3058番地 dt[2] &h30B0番地 この構造体をメモリ上(32ビットCPUを想定)に置き換えます。 それぞれ dt 及び dt[ N ]をベースのアドレスとすると、 オフセットアドレス分加算することで、メンバ変数の位置を 特定する事ができます。 (実際のコーディングでは、アドレスにラベルとしてつけているのが変数名 なので、意識しませんがね) オフセット アドレス ↓ &h0番地 「char型 で メンバ変数名:name を80個確保;」 &h80番地 「int型 で メンバ変数名:height;」 &h84番地 「int型 で メンバ変数名:weight;」 になります。 それぞれ dt 及び dt[ N ]をベースのアドレスと、メンバ変数 「char name[80];」は、同じアドレスになります。 mufflerさんがイメージしている書き方「strcpy(dt[1],"日本太郎");」がエ ラーにならず、かつ期待通りに処理できてしまう理由は、同じアドレスであ るためです。 もし、 name がこの場所以外に定義されている場合は、期待通りに処理は されません。 また、この書き方はソースを見直したときに、「?」つきやすいので、構造 体の場合は、メンバ変数を指定する事で、「目的を明示」「メンバ変数の位 置が変わっても処理を変更しなくて良い」という恩恵を受けることが出来ま す。 (2) int型等のプリミティブ型以外は、このような書き方をしないほうが良いで す。先輩から教わりました。 (詳しい理由は分かりませんが、処理時間等に影響するらしい) なので、memcpy関数を使うことをお勧めします。 文字列関数のstrncpy関数と使い方が似ていますが、大きな違いはNULL終端 をこの関数では意識しないことです。第3引数で指定したバイト数を一度に 処理します。 なので、「memcpy(dt[9].name,"日本太郎",80);」とするところを大げさに 「memcpy(dt[9].name,"日本太郎",100);」とすると、もれなくメモリ破壊 に遭遇します。 本題に戻り、ここでは、 「memset(&dt[5],&dt[1],sizeof( struct person ))」 とする事をお勧めします。
その他の回答 (6)
- Tacosan
- ベストアンサー率23% (3656/15482)
私も #1 と同様, 「構造体」というものについて再確認した方がよいと思います. このままでは, 近い将来に混乱して全く分からなくなってしまう可能性があります. あと, 「配列」や「ポインタ」の概念も念のため見直しておいたほうがよいでしょう (配列名dtに「"日本太郎"」を設定する, などの書き方が怪しい). 以下蛇足: 構造体の代入ができない古代の処理系ならいざ知らず, 今では memcpy よりも構造体の代入を使う方が素直だし精神衛生上もよいと思います>#5. 代入を使ったとしても, memcpy 相当の処理に変える可能性は十分あります. 少なくとも型の違いは検出してくれる. ついでにいうと, dt を構造体の配列で定義したときに strcpy(dt[1],"日本太郎"); をエラーにしない処理系はさっさと捨てるべきだと思う.
お礼
ご回答ありがとうございます。 もっと構造体について勉強してみます! C初心者なのですが、ビギナー向けの参考書に書いてあった、プログラムなのに、このくらいの事を理解できなくて、本当に悔しいです(T_T) 構造体の配列について新しい質問を立てるので、お答えいただければ幸いです。
- aris-wiz
- ベストアンサー率38% (96/252)
細かいですが、少々突っ込みを。。。 >「char name[80];」は、同じアドレスになります。 文脈からすると、同じ”オフセットアドレス”? >「memset(&dt[5],&dt[1],sizeof( struct person ))」 memcpyの間違い?
- aris-wiz
- ベストアンサー率38% (96/252)
>dt[1]~dt[10]までの10個の変数名が >あるという考え方でよろしいのでしょうか? プログラミング言語には0から始まるか1から始まるか決まりがあります C言語は「0オリジン」の言語なので dt[0]~dt[9]の10個になります。
お礼
ご回答ありがとうございます。 >dt[0]~dt[9]の10個になります。 上記の10個ですよね (;^_^) ご指摘ありがとうございます。
- aris-wiz
- ベストアンサー率38% (96/252)
構造体とは簡単に言えば、変数を集めた名前付きの箱です。 今回でいえば、nameというchar[80]型の変数と heightとweightという int型変数を集めた、personという名前の箱です。 >struct person dt[10]; struct personは箱の名前ですから、 ここで用意されるdtは、文字列用の配列ではなく、 personという箱の配列になります。 (1)の部分で strcpy(dt[1].name,"日本太郎"); となっているのは、配列dtの中にある、dt[1]の要素の 箱の中にある、nameというchar[80]型変数に"日本太郎"を コピーするとなるわけです。 (2)の部分は、 構造体は同じ名前である以上同じサイズ、同じ構造をとります。 なので、C言語ではその構造体の変数どうしで代入を 行うことでコピーができるのです。 つまり(1)で作ったデータをdt[5]にそのまま コピーしているわけです。
お礼
ご回答ありがとうございます。 dt[1]~dt[10]までの10個の変数名があるという考え方でよろしいのでしょうか?
- php504
- ベストアンサー率42% (926/2160)
構造体でないなら char name[80]; int height; int weight; strcpy(name,"日本太郎"); weight=70; height=180; で良いのはわかりますよね 配列でない構造体の場合は struct person data; strcpy(data.name,"日本太郎"); data.weight=70; data.height=180; になります 質問の例はこの構造体がさらに配列になっているだけです。
- asuncion
- ベストアンサー率33% (2127/6289)
そのstrcpyは、構造体の配列の要素であるdt[1]の メンバーnameに、 "日本太郎"という内容を 格納するためのものです。 構造体の概念を今一度確認なさってみては いかがでしょうか。
お礼
ご回答ありがとうございます。 そうですねもうちょっと構造体を勉強しなおしてみます!
お礼
ご回答ありがとうございます。 >まずは、「strcpy(dt[1].name,"日本太郎");」を、説明すると >変数 dt の 配列2番目にある 構造体変数name がさすポインタに >"日本太郎" をコピーする。 >となります。 >dt 及び dt[ N ]をベースのアドレスと、メンバ変数 >「char name[80];」は、同じアドレスになります。 >mufflerさんがイメージしている書き方「strcpy(dt[1],"日本太郎");」が >エラーにならず、かつ期待通りに処理できてしまう理由は、同じアドレス >であるためです。 上記の内容もう少しで分かりそうなのですが、まだよく分からない状態です。 構造体の配列について新しい質問を立てるので、お答えいただければ幸いです。