部品の構造体による子部品の数の計算の質問

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
slei

部品の構造体による子部品の数の計算の質問

#1

投稿記事 by slei » 15年前

初めまして。
初歩的で申し訳ないですが、どうしても詰まっているため質問させていただきたく思います。
各部品を構造体で示し、指定した親部品に必要な各子部品を求めるプログラムを作りたいのですが、実行時に「セグメンテーション違反です」のエラーが発生します。 どこかの型が誤っているということは何となくわかるのですが、具体的な修正場所が見えずに困っています。おそらく構造体の部分だとは思うのですが、関数の部分が正しいのかも確証が持てません。
C言語、OSはlinuxです。

コード:

#include<stdio.h>

struct item {
  char *part_name; /* アイテム名 */ 
  int n_spart; /* 子アイテム数 */
  int spart[10]; /* 子アイテム番号 */
  float q_spart[20]; /* 子アイテムの必要量 */
} buhin[25];

void init_buhin()
{
  buhin[0].part_name = "生産必要量";
  buhin[0].n_spart = 3;
    buhin[0].spart[0] = 1; 
    buhin[0].q_spart[0] = 10.0; 
    buhin[0].spart[1] = 2;
    buhin[0].q_spart[1] = 6.0;
    buhin[0].spart[2] = 3;     
    buhin[0].q_spart[2] = 4.0;

  buhin[1].part_name = "直4エンジン";
  buhin[1].n_spart = 4;
    buhin[1].spart[0] = 4;     
    buhin[1].q_spart[0] = 1.0;
    buhin[1].spart[1] = 7;     
    buhin[1].q_spart[1] = 1.0;
    buhin[1].spart[2] = 5;     
    buhin[1].q_spart[2] = 1.0;
    buhin[1].spart[3] = 3;     
    buhin[1].q_spart[3] = 4.0;

  buhin[2].part_name = "V8エンジン";
  buhin[2].n_spart = 4;
    buhin[2].spart[0] = 4;
    buhin[2].q_spart[0] = 2.0;
    buhin[2].spart[1] = 19;     
    buhin[2].q_spart[1] = 2.0;
    buhin[2].spart[2] = 6;     
    buhin[2].q_spart[2] = 1.0;
    buhin[2].spart[3] = 2;     
    buhin[2].q_spart[3] = 8.0;

  buhin[3].part_name = "PSAssy";
  buhin[3].n_spart = 4;
    buhin[3].spart[0] = 15; 
    buhin[3].q_spart[0] = 1.0;
    buhin[3].spart[1] = 16;     
    buhin[3].q_spart[1] = 1.0;
    buhin[3].spart[2] = 17;     
    buhin[3].q_spart[2] = 1.0;
    buhin[3].spart[3] = 18;     
    buhin[3].q_spart[3] = 2.0;

  buhin[4].part_name = "SHAssy";
  buhin[4].n_spart = 4;
    buhin[4].spart[0] = 8; 
    buhin[4].q_spart[0] = 1.0;
    buhin[4].spart[1] = 9;     
    buhin[4].q_spart[1] = 1.0;
    buhin[4].spart[2] = 10;     
    buhin[4].q_spart[2] = 2.0;
    buhin[4].spart[3] = 11;     
    buhin[4].q_spart[3] = 10.0;

  buhin[5].part_name = "直4用CCAssy";
  buhin[5].n_spart = 4;
    buhin[5].spart[0] = 12;
    buhin[5].q_spart[0] = 1.0;
    buhin[5].spart[1] = 13;     
    buhin[5].q_spart[1] = 1.0;
    buhin[5].spart[2] = 14;     
    buhin[5].q_spart[2] = 1.0;
    buhin[5].spart[3] = 11;     
    buhin[5].q_spart[3] = 10.0;

  buhin[6].part_name = "V8用CCAssy";
  buhin[6].n_spart = 4;
    buhin[6].spart[0] = 20;
    buhin[6].q_spart[0] = 1.0;
    buhin[6].spart[1] = 21;     
    buhin[6].q_spart[1] = 1.0;
    buhin[6].spart[2] = 14;     
    buhin[6].q_spart[2] = 1.0;
    buhin[6].spart[3] = 11;     
    buhin[6].q_spart[3] = 10.0;

  buhin[7].part_name = "直4用シリンダ";
  buhin[7].n_spart = 0;

  buhin[8].part_name = "シリンダヘッド";
  buhin[8].n_spart = 0;

  buhin[9].part_name = "シリンダヘッドカバー";
  buhin[9].n_spart = 0;

  buhin[10].part_name = "カムシャフト";
  buhin[10].n_spart = 0;

  buhin[11].part_name = "ボルト";
  buhin[11].n_spart = 0;

  buhin[12].part_name = "直4用クランクケース";
  buhin[12].n_spart = 0;

  buhin[13].part_name = "直4用クランクシャフト";
  buhin[13].n_spart = 0;

  buhin[14].part_name = "クランクケースカバー";
  buhin[14].n_spart = 0;

  buhin[15].part_name = "ピストン";
  buhin[15].n_spart = 0;

  buhin[16].part_name = "ガスケット";
  buhin[16].n_spart = 0;

  buhin[17].part_name = "コンロッド";
  buhin[17].n_spart = 0;

  buhin[18].part_name = "ピストンクリップ";
  buhin[18].n_spart = 0;

  buhin[19].part_name = "V8用シリンダ";
  buhin[19].n_spart = 0;

  buhin[20].part_name = "V8用クランクケース";
  buhin[20].n_spart = 0;

  buhin[21].part_name = "V8用クランクシャフト";
  buhin[21].n_spart = 0;
}

