構造体配列について

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

構造体配列について

#1

投稿記事 by Cげんが~ » 17年前

構造体配列をを用いて、構造体をいくつも作ります。
その構造体を初期化するために、新たな初期化関数を作成する際、
構造体を関数の引数として使う場合、下記のようになります。

typedef struct
{ int x,y;
}vector; //2次元ベクトル構造体

typedef struct
{
int is_display;
int is_dragging;
vector pos;
vector disp_pos;
}Diodo; //ダイオードの構造体

Diodo_Syokika(Diodo *diodo[/url])   ← 怪しい・・・
{
diodo[0]->is_display = FALSE;
diodo[0]->is_dragging = FALSE;
diodo[0]->pos.x =31.5;
diodo[0]->disp_pos.x = 5;
diodo[0]->pos.y =49;
} //初期化する為のユーザ関数

次にメイン関数内で

  Diodo diodo[5];
Diodo_Syokika(???);   ←分からないところ!!

のように呼び出して使いたいんですが、
Diodo_Syokikaを呼び出す際の引数の書き方が分からず、苦労してます。
引数に構造体配列のポインタ?を持ってくる際はどうしたらいいのでしょうか?
分かる方いらっしゃいましたらお願いします。

へろりくしょん

Re:構造体配列について

#2

投稿記事 by へろりくしょん » 17年前

関数の仮引数の宣言では、最外周の配列に限りポインタに読み替えられます。
ですから Diodo_Syokika(Diodo *diodo[/url]) という関数宣言は、
構造体Diodoのポインタのポインタを引数に取る関数Diodo_Syokikaになります。

配列へのポインタを引数に取るには以下のようにします。

Diodo_Syokika(Diodo (*diodo)[5]);

呼び出す時は、Diodo_Syokika(&diodo); とします。


ですが、式の中で添え字演算子を省略し、単に変数名のみで記述した場合、それは
配列の先頭要素へのポインタを意味します。
ので、配列でなければならない絶対的な理由がないのであれば、次のようにするのが一般的です。

Diodo_Syokika(Diodo *diodo)
{
diodo[0].is_display = FALSE;
diodo[0].is_dragging = FALSE;
.
.
.
}

int main(void)
{
Diodo diodo[5];
Diodo_Syokika(diodo);

return 0;
}


ところで、Diodo_Syokika()の戻り値が無いですね。

Cげんが~

Re:構造体配列について

#3

投稿記事 by Cげんが~ » 17年前

さっそくの返信ありがとうございます。
配列にし、構造体をいくつも作りたいので、配列は絶対条件なんです。
ですので、

>Diodo_Syokika(Diodo (*diodo)[5]);
>呼び出す時は、Diodo_Syokika(&diodo); とします。

を参考にさせていただきました。
やっとコンパイル出来ました。ありがとうございます。

また、
>Diodo_Syokika()の戻り値が無いですね。
は、どういう事なのでしょうか?

へろりくしょん

Re:構造体配列について

#4

投稿記事 by へろりくしょん » 17年前

> さっそくの返信ありがとうございます。
> 配列にし、構造体をいくつも作りたいので、配列は絶対条件なんです。
> ですので、
>
配列で無ければならないというのは、Diodo_Syokika()関数の引数が、ということです。
大抵の場合は、配列の先頭要素へのポインタを渡すだけで事足りますので。


> >Diodo_Syokika()の戻り値が無いですね。
> は、どういう事なのでしょうか?
>
C言語では関数には戻り値の型を必要とします。

管理人

Re:構造体配列について

#5

投稿記事 by 管理人 » 17年前

やるんでしたら、こうではないでしょうか。ポインタポインタと思わなくても、
配列を宣言した時点でそれはアドレスで操作するものですから、難しく思わなくて大丈夫ですよ。
引数は普通に変数名を書き、受け取りは最初宣言した通りに書けばいいのです。

ただ今回、intであるvectorにdouble型を入れようとしているので警告が出ます。
doubleにしたいならdoubleに変更してください。

修正したのは、こんな感じです。
#include<stdio.h>

typedef struct{
	int x,y; 
}vector; //2次元ベクトル構造体 

typedef struct{ 
	int is_display; 
	int is_dragging; 
	vector pos; 
	vector disp_pos; 
}Diodo; //ダイオードの構造体 

void Diodo_Syokika(Diodo diodo[5]){ 
	diodo[0].is_display = -1; 
	diodo[0].is_dragging = -1; 
	diodo[0].pos.x =31.5; 
	diodo[0].disp_pos.x = 5; 
	diodo[0].pos.y =49; 
}

int main(){
	Diodo diodo[5]; 
	Diodo_Syokika(diodo);
	printf("%d %d....",diodo[0].is_display,diodo[0].is_dragging);
	return 0;
}

