• ベストアンサー

構造体の配列について(2)

前回「構造体の配列について」という質問タイトルで、質問させていただいたのですが、理解が完全ではないため同じようなプログラム内容ではありますが、疑問を書かせていただきます。よろしくお願いします。 ----------------------------------------------------------------------- #include<stdio.h> #include<string.h> struct person{ char name[1];    //// (1) //// int height; int weight; }; int main() { struct person dt[10]; strcpy(dt[0].name,"日本一郎"); strcpy(dt[2].name,"関東次郎"); strcpy(dt[9].name,"関西三郎"); dt[1].weight=99; dt[1].height=168; printf("%s %s %s %d %d \n",dt[0].name,dt[2].name,dt[9].name,dt[1].weight,dt[1].height); return 0; } ----------------------------------------------------------------------- 以上のプログラムの(1)の部分で、文字を1文字しか格納出来ないのに、 strcpy(dt[0].name,"日本一郎"); strcpy(dt[2].name,"関東次郎"); strcpy(dt[9].name,"関西三郎"); としても何故正しく実行できるのかわかりません。 前回いろいろとご回答いただいたのに、しっかりと理解できない者ですが、教えていただければ嬉しいです。

質問者が選んだベストアンサー

  • ベストアンサー
  • S117
  • ベストアンサー率40% (18/45)
回答No.13

>#11のお礼 ◎2 ちょっと違います。この場合height weightともにまだデータが破壊されていません。 私の回答が少しわかりづらかったですね。補足しておきます。 私は2つの現象について言及しています。 例1 >不正に書き換えた後(メモリ破壊)に、そこになにかを書き込むまえに読み込むと、値が不正になっているのです。 ---------------------------------------------- dt[0].height = 168; //(1) dt[0].weight = 99; //(2) strcpy( dt[0].name, "日本一郎" ); //(3) printf( "氏名: %s\n", dt[0].name ); printf( "身長: %d\n", dt[0].height ); printf( "体重: %d\n", dt[0].weight ); ---------------------------------------------- この場合、(1),(2)で設定された値が(3)で不正に書き換えられています。そして、不正な値が表示されるでしょう。 例2 >そこ(破壊された場所)に値を書き込む操作自体には影響が出ません。 ---------------------------------------------- strcpy( dt[0].name, "日本一郎" ); //(1) dt[0].height = 168; //(2) dt[0].weight = 99; //(3) //printf( "氏名: %s\n", dt[0].name ); //(4) printf( "身長: %d\n", dt[0].height ); printf( "体重: %d\n", dt[0].weight ); ---------------------------------------------- この場合も、(1)が不正なデータの書き換えをしています。 ところが、その後(2)(3)でデータを書き換えます。 結果、表示時に身長と体重は正常なデータです。 なお、(4)で名前を表示しようとすると、データの内容が1文字目しか維持できる保証がないために、何が起きるかわかりません。なので、コメントアウトしてあります。 なお、#9のお礼では、あなたは例2の場合に(2)(3)の操作自体が不正だと考えているように読めましたので、#11での指摘となりました。

muffler
質問者

お礼

>strcpy( dt[0].name, "日本一郎" ); //(1) >dt[0].height = 168; //(2) >dt[0].weight = 99; //(3) >//printf( "氏名: %s\n", dt[0].name ); >printf( "身長: %d\n", dt[0].height ); >printf( "体重: %d\n", dt[0].weight ); (1)により「height」、「weight」のメモリに不正なデータ書き換えを行っても、(2)、(3)を後に書くことにより、「height」、「weight」のメモリに正常なデータを書き換えられるということですね!

その他の回答 (13)

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.14