float get_q(int p, int q)
{
  int i; /* カウンタ */
  float r =0.0; /* 返す量 */

  if (p == q)
    r = 1.0;
  else if(buhin[p].n_spart != 0) /* 子アイテムの存在をチェック */
    for(i = 0;i < buhin[p].n_spart; i++) /* 子アイテムの数だけループ */
      r += get_q(buhin[p].spart[i], q) * buhin[p].q_spart[i];

  return r;
}

int main()
{
  float t_quant;
  int p0;  /* 基準番号 */
  int q0;  /* 調べたい番号 */
  int x; /* カウンタ */

  init_buhin();

  p0 = 0;   /* 0に使われる */
  for(x = 0;x < 22; x++){
    if(buhin[x].n_spart == 0){
    q0 =  x;

  t_quant = get_q(p0,q0);
  printf("Total quantity of %s is %f in %s.\n",
	 buhin[q0].part_name, t_quant, buhin[p0].part_name);
          }
	}
  return 0;
}

 


求めたい数にあたるq0に0または2を代入したときのみエラーが起きずに実行され、他の数字が入ると実行不可能というのも原因がわからず困っています。課題の期限が迫っていて、早くに助言をいただけると非常に助かります。拙文申し訳ありません。よろしくお願いします。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 部品の構造体による子部品の数の計算の質問

#2

投稿記事 by bitter_fox » 15年前

slei さんが書きました:

コード:

#include<stdio.h>

float get_q(int p, int q)
{
  int i; /* カウンタ */
  float r =0.0; /* 返す量 */

  if (p == q)
    r = 1.0;
  else if(buhin[p].n_spart != 0) /* 子アイテムの存在をチェック */
    for(i = 0;i < buhin[p].n_spart; i++) /* 子アイテムの数だけループ */
      r += get_q(buhin[p].spart[i], q) * buhin[p].q_spart[i];

  return r;
}
r += get_q(buhin[p].spart, q) * buhin[p].q_spart;
これが原因だと思います。
get_q関数内でget_q関数を呼ぶことは再帰呼び出しと言うものになってしまいます。
この実装では終了判定がしっかりしておらず、関数の呼び出しの際などに使用されるスタック領域と言う領域を破壊してしまっています。


slei さんが書きました:求めたい数にあたるq0に0または2を代入したときのみエラーが起きずに実行され

これは、偶然にも終了判定に引っかかっために、エラーが発生しませんでした。

slei

Re: 部品の構造体による子部品の数の計算の質問

#3

投稿記事 by slei » 15年前

回答ありがとうございます。関数のほうでしたか……
ループの終了条件が自分自身でしっかり把握できていないというのも問題でしたね。
この場合、正常に結果を返すためにはどのように書き換えればいいのでしょうか?
教えて君で申し訳ありません。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 部品の構造体による子部品の数の計算の質問

#4

投稿記事 by bitter_fox » 15年前

slei さんが書きました:回答ありがとうございます。関数のほうでしたか……
ループの終了条件が自分自身でしっかり把握できていないというのも問題でしたね。
この場合、正常に結果を返すためにはどのように書き換えればいいのでしょうか?
教えて君で申し訳ありません。
再帰呼び出しを用いることは課題に入っているのでしょうか?
それによって変わってきますが、再帰呼び出しを用いなくてよいならば、

コード:

      r += buhin[p].spart[i] * buhin[p].q_spart[i];
として、main関数をしっかりとしてあげれば正常に動作します。

[hr][追記]
再帰なしで動作させるにしてもget_q関数はもう少し弄らなければいけないようです。