でも配列ごと渡したのに[0]しか初期化しないのはちょっと気持ち悪いので、
[0]しか要らないのならこのように個別に渡せます。
今度はポインタを意識する必要があり、
アロー演算子を使います。

#include<stdio.h>

typedef struct{
	int x,y; 
}vector; //2次元ベクトル構造体 

typedef struct{ 
	int is_display; 
	int is_dragging; 
	vector pos; 
	vector disp_pos; 
}Diodo; //ダイオードの構造体 

void Diodo_Syokika(Diodo *diodo){ 
	diodo->is_display = -1; 
	diodo->is_dragging = -1; 
	diodo->pos.x =31.5; 
	diodo->disp_pos.x = 5; 
	diodo->pos.y =49; 
}

int main(){
	Diodo diodo[5]; 
	Diodo_Syokika(&diodo[0]);
	printf("%d %d....",diodo[0].is_display,diodo[0].is_dragging);
	return 0;
}
 


>>> >Diodo_Syokika()の戻り値が無いですね。 
>>> は、どういう事なのでしょうか? 
>>> 
>>C言語では関数には戻り値の型を必要とします。 

補足しますと、関数は何らかの形で値を返します。
値を返さない場合は「なし」を意味する「void」を書きます。
main文もint mainとかvoid mainとかで始まってると思います。
参考書を見てもらっても、関数には何らかの形で型が書いてあるはずです。

void Diodo_Syokika(Diodo *diodo){ 
    return ;
}
なら関数が終了したときに、値を返さない

int Diodo_Syokika(Diodo *diodo){ 

    return 1;
}

なら関数が終了したときにint型である1を返す。

double Diodo_Syokika(Diodo *diodo){ 
    return 1.3;
}

なら関数が終了したときにdouble型である1.3を返す・・・。と言ったように。
この場合、main文で

Diodo_Syokika(diodo); 

の部分を

double d;

d=Diodo_Syokika(diodo);

とすれば、関数処理から戻ってきた時点で、dには1.3が入ります。
この辺「C言語 入門」でググれば沢山入門サイト出てきますのでおさらいしておいてください。
 

Cげんが~

Re:構造体配列について

#6

投稿記事 by Cげんが~ » 17年前

ご指摘ありがとうございます。
さっそく参考にさせていただきます。

戻り値につきましては、まだ勉強不足でした。
また、その部分から勉強しなおさせていただきます。

ありがとうございました。
また、自身で勉強してみて、分からなかったら質問させていただくと思いますが、
その際にはお願いいたします。

Cげんが~

Re:構造体配列について

#7

投稿記事 by Cげんが~ » 17年前

管理人さん、へろりさんどうもありがとうございます。
おかげ様で、戻り値について、理解できました。
これから先も是非役立てていきたいと思います。

さて、構造体配列につきましては、大変丁寧に説明していただき、
なんとか理解できる事が出来ました。
ありがとうございます。

しかし、その先の構造体配列を
forや、whileで繰り返し、構造体の初期化等を一気にしてしまおうと、
しているんですが、エラーばかり出て全く出来ません。

プログラムとしては、下記のように組んだんですが、
どこが悪いのでしょうか?
何度もすいませんが、ご指導お願いします。