今までのやり取りを見ていて、やはり実際のメモリイメージを見たほうが理解できると思いますので簡易メモリダンプを付けてみました。 #include <stdio.h> struct person{ char name[1]; int height; int weight; }; void memdump(void *pmem,int size);//プロトタイプ int main() { struct person dt[2]; memset(dt,0xff,sizeof(dt));//0xffで埋め尽くし memdump(dt,sizeof(dt)); dt[0].height = 168; memdump(dt,sizeof(dt)); dt[0].weight = 99; memdump(dt,sizeof(dt)); strcpy( dt[0].name, "abcdefghijklm" ); memdump(dt,sizeof(dt)); printf( "氏名: %s\n", dt[0].name ); printf( "身長: %d\n", dt[0].height ); printf( "体重: %d\n", dt[0].weight ); return 0; } // 簡易メモリダンプ void memdump(void *pmem,int size) { unsigned char *pbyte = (char*)pmem; int i; for( i=0 ; i<size ; i++ ) { if( (0x20 <= pbyte[i]) && (pbyte[i] <=0x7f) ) { printf( " %c", pbyte[i] ); } else { printf( " ." ); } if( (i%4)==3 ) printf( " " ); } printf( "\n" ); for( i=0 ; i<size ; i++ ) { printf( "%02X", pbyte[i] ); if( (i%4)==3 ) printf( " " ); } printf( "\n" ); } 日本語表示は面倒だったので英数字オンリーです。それとint系の数値はリトル・エンディアンですので値の並びが4バイトで逆に並んでいるので注意してください。 実行結果は、こんな感じです。 . . . . . . . . . . . . . . . . . . . . . . . . FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF . . . . . . . . . . . . . . . . . . . . . . . . FFFFFFFF A8000000 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF . . . . . . . . c . . . . . . . . . . . . . . . FFFFFFFF A8000000 63000000 FFFFFFFF FFFFFFFF FFFFFFFF a b c d e f g h i j k l m . . . . . . . . . . . 61626364 65666768 696A6B6C 6D00FFFF FFFFFFFF FFFFFFFF 氏名: abcdefghijklm 身長: 1751606885 体重: 1818978921 上のダンプで数値のA8000000が168で63000000が99になります。このダンプを活用して色々と試してみてください。

muffler
質問者

お礼

ご回答ありがとうございます。 まだ理解していない関数があるため、分からない部分はありますが、このプログラムにより、メモリイメージが可視化できるので、理解できれば、かなり理解が深まると思います!

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.12

>◎2のようにメモリ破壊部に「.height」、「.weight」は設定できるが、値が不正になっているという事でしょうか? >dt[0].height = 168; >dt[0].weight = 99; ここまでは正しいです。ところが、 >strcpy( dt[0].name, "日本一郎" ); これで、nameのために確保してあった大きさ(1バイト)を超えて書込んでいます。 heightとweightの領域の内容を破壊しています。 その結果、 >printf( "身長: %d\n", dt[0].height ); >printf( "体重: %d\n", dt[0].weight ); ここで出力しているheightとweightの値が、意図とは異なる内容になってしまいます。

muffler
質問者

お礼

>dt[0].height = 168; >dt[0].weight = 99; 上記までは確保されているメモリにしっかりと設定されるが、 >strcpy( dt[0].name, "日本一郎" ); この1文で「height」と「weight」のメモリが破壊され意図と異なる内容になってしまうということですね!

  • S117
  • ベストアンサー率40% (18/45)
回答No.11

>#9へのお礼 いや、やっぱり理解できてないと思います。 メモリ破壊というのは、メモリのデータを不正に書き換えることを意味しています。(メモリのデータが破壊されるのを省略してメモリ破壊と称している。) なので、そこに値を書き込む操作自体には影響が出ません。 不正に書き換えた後(メモリ破壊)に、そこになにかを書き込むまえに読み込むと、値が不正になっているのです。 それぞれの詳しいことについては、各回答者がすでに書いているので省きます。 以下は、直接質問と関係ないですが、アドバイスです。 もう少し落ち着いて、じっくりと各回答を読みましょう。また、一般にプログラムの動作というものはとても厳密です。なのでそれについての解説の文章もとても厳密なので、変に省略したり言い換えたりしない方が、確実に理解できます。また、自分で説明するときも意味が正しいかよく考えてください。

muffler
質問者

お礼