やっぱり引数を二つ取ってるってことは再帰を使うのかな・・・
最後に編集したユーザー bitter_fox on 2011年2月09日(水) 06:54 [ 編集 1 回目 ]

slei

Re: 部品の構造体による子部品の数の計算の質問

#5

投稿記事 by slei » 15年前

ちゃんと……というとget_qはその1行だけを差し替えてmain関数のほうで再帰と同じような動作をさせるということでしょうか?
その場合の記述もどうすればいいかよくわかりませんが・・・・・・
特に再帰を使うような支持はでていませんが、しっかり把握できていないのに無理に使ったりすると混乱の元ですね……
1行だけ差し替えた場合実行そのものは出来たのでやはりそこが問題で正しかったようですが、その先の計算で再び躓いています。
何から何まで聞いたりして本当に申し訳ないです。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 部品の構造体による子部品の数の計算の質問

#6

投稿記事 by bitter_fox » 15年前

slei さんが書きました:ちゃんと……というとget_qはその1行だけを差し替えてmain関数のほうで再帰と同じような動作をさせるということでしょうか?
いえ、get_q関数は合計を取得してる関数にちゃんとなってるんで、main関数内ではただ呼び出すだけで大丈夫です。
slei さんが書きました:特に再帰を使うような支持はでていませんが、しっかり把握できていないのに無理に使ったりすると混乱の元ですね……
基本的には再帰は再帰でしか出来ないことがあるときに使うべきですので、普通のループで済む場合は使わないですね。
slei さんが書きました:1行だけ差し替えた場合実行そのものは出来たのでやはりそこが問題で正しかったようですが、その先の計算で再び躓いています。
修正点を挙げたいのですが、このプログラムでしていることが良く解らないので、次の点をもう少し詳しく教えていただけますでしょうか?

1.どういった値が出力されればいいのか
2.何らかの値の合計を取得してるように見えるが、どの値なのか[修正]質問本文に書いてありました、失礼しました。

slei

Re: 部品の構造体による子部品の数の計算の質問

#7

投稿記事 by slei » 15年前

何度も申し訳ありません。
このプログラムで出力したいのは、構造体0に示した
「直4エンジン」(構造体1)10個、「V8エンジン」(構造体2)6個、「PSAssy」(構造体3)4個を作るのに必要なこれ以上分割できない要素(n_spart = 0の部品)のそれぞれの個数を出力させたい、というものです。
PSAssyは先にあげた二つの子部品にもなっていますが、それの必要量も足した上で4個必要、という題意と思われます。
出力の理想としては、「Total quantity of (部品名) is (必要量) in (目的(今回は生産必要量))」というのを子部品の数だけ出したいというものです。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 部品の構造体による子部品の数の計算の質問

#8

投稿記事 by bitter_fox » 15年前

slei さんが書きました: 出力の理想としては、「Total quantity of (部品名) is (必要量) in (目的(今回は生産必要量))」というのを子部品の数だけ出したいというものです。
なるほど、解りました。

では、この出力であっているか確認していただけますか?

コード:

Total quantity of 直4エンジン is 10.000000 in 生産必要量.
Total quantity of V8エンジン is 14.000000 in 生産必要量.
Total quantity of PSAssy is 8.000000 in 生産必要量.
Total quantity of SHAssy is 3.000000 in 生産必要量.
Total quantity of 直4用CCAssy is 1.000000 in 生産必要量.
Total quantity of V8用CCAssy is 1.000000 in 生産必要量.
Total quantity of 直4用シリンダ is 1.000000 in 生産必要量.
Total quantity of シリンダヘッド is 1.000000 in 生産必要量.
Total quantity of シリンダヘッドカバー is 1.000000 in 生産必要量.
Total quantity of カムシャフト is 2.000000 in 生産必要量.
Total quantity of ボルト is 30.000000 in 生産必要量.
Total quantity of 直4用クランクケース is 1.000000 in 生産必要量.
Total quantity of 直4用クランクシャフト is 1.000000 in 生産必要量.
Total quantity of クランクケースカバー is 2.000000 in 生産必要量.
Total quantity of ピストン is 1.000000 in 生産必要量.
Total quantity of ガスケット is 1.000000 in 生産必要量.
Total quantity of コンロッド is 1.000000 in 生産必要量.
Total quantity of ピストンクリップ is 2.000000 in 生産必要量.
Total quantity of V8用シリンダ is 2.000000 in 生産必要量.
Total quantity of V8用クランクケース is 1.000000 in 生産必要量.
Total quantity of V8用クランクシャフト is 1.000000 in 生産必要量.