struct void Diodo_Syokika{

for(Di1=0;Di1<5;Di1++)
{
diodo[Di1]->is_display = FALSE;
diodo[Di1]->is_dragging = FALSE;
diodo[Di1]->disp_pos.x=diodo[Di1]->pos.x = 5;
diodo[Di1]->disp_pos.y=diodo[Di1]->pos.y = 205;
diodo[Di1]->XD = 1;
diodo[Di1]->YD = 0;
diodo[Di1]->rad = 90;
diodo[Di1]->is_conect = FALSE;
diodo[Di1]->Lflug = FALSE;
diodo[Di1]->Rflug = FALSE;
diodo[Di1]->BD = 1;



box

Re:構造体配列について

#8

投稿記事 by box » 17年前

何をしようとするときに(コンパイル時? 実行時?)、どんなエラーが出ますか?
また、構造体定義の最新状態と、配列diodoの定義内容も見せてください。

「こんなデータ構造を作って、こんな風に初期化しようとしたが、
こんなエラーが出てしまってうまくいかない」というのをセットにして見せてください。

Cげんが~

Re:構造体配列について

#9

投稿記事 by Cげんが~ » 17年前

ご指摘いただきましてすいません。

構造体は
typedef struct Diodo
{
int is_display;
int is_dragging;
vector     pos;
vector     disp_pos;
vector     drag_offset;
int rad;
int is_conect;
int Lflug;
int Rflug;
}Diodo;

ベクトル構造体は
typedef struct
{
int x, y;
} vector;


です。

初期化する為の関数は上記の通り、

struct void Diodo_Syokika{

 for(Di1=0;Di1<5;Di1++)
 {
   diodo[Di1]->is_display = FALSE;
   diodo[Di1]->is_dragging = FALSE;
   diodo[Di1]->disp_pos.x=diodo[Di1]->pos.x = 5;
   diodo[Di1]->disp_pos.y=diodo[Di1]->pos.y = 205;
   diodo[Di1]->rad = 90;
   diodo[Di1]->is_conect = FALSE;
   diodo[Di1]->Lflug = FALSE;
   diodo[Di1]->Rflug = FALSE;
   diodo[Di1]->BD = 1;

  }


です。

この2つをメイン関数の中で、呼び出す形としては

int WINAPI WinMain( HINSTANCE hCurInst, HINSTANCE hPrevInst,
LPSTR lpsCmdLine, int nCmdShow )
{ 
      ・
      ・
  Diodo diodo[5];
Diodo_Init(&diodo);
      ・
      ・
      ・


として呼び出しているんですが、
上記のようにしてコンパイルすると、
コンパイルは出来るんですが、実行画面で

DxLib :test.exe -アプリケーションエラー
  
  "0x77fcae88"の命令が"0x00000002"のメモリを参照しました。メモリが"read"になることはできません
  でした。プログラムを終了するには[OK]をクリックしてください

DxLib :test.exe -アプリケーションエラー

  例外 unknown software exception (0xc0000027)がアプリケーションの0x77ea20b0で発生しました。
  プログラムを終了するには[OK]をクリックしてください


というものが出ます。
しかし、Diodo_Syokikaの関数にfor()を付けず、ループを行わなかったら上記エラーは出ません。

初めての事なのでどうしたらよいのか分かりません。
どうか教えてください。お願いします。



 
      

     

 

やそ

Re:構造体配列について

#10

投稿記事 by やそ » 17年前

明らかにおかしいじゃないですか((((((^_^;)


struct void Diodo_Syokika{

 for(Di1=0;Di1<5;Di1++)
 {
   diodo[Di1]->is_display = FALSE;
   diodo[Di1]->is_dragging = FALSE;
   diodo[Di1]->disp_pos.x=diodo[Di1]->pos.x = 5;
   diodo[Di1]->disp_pos.y=diodo[Di1]->pos.y = 205;
   diodo[Di1]->rad = 90;
   diodo[Di1]->is_conect = FALSE;
   diodo[Di1]->Lflug = FALSE;
   diodo[Di1]->Rflug = FALSE;
   diodo[Di1]->BD = 1;

  }


です。

この2つをメイン関数の中で、呼び出す形としては
int WINAPI WinMain( HINSTANCE hCurInst, HINSTANCE hPrevInst, 
LPSTR lpsCmdLine, int nCmdShow ) 
{  
      ・ 
      ・ 
  Diodo diodo[5]; 
Diodo_Init(&diodo); 
      ・ 
      ・ 
      ・ 
}
定義段階では
struct void Diodo_Syokika
でしたよね。

それとなんで初期化用関数までstruct?
関数なんですから
void Diodo_Syokika(引数)
{
文
}
の形にして下さい。

落ち着いてひとつずつ見直していけばきっと分かるはず^^

管理人

Re:構造体配列について

#11

投稿記事 by 管理人 » 17年前

なんか、構造体なのやら関数なのやらわからないような書き方になってしまっています^^;
基礎が大事なので、もう一度入門サイトで

「関数」と「構造体」についてザっとでいいから見直されることおススメします。
・・・で、ループで初期化させたいならこういうことでしょうか。

さっきのプログラムとほとんど一緒です。色つきのとこだけ違います。
ただこれだと全部同じ値で初期化されるのですが、いいのでしょうか?
#include<stdio.h>

typedef struct{
	int x,y; 
}vector; //2次元ベクトル構造体 

typedef struct{ 
	int is_display; 
	int is_dragging; 
	vector pos; 
	vector disp_pos; 
}Diodo; //ダイオードの構造体 

void Diodo_Syokika(Diodo *diodo){ 
	diodo->is_display = -1; 
	diodo->is_dragging = -1; 
	diodo->pos.x =31.5; 
	diodo->disp_pos.x = 5; 
	diodo->pos.y =49; 
}

int main(){
	Diodo diodo[5]; 
         for(int i=0;i<5;i++)
	     Diodo_Syokika(&diodo);	
	printf("%d %d....",diodo[0].is_display,diodo[0].is_dragging);
	return 0;
}

Cげんが~

Re:構造体配列について

#12

投稿記事 by Cげんが~ » 17年前

大変遅くなりまして申し訳ございません。

みなさんの指導を参考に改善を重ね、なんとか、
構造体配列を作成する事が出来ました。

みなさん本当にありがとうございました。
また質問する事があると思いますが、その際にはよろしくお願いします。

閉鎖

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