ご回答ありがとうございます。 >そこに値を書き込む操作自体には影響が出ません。 >不正に書き換えた後(メモリ破壊)に、そこになにかを書き込むまえに読 >み込むと、値が不正になっているのです。 以上の内容は、 ◎1------------------------------------- struct person{ char name[1]; int height; int weight; }; int main() { struct person dt[10]; //dt[0].height = 168; //dt[0].weight = 99; strcpy( dt[0].name, "日本一郎" ); printf( "氏名: %s\n", dt[0].name ); return 0; } ------------------------------------- ◎2------------------------------------- struct person{ char name[1]; int height; int weight; }; int main() { struct person dt[10]; dt[0].height = 168; dt[0].weight = 99; strcpy( dt[0].name, "日本一郎" ); printf( "氏名: %s\n", dt[0].name ); printf( "身長: %d\n", dt[0].height ); printf( "体重: %d\n", dt[0].weight ); return 0; } ------------------------------------- ◎1に対して、◎2のようにメモリ破壊部に「.height」、「.weight」は設定できるが、値が不正になっているという事でしょうか?

noname#144013
noname#144013
回答No.10

こんにちは。 > dt[0].height = 168; > dt[0].weight = 99; > strcpy( dt[0].name, "日本一郎" );  //// (1) //// > > (1)を設定した時点で、確保したメモリ領域を超えてしまい、「.height」、「.weight」のメモリを破壊 > してしまう。という理解でよろしいでしょうか? そのとおりです。 もちろん、「.name」 が充分にエリア確保が行われているのであれば、問題ありません。 ですので、C言語(に限りませんが)でこういった処理を行う場合、プログラマーは、メモリイメージを 想像しながら、「この記述で問題がないか?」などを意識してコードを記述するクセをつけた方が良い かもしれません。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.9

#5 に対して「dt[0].namneの内容がおかしくなるという感じですかね?」って書いてるけど, まさにその実例が #3 だってことは理解できてる?

muffler
質問者

お礼

strcpy(dt[1].name,"北風小僧"); 確保した領域を超えて以上の文字列を設定していて、 dt[1].weight=99; dt[1].height=168; を破壊されたメモリに設定しようとしているため、不具合が起きるでよいでしょうか? 皆さんのアドバイスのおかげで、メモリのイメージが出来るようになりました!

noname#144013
noname#144013
回答No.8

こんにちは。 >確保したメモリ領域を越えて、メモリを使ったため不具合が起こっているという考えなのでしょうか? 『考え』というよりも、実際にそういう現象(他のエリアを破壊する不具合)が発生してしまうということです。 ご質問のプログラムでは、たまたま、壊されたエリアに対して参照・表示等の処理を行っていませんので、 不具合が目に見える形として表面に現れていないだけです。 繰り返しになってしまいますが、少し置き換えた例を上げてみます。 注)下記の例では、char型のデータサイズ=1バイト、int型のデータサイズ=4バイト、   文字コード1文字(全角)のコードサイズ=2バイトとし、また、コンパイラの設定と   して、構造体のアライメント指定(境界サイズ指定)を8バイトとした場合の例です。 ■ケース1(正常なケース)    ---------------------------------------------------    struct person{      char name[64];   //氏名 ←エリア確保が充分な場合                  //(氏名の文字列長が64バイト未満と限定した場合)      int height;      //身長      int weight;      //体重    };    struct person dt[10];    dt[0].height = 168;    dt[0].weight = 99;             //@1    strcpy( dt[0].name, "日本一郎" );   //@2    printf( "氏名: %s\n", dt[0].name );    printf( "身長: %d\n", dt[0].height );    printf( "体重: %d\n", dt[0].weight );  //@3    ---------------------------------------------------   1)@1の実行後のdt[0]のメモリイメージ    ┌─── ~~ ────┬───┬───┐    │     不定        │ 168 │ 99  │    └─── ~~ ────┴───┴───┘         .name          .height  .weight   2)@2の実行後のdt[0]のメモリイメージ    ┌─── ~~ ────┬───┬───┐    │ "日本一郎"+'\0'    │ 168 │ 99  │    └─── ~~ ────┴───┴───┘         .name          .height  .weight    ※.nameエリア内において、格納された文字列の末尾コード('\0')以降の余った     領域は不定データのままです。   3)@3の実行後の表示結果    氏名: 日本一郎    身長: 168    体重: 99 ■ケース2(不具合が発生するケース)    ---------------------------------------------------    struct person{      char name[1];   //氏名 ←エリア確保が充分でない場合      int height;     //身長      int weight;     //体重    };    struct person dt[10];    dt[0].height = 168;    dt[0].weight = 99;             //@1    strcpy( dt[0].name, "日本一郎" );   //@2    printf( "氏名: %s\n", dt[0].name );    printf( "身長: %d\n", dt[0].height );    printf( "体重: %d\n", dt[0].weight );  //@3    ---------------------------------------------------   1)@1の実行後のdt[0]のメモリイメージ    ┌───┬───┬───┐    │不定  │ 168 │ 99  │    └───┴───┴───┘     .name   .height  .weight    ※.nameの宣言時の配列個数は1個ですが、実際はアライメントにより4バイト分     確保されます。(※ただしコンパイラなどの環境設定に依存します。)   2)@2の実行後のdt[0]のメモリイメージ    ┌───┬───┬───┐    │"日本"  "一郎"  '\0'   │    └───┴───┴───┘     .name   .height  .weight    ※ここで、.nameエリアの先頭アドレスから、文字列 "日本一郎" がコピーされて     しまうので、.nameエリアの境界を越えて .height以降のエリアにも文字列がコピー     されてしまいます。(文字列データは末尾コード'\0'も含まれます)     従って、それまでセットされていたデータは上書きされて(壊されて)しまいます。   3)@3の実行後の表示結果    氏名: 日本一郎  ←ここは、正常に氏名が表示されてしまいます。                 printfの書式で %s と指定されていて、それに対応する引数が 文字列                 エリアの先頭ポインタ(dt[0].name)となっていますので、printf関数は                 その先頭ポインタから末尾コード'\0'が現れるまでのデータを文字列と                 みなして表示出力します。    身長: xxxxxx   ←ここは本来、数値の168(0x000000A8)が表示されるのを期待すべき                 ところですが、上書きされた(壊された)ため、想定外のデータが表示                 されてしまいます。                 (実際は、文字列”一郎"の文字コードが数値として表示されてしまう)    体重: 0       ←ここは本来、数値の99(0x00000063)が表示されるのを期待すべき                 ところですが、上書きされた(壊された)ため、想定外のデータが表示                 されてしまいます。                 (実際は、エリアの最初の1バイトが文字列の末尾コード'\0'で上書き                  され、結果として数値の0が表示されてしまいます)

muffler
質問者

お礼

ご回答ありがとうございます。 ご回答にあるメモリイメージとてもわかりやすいです。 char name[1];    int height;    int weight; 以上の変数名を宣言して、必要なメモリが確保されるのですが、 dt[0].height = 168; dt[0].weight = 99;             strcpy( dt[0].name, "日本一郎" );  //// (1) //// (1)を設定した時点で、確保したメモリ領域を超えてしまい、「.height」、「.weight」のメモリを破壊してしまう。 という理解でよろしいでしょうか?

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.7

構造体の配列に限らず、一般に配列において、 定義した範囲を超えて代入してはいけません。 それは、プログラムを書く側が注意しなければなりません。 C言語の処理系は、ほとんど何もしてくれません。せいぜい、実行時にプログラムを異常終了させてくれるくらいです。

muffler
質問者

お礼

>構造体の配列に限らず、一般に配列において、 >定義した範囲を超えて代入してはいけません。 以上のご回答しっかり頭に入れて起きます!

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.6

>(1)の順番で、メンバ名を宣言したら、(2)も(1)と同じ順番で書かなければいけないんですかね?? そういうことはありません。 構造体の定義順と、メンバーへのアクセス順には 何も関係がありません。

muffler
質問者

お礼

ご回答ありがとうございます。 メンバーへのアクセス順には何も関係がないという事理解できました! ---------------------------------------------- struct person{ char name[80]; int height; int weight; }; int main() { struct person dt[10]={"日本一郎",180,70}; printf("%d %d %s\n",dt[0].weight,dt[0].height,dt[0].name); --------------------------------------------------- 以上のように{ }を使って、初期化する場合はメンバを宣言した順に、{ }の中身も宣言しなければいけないですよね?

  • fatbowler
  • ベストアンサー率48% (26/54)
回答No.5

初心者にやさしく書きますね。 strcpy(dt[0].name,"日本一郎"); が一見正しく動いているように見えるのは、このコードが 「指定されたアドレスから始まる領域に、"日本一郎"という 文字列をコピーする」 という意味だからです。 領域が確保されているかどうかはお構いなしにメモリに値を セットしてしまう、ということを平気でやってしまうのがC言語の 特徴でもあります。 確保した領域を超えて値をセットしてしまうことを「メモリ破壊」 と呼び、メモリリーク(メモリ解放漏れ)と共に見つけにくい バグの代表格です。 例にdt[0].weightやdt[0].heightではなく、dt[1].weighやtdt[1].height を使ったのは、dt[0].weightやdt[0].heightに値を入れると、 dt[0].nameの内容がおかしくなったからではありませんか? 問題が起こっているのに、敢えて見えないふりをしているだけで、 正しく実行できているとは言えないのです。

muffler
質問者

お礼

ご回答ありがとうございます。 >領域が確保されているかどうかはお構いなしにメモリに値を >セットしてしまう、ということを平気でやってしまうのがC言語の >特徴でもあります。 >確保した領域を超えて値をセットしてしまうことを「メモリ破壊」 >と呼び、メモリリーク(メモリ解放漏れ)と共に見つけにくい >バグの代表格です。 上記の内容、今勉強中ですが、大まかにはイメージできるようになりました! strcpy(dt[0].name,"日本一郎");に対して、dt[1].weight=99; dt[1].height=168;というようにdt「1」に設定したのは、たまたま ですが(;^_^)、dt[0]としてしまうと破壊されたメモリにアクセスしてしまい、dt[0].namneの内容がおかしくなるという感じですかね?

muffler
質問者

補足

struct person{ char name[1];     //// int height;      //// (1) int weight;      //// }; int main() { struct person dt[10]; strcpy(dt[1].name,"日本一郎");    //// dt[1].height=168;            //// (2) dt[1].weight=99;           //// (1)の順番で、メンバ名を宣言したら、(2)も(1)と同じ順番で書かなければいけないんですかね??

  • chie65535
  • ベストアンサー率43% (8519/19365)
回答No.4

>何故正しく実行できるのかわかりません。 「確保した領域を越えて他人のメモリを使ったとしても、他人がそのメモリを使わない限り、自分に不都合は起きない」ので「正しく実行」してしまうのです。 intが4バイトと仮定して、メモリの中身を見ると +000 dt[0].name[0] +001 空き +002 空き +003 空き +004  | dt[0].height +007 +008  | dt[0].weight +011 +012 dt[1].name[0] +013 空き +014 空き +015 空き +016  | dt[1].height +019 +020  | dt[1].weight +023 +024 dt[2].name[0] +025 空き +026 空き +027 空き +028  | dt[2].height +031 +032  | dt[2].weight +035 略 +108 dt[9].name[0] +109 空き +110 空き +111 空き +112  | dt[9].height +115 +116  | dt[9].weight +119 となっています。 ここで strcpy(dt[0].name,"日本一郎"); を実行すると +000 '日'の1バイト目 dt[0].name[0] +001 '日'の2バイト目 空き +002 '本'の1バイト目 空き +003 '本'の2バイト目 空き +004  | '一郎'の4バイト dt[0].height +007 +008  | 1バイト目に'\0' dt[0].weight +011 +012 不変 dt[1].name[0] +013 不変 空き +014 不変 空き +015 不変 空き +016  | 不変 dt[1].height +019 +020  | 不変 dt[1].weight +023 +024 不変 dt[2].name[0] +025 不変 空き +026 不変 空き +027 不変 空き +028  | 不変 dt[2].height +031 +032  | 不変 dt[2].weight +035 略 +108 不変 dt[9].name[0] +109 不変 空き +110 不変 空き +111 不変 空き +112  | 不変 dt[9].height +115 +116  | 不変 dt[9].weight +119 となります。次に strcpy(dt[2].name,"関東次郎"); を実行すると +000 '日'の1バイト目 dt[0].name[0] +001 '日'の2バイト目 空き +002 '本'の1バイト目 空き +003 '本'の2バイト目 空き +004  | '一郎'の4バイト dt[0].height +007 +008  | 1バイト目に'\0' dt[0].weight +011 +012 不変 dt[1].name[0] +013 不変 空き +014 不変 空き +015 不変 空き +016  | 不変 dt[1].height +019 +020  | 不変 dt[1].weight +023 +024 '関'の1バイト目 dt[2].name[0] +025 '関'の2バイト目 空き +026 '東'の1バイト目 空き +027 '東'の2バイト目 空き +028  | '次郎'の4バイト dt[2].height +031 +032  | 1バイト目に'\0' dt[2].weight +035 略 +108 不変 dt[9].name[0] +109 不変 空き +110 不変 空き +111 不変 空き +112  | 不変 dt[9].height +115 +116  | 不変 dt[9].weight +119 となります。次に strcpy(dt[9].name,"関西三郎"); を実行すると +000 '日'の1バイト目 dt[0].name[0] +001 '日'の2バイト目 空き +002 '本'の1バイト目 空き +003 '本'の2バイト目 空き +004  | '一郎'の4バイト dt[0].height +007 +008  | 1バイト目に'\0' dt[0].weight +011 +012 不変 dt[1].name[0] +013 不変 空き +014 不変 空き +015 不変 空き +016  | 不変 dt[1].height +019 +020  | 不変 dt[1].weight +023 +024 '関'の1バイト目 dt[2].name[0] +025 '関'の2バイト目 空き +026 '東'の1バイト目 空き +027 '東'の2バイト目 空き +028  | '次郎'の4バイト dt[2].height +031 +032  | 1バイト目に'\0' dt[2].weight +035 略 +108 '関'の1バイト目 dt[9].name[0] +109 '関'の2バイト目 空き +110 '西'の1バイト目 空き +111 '西'の2バイト目 空き +112  | '三郎'の4バイト dt[9].height +115 +116  | 1バイト目に'\0' dt[9].weight +119 となります。次に dt[1].weight=99; dt[1].height=168; を実行すると +000 '日'の1バイト目 dt[0].name[0] +001 '日'の2バイト目 空き +002 '本'の1バイト目 空き +003 '本'の2バイト目 空き +004  | '一郎'の4バイト dt[0].height +007 +008  | 1バイト目に'\0' dt[0].weight +011 +012 不変 dt[1].name[0] +013 不変 空き +014 不変 空き +015 不変 空き +016  | 168 dt[1].height +019 +020  | 99 dt[1].weight +023 +024 '関'の1バイト目 dt[2].name[0] +025 '関'の2バイト目 空き +026 '東'の1バイト目 空き +027 '東'の2バイト目 空き +028  | '次郎'の4バイト dt[2].height +031 +032  | 1バイト目に'\0' dt[2].weight +035 略 +108 '関'の1バイト目 dt[9].name[0] +109 '関'の2バイト目 空き +110 '西'の1バイト目 空き +111 '西'の2バイト目 空き +112  | '三郎'の4バイト dt[9].height +115 +116  | 1バイト目に'\0' dt[9].weight +119 のようになります。 メモリの中では、dt[0].height、dt[0].weight、dt[2].height、dt[2].weight、dt[9].height、dt[9].weightが文字列に潰されて「大変な事になって」います。 でも「だれも、それに代入もしてないし、参照も表示もしてない」ので「大変な事になっていても、何の影響も無い」のです。 なので「他人のメモリをどんだけ壊そうが、何の影響も無いなら、正しく動いてしまう」のです。 文字列が「全角文字で4文字」だったから、壊れたのが8バイトで済み、大きな影響が無かっただけです。(1バイトしか無い領域に、8バイト+終端1バイトの9バイトを書き込んだので、壊れたバイト数は、9-1=8で、8バイトです) 名前を長くして、例えば strcpy(dt[0].name,"日本一郎"); を strcpy(dt[0].name,"じゅげむじゅげむごこうのすりきれかいじゃりすいぎょのすいぎょうまつうんらいまつふうらいまつくうねるところにすむところやぶらこうじのやぶこうじぱいぽぱいぽぱいぽのしゅーりんがんしゅーりんがんのぐーりんだいぐーりんだいのぽんぽこぴーのぽんぽこなーのちょうきゅうめいのちょうすけ"); に変えてみましょう。 多分、構造体配列の領域を越えて、メモリ中の色々な重要データも破壊するので、プログラムが例外を吐いて落ちるか、不正なアクセスをしたと言う警告が出て止まります。

muffler
質問者

お礼

いつもご丁寧に詳しくご回答ありがとうありがとうございます。 >「確保した領域を越えて他人のメモリを使ったとしても、他人がそのメモリ >を使わない限り、自分に不都合は起きない」ので「正しく実行」してしまう >のです。 上記の内容とメモリのイメージ頑張って理解してみます!

関連するQ&A

  • 構造体の配列について

    --------------------------------------------------- #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)の部分もよくイメージがわきません。 以上、どのような仕組みになっているのか教えていただければ嬉しいです。

  • C言語/構造体の宣言と初期設定について

    C言語初心者です。 私が使用している参考書の記載に誤りがあるのか確認したくて質問させて頂きました。 宜しくお願い致します。 struct person{  char name[40];  int height;  int weight; } struct person dt = {"山田太郎", 70, 180}; printf("%s %d %d\n", dt.name, dt.weight, dt.height); このコードで出力されるのは、 山田太郎 70 180 とのことですが、 宣言時のメンバの順番と、 初期化時の値の順番が、 上の記述だと一致していないように私には思えます。 参考書にある上記の記載は、はたして、正しいのでしょうか?

  • 構造体についてです。

    身体測定表を作っていて最初に作ったデータを変更して表示したいのですがNo1の168cm→162cm No2の74kg→74.5kg  No3の20歳→19歳 No4の田中三郎→小林三郎 (No3と4は構造体ポインタを使ってデータを変更) 全データを表示させてその後No1と3の名前~体重を丸ごと入れ替えて全データを表示させたいのですがエラーがでてしまいます。 分かる人がいましたらどこを直したらいいか教えて下さい。 #include <stdio.h> #include <string.h> struct data{ int no; char name[21]; int age; int height; float weight; }; struct data *sp; void main(){ int i; struct data a[4]={ {1,"鈴木太郎",23,168,60}, {2,"山本次郎",17,180,74}, {3,"山田花子",20,156,53}, {4,"田中三郎",35,172,68}, }; struct data b; for(i=0;i<4;i++){ printf("番号 :%d\n",a[i].no); printf("名前 :%s\n",a[i].name); printf("年齢 :%d歳\n",a[i].age); printf("身長 :%dcm\n",a[i].height); printf("体重 :%4.1fkg\n\n",a[i]. weight); } a[0].height=162; a[1].weight=74.5; *sp[2].age=19; strcpy(*sp[3].name,"小林三郎"); for(i=0;i<=4;i++){ b=a[0]; a[0]=a[2]; a[2]=b; a[0].no=1; a[2].no=3; } for(i=0;i<=4;i++){ printf("番号 :%d\n",a[i].no); printf("名前 :%s\n",a[i].name); printf("年齢 :%d歳\n",a[i].age); printf("身長 :%dcm\n",a[i].height); printf("体重 :%4.1fkg\n\n",a[i].weight); } }

  • 構造体配列

    いつもお世話になっています。 今日構造体配列を勉強した際に下の演習をしていたのですが、いまいち基礎的な関数や配列のことやコマンドライン引数のことが理解できていません。一応自分なりにプログラムを書いてみたのですが、エラーがでます。 どなたかアドバイス・ご指摘・解説・例などをおねがいいたします。 問題はコマンドライン引数で人数を指定し,人数分のデータを標準入力(キーボード)から構造体配列に入力し,標準出力(ディスプレイ)に出力するプログラムです。 #include<stdio.h> typedef struct{ char name[100]; int age; double height; double weight; } PERSONAL_DATA1; typedef struct{ int person[10]; }PERSONAL_DATA2; PERSONAL_DATA1 input_personal_data(int num); void output_personal_data(PERSONAL_DATA2 person[10],int num); int main(int argc, char *argv[]){ PERSONAL_DATA1 x; int num,i; char person[10]; if(argc != 2){ printf("Usage ./test number"); return 0; } num=atoi(argv[1]); for(i=0;i<10&&i<num;i++){ person[i]=input_personal_data(); output_personal_data(person,num); return 0; } } PERSONAL_DATA input_personal_data(void){ PERSONAL_DATA1 x; printf("name>"); scanf("%c" ,&x.name); printf("age>"); scanf("%d" ,&x.age); printf("height>"); scanf("%lf" ,&x.height); printf("weight>"); scanf("%lf" ,&x.weight); return x; } void output_personal_data(PERSONAL_DATA2 person[10],int num){ PERSONAL_DATA1 x; printf("name>>%s\n" ,x.name); printf("age>>%d\n" ,x.age); printf("height>>%lf[cm]\n" ,x.height); printf("weight>>%lf[kg]\n" ,x.weight); } またコマンドライン引数で指定したデータファイルAから入力した個人データ集合を構造体配列に取り込み,標準出力(ディスプレイ)と同じくコマンドライン引数で指定したデータファイルBへファイル出力に出力するプログラムというおまけの問題もあります。 こちらの問題のヒントもいただけませんか?

  • C言語のプログラムで...

    下のプログラムは参考書にあったサンプルプログラムなのですが /* 関数の宣言 */ int print_struct(struct person dat); のところはなぜint型なのですか? #include <stdio.h> #include <string.h> /* 構造体の定義 */ struct person { char name[20]; /* 名前 */ double height; /* 身長 */ double weight; /* 体重 */ int bpl; /* 最低血圧 */ int bph; /* 最高血圧 */ }; /* 関数の宣言 */ int print_struct(struct person dat); /* main関数 */ int main(void) { /* 変数の宣言 */ struct person dat; /* 構造体のメンバーに値を代入 */ strcpy(dat.name,"山田太郎"); dat.height = 173.5; dat.weight = 63.0; dat.bpl = 98; dat.bph = 113; /* struct person関数を実行 */ print_struct(dat); return 0; } /* print_struct関数 */ int print_struct(struct person dat) { /* 画面に出力 */ printf("%s\n",dat.name); printf("%f\n",dat.height); printf("%f\n",dat.weight); printf("%d\n",dat.bpl); printf("%d\n",dat.bph); return 0; }

  • プログラミング構造体について。

    include<stdio.h> #include<stdlib.h> #include<string.h> struct person{ char name[10]; int gender; int age; }; void printPersonList(struct person *person_p, int size); void outputPersonList(struct person *person_p, int size); double getAverageOfAge(struct person *person_p, int size); int countMales(struct person *person_p, int size); int countFemales(struct person *person_p, int size); int main(void){ struct person *person_p; int i, count, gender, age, maleCount, femaleCount; char name[20]; double average; printf("登録する人数を入力してください。\n"); scanf("%d", &count); person_p = (struct person*)malloc(sizeof(struct person)* count); for(i=0; i < count; i++){ printf("名前・性別(男性:0, 女性:1)・年齢をスペース区切りで入力してください。\n"); scanf("%s %d %d", name, &gender, &age); strcpy((person_p + i) -> name, name); (person_p + i) -> gender = gender; (person_p + i) -> age = age; } printPersonList(person_p, count); outputPersonList(person_p, count); average = getAverageOfAge(person_p, count); printf("平均年齢:%f\n", average); maleCount = countMales(person_p, count); femaleCount = countFemales(person_p, count); printf("男性:%d名, 女性:%d名\n", maleCount, femaleCount); free(person_p); return 1; } void printPersonList(struct person *person_p, int size){ int i; printf("登録リスト\n"); printf(" name | gender | age\n"); printf("----------+--------+-----\n"); for(i=0; i < size; i++){ printf("%10s | %1d | %2d\n", (person_p + i) -> name, (person_p + i) -> gender, (person_p + i) -> age); } } void outputPersonList(struct person *person_p, int size){ FILE *output; int i; if((output = fopen("meibo.c", "w")) == NULL){ printf("meibo.cを開けませんでした。\n"); return; } for(i=0; i < size; i++){ fprintf(output, "%s, %d, %d\n", (person_p + i) -> name, (person_p + i) -> gender, (person_p + i) -> age); } fclose(output); } 残り3つの関数をすべて定義する(それぞれ10行程度) getAverageOfAge, countMales, countFemales どう定義すればいいのか教えてください。お願いします。

  • C言語の構造体の配列の扱い方

    #include <stdio.h> struct record { char name[10]; float height; float weight; }; /* 各データを、長さ 5 の record 構造体の配列に代入 */ struct record records[5] = { { "yasuo", 170.5, 70.5 }, { "hideaki", 176.5, 65.8 }, { "nobu", 166.5, 58.2 }, { "yuichi", 168.0, 65.4 }, { "nori", 152.7, 68.6 } }; float std_weight(struct record r){ /* 標準体重 = (身長 - 100) * 0.9 */ return (r.height - 100.0) * 0.9; } float std_weight(struct record r); となっている時に、メイン関数にて、5人の身長をもとめる方法と適正標準体重を求める方法を教えてください。構造体の配列を一括で扱うコードがいまいちわかりません。おねがいします。

  • リスト構造がうまく動きません!!

    C言語で以下のようなプログラムを作りました。 「main関数内で下記のデ-タを構造体に格納し、キーボードから入力された名前と該当する学生の身長と年齢を画面に表示するプログラムを作成せよ。」というものです。 このプログラムはコンパイルは通るのですが、2人目以降のデータを表示させようとしても表示してくれません。。。どうもリスト構造のfor文がうまくループしていないみたいなんですが原因が分かりません。どなたか原因の分かる方アドバイスをお願いしますm(_ _)m #include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct data{ char name[20]; int height; int age; struct data *next; }person; person *newperson(void); int main(void){ char namae[20],s[20]; int toshi,shinchou,i; person *head; person *list; person *nlist; person *LIST; head = newperson(); nlist = head; printf("データを入れてください。\n"); for(i=0;i<=4;i++){ scanf("%s",namae); scanf("%d",&shinchou); scanf("%d",&toshi); list = newperson(); strcpy(list ->name,namae); list -> height = shinchou; list -> age = toshi; nlist -> next = list; nlist = list; } printf("知りたい人の名前は?\n"); scanf("%s",s); for(LIST = head->next;LIST ->next != NULL;LIST = LIST->next){ if(strcoll(s,LIST ->name)==0){ printf("%s\t%d\t%d\n",LIST->name,LIST->height,LIST->age); break; } printf("%s\n",LIST->name); printf("%s\n",LIST->next->name); } return(0); } person *newperson(){ person *dummy; dummy = (person*)malloc(sizeof(person)); dummy -> next = NULL; return(dummy); }

  • 構造体について

    5件のデータをRECORDに追加したいのですが、 RECORD inputdata(void)の宣言文エラーなどのコンパイルエラー。それと、inputdataを用いてどうやって5件のデータを入れたらいいかがわかりません。教えてください。 #define SIZE 5 #include <stdio.h> typedef struct{ int yy; int mm; int dd; }YMD; typedef struct{ char name[20]; YMD birthday; int age; }RECORD; RECORD inputdata(void); void main(void) { int i; for(i = 0;i < SIZE;i++){ inputdata(); } RECORD inputdata(void) { RECORD person; printf("名前>"); scanf("%s", person.name); printf("誕生日入力\n"); printf("年>"); scanf("%d", person.birthday.yy); printf("月>"); scanf("%d", person.birthday.mm); printf("日>"); scanf("%d", person.birthday.dd); return person; }

  • 構造体のポインタ

    なぜかprevのほうが表示されません。 問題としては関数を作成し gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> jiyon[17] -> hara[20] -> nicole[20] -> sunyon[23] -> gyuri[23] -> END と表示させるのが目的です gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> jiyon[17] ここまではうまく表示できているのですが・・・ #include <stdio.h> void printoufuku(struct kara *p); struct kara { char name[16]; int age; struct kara *next; struct kara *prev; }; int main() { struct kara a, x, f, m, c, *start; strcpy(a.name, "gyuri"); a.age = 23; strcpy(x.name, "sunyon"); x.age = 23; strcpy(f.name, "nicole"); f.age = 20; strcpy(m.name, "hara"); m.age = 20; strcpy(c.name, "jiyon"); c.age = 17; a.next = &x; x.next = &f; f.next = &m; m.next = &c; c.next = NULL; /********************* 5 lines */ c.prev = &m; m.prev = &f; f.prev = &x; x.prev = &a; a.prev = NULL; /*********************/ start = &a; printoufuku(start); return 0; } void printoufuku(struct kara *p) { for(p->next; p != NULL;p = p->next){ printf("%s[%d] ->",p->name,p->age); } for(p->prev; p != NULL; p = p->prev){ printf("%s[%d] ->",p->name,p->age); } }

専門家に質問してみよう