slei

Re: 部品の構造体による子部品の数の計算の質問

#9

投稿記事 by slei » 15年前

Total quantity of 直4用シリンダ is 34.000000 in 生産必要量.
Total quantity of シリンダヘッド is 34.000000 in 生産必要量.
Total quantity of シリンダヘッドカバー is 34.000000 in 生産必要量.
Total quantity of カムシャフト is 34.000000 in 生産必要量.
Total quantity of ボルト is 34.000000 in 生産必要量.
Total quantity of 直4用クランクケース is 34.000000 in 生産必要量.
Total quantity of 直4用クランクシャフト is 34.000000 in 生産必要量.
Total quantity of クランクケースカバー is 34.000000 in 生産必要量.
Total quantity of ピストン is 34.000000 in 生産必要量.
Total quantity of ガスケット is 34.000000 in 生産必要量.
Total quantity of コンロッド is 34.000000 in 生産必要量.
Total quantity of ピストンクリップ is 34.000000 in 生産必要量.
Total quantity of V8用シリンダ is 34.000000 in 生産必要量.
Total quantity of V8用クランクケース is 34.000000 in 生産必要量.
Total quantity of V8用クランクシャフト is 34.000000 in 生産必要量.


先ほどのrの部分だけ取り替えて計算部分の書き直しが出来ていないせいか、すべて同じ値が渡されてしまっているようです。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 部品の構造体による子部品の数の計算の質問

#10

投稿記事 by bitter_fox » 15年前

質問が分かりにくかったですね。申し訳ありません。

僕の質問の意図しては、プログラムを実行した際に出力されるのは、

コード:

Total quantity of 直4エンジン is 10.000000 in 生産必要量.
Total quantity of V8エンジン is 14.000000 in 生産必要量.
Total quantity of PSAssy is 8.000000 in 生産必要量.
Total quantity of SHAssy is 3.000000 in 生産必要量.
Total quantity of 直4用CCAssy is 1.000000 in 生産必要量.
Total quantity of V8用CCAssy is 1.000000 in 生産必要量.
Total quantity of 直4用シリンダ is 1.000000 in 生産必要量.
Total quantity of シリンダヘッド is 1.000000 in 生産必要量.
Total quantity of シリンダヘッドカバー is 1.000000 in 生産必要量.
Total quantity of カムシャフト is 2.000000 in 生産必要量.
Total quantity of ボルト is 30.000000 in 生産必要量.
Total quantity of 直4用クランクケース is 1.000000 in 生産必要量.
Total quantity of 直4用クランクシャフト is 1.000000 in 生産必要量.
Total quantity of クランクケースカバー is 2.000000 in 生産必要量.
Total quantity of ピストン is 1.000000 in 生産必要量.
Total quantity of ガスケット is 1.000000 in 生産必要量.
Total quantity of コンロッド is 1.000000 in 生産必要量.
Total quantity of ピストンクリップ is 2.000000 in 生産必要量.
Total quantity of V8用シリンダ is 2.000000 in 生産必要量.
Total quantity of V8用クランクケース is 1.000000 in 生産必要量.
Total quantity of V8用クランクシャフト is 1.000000 in 生産必要量.
これらで、いいですか?と言うものでした。
(つまりはこの出力が正解かどうかを確認してほしかったんですが・・・)

slei

Re: 部品の構造体による子部品の数の計算の質問

#11

投稿記事 by slei » 15年前

こちらこそ申し訳ありません。
子部品の数は手動で計算してみないと確認できませんが、出力したいのはそれ以上分解できない部品(n_spart = 0)のみなので
直4エンジンからV8用CCAssyまでの出力は必要ないですね。
6個でいいはずのV8エンジンが14と出力されているあたり、こちらの計算関数や構造体にまだ誤りがありそうですね……

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 部品の構造体による子部品の数の計算の質問

#12

投稿記事 by bitter_fox » 15年前

確認ありがとうございます。
slei さんが書きました:出力したいのはそれ以上分解できない部品(n_spart = 0)のみなので
それ以上分解できない部品でしたか・・・
見落としてましたww
slei さんが書きました: 6個でいいはずのV8エンジンが14と出力されているあたり、こちらの計算関数や構造体にまだ誤りがありそうですね……
14と出力されたのは恐らく、

コード:

  buhin[2].part_name = "V8エンジン";
  buhin[2].n_spart = 4;
    buhin[2].spart[0] = 4;
    buhin[2].q_spart[0] = 2.0;
    buhin[2].spart[1] = 19;     
    buhin[2].q_spart[1] = 2.0;
    buhin[2].spart[2] = 6;     
    buhin[2].q_spart[2] = 1.0;
    buhin[2].spart[3] = 2;         // ココ
    buhin[2].q_spart[3] = 8.0;
ココで自分自身を必要な部品としていたためだと思います。

(現在どういった流れのプログラムにしたらいいのかを書いてるので少々お待ちくださいね。)
[hr][追記]
再帰を使っていないアルゴリズムでは正常な出力にならないので再帰を使ったものに書き直します。
申し訳ございません。
最後に編集したユーザー bitter_fox on 2011年2月09日(水) 08:58 [ 編集 1 回目 ]

slei

Re: 部品の構造体による子部品の数の計算の質問

#13

投稿記事 by slei » 15年前

bitter_fox さんが書きました: buhin[2].spart[3] = 2; // ココ
buhin[2].q_spart[3] = 8.0;

ココで自分自身を必要な部品としていたためだと思います。
うぁ、そこで参照したかったのは2番じゃなくて3番ですね・・・・・・凡ミスです
bitter_fox さんが書きました: (現在どういった流れのプログラムにしたらいいのかを書いてるので少々お待ちくださいね。)
ありがとうございます、本当に何度もすみません。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 部品の構造体による子部品の数の計算の質問

#14

投稿記事 by bitter_fox » 15年前

slei さんが書きました:
bitter_fox さんが書きました: buhin[2].spart[3] = 2; // ココ
buhin[2].q_spart[3] = 8.0;

ココで自分自身を必要な部品としていたためだと思います。
うぁ、そこで参照したかったのは2番じゃなくて3番ですね・・・・・・凡ミスです
あっ、そこを直したら正常に動作しました・・・w

どうやら再帰の終了判定を間違えていたという指摘は的外れだったようです。本当に混乱させるようなことを言ってしまって申し訳ありません・・・

slei

Re: 部品の構造体による子部品の数の計算の質問

#15

投稿記事 by slei » 15年前

……あっ、元のプログラムでそこ修正したら本当に動きましたね……
数字ひとつでここまでてんてこ舞いになる、単純ミスの怖さを改めて思い知りました……
[text]
Total quantity of 直4用シリンダ is 10.000000 in 生産必要量.
Total quantity of シリンダヘッド is 22.000000 in 生産必要量.
Total quantity of シリンダヘッドカバー is 22.000000 in 生産必要量.
Total quantity of カムシャフト is 44.000000 in 生産必要量.
Total quantity of ボルト is 380.000000 in 生産必要量.
Total quantity of 直4用クランクケース is 10.000000 in 生産必要量.
Total quantity of 直4用クランクシャフト is 10.000000 in 生産必要量.
Total quantity of クランクケースカバー is 16.000000 in 生産必要量.
Total quantity of ピストン is 92.000000 in 生産必要量.
Total quantity of ガスケット is 92.000000 in 生産必要量.
Total quantity of コンロッド is 92.000000 in 生産必要量.
Total quantity of ピストンクリップ is 184.000000 in 生産必要量.
Total quantity of V8用シリンダ is 12.000000 in 生産必要量.
Total quantity of V8用クランクケース is 6.000000 in 生産必要量.
Total quantity of V8用クランクシャフト is 6.000000 in 生産必要量.
[/text]
bitter_fox さんが書きました: どうやら再帰の終了判定を間違えていたという指摘は的外れだったようです。本当に混乱させるようなことを言ってしまって申し訳ありません・・・
いえ、相談に乗ってくれなかったらこのミスにずっと気づかないままいつまでも頭を抱えていたと思います。本当にありがとうございました!

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 部品の構造体による子部品の数の計算の質問

#16

投稿記事 by bitter_fox » 15年前

slei さんが書きました: 数字ひとつでここまでてんてこ舞いになる、単純ミスの怖さを改めて思い知りました……
ですね。
再帰呼び出しをするところを次のようにしておくと、ほんの少し安全になりますよ。

コード:

for(i = 0;i < buhin[p].n_spart; i++) /* 子アイテムの数だけループ */
{
	if (p != buhin[p].spart[i]) // 次に呼ぶアイテムが今のアイテムと違ってるときだけ
	{
		r += get_q(buhin[p].spart[i], q) * buhin[p].q_spart[i];
	}
	else // 同じ物を呼ぼうとしている
	{
		printf("Error: Happen SelfRefer (%d(%d))\n", p, i);
	}
}
ほんの少しと言うのは、複数のデータで円を描くように参照しあっていた時は同じくセグメンテーション違反になってしまいます。。。

閉鎖

“C言語何でも質問掲示板” へ戻る