構造体を引数とする関数について

このQ&Aのポイント
  • 構造体を引数とする関数についてエラーが発生し、上手く動作しません。
  • C++環境でVC++を使用していますが、問題の原因を特定することができません。
  • プログラムを修正するか、代替案を提示していただきたいです。
回答を見る
  • ベストアンサー

構造体を引数とする関数について

関数に構造体を渡したいのですが、エラーが出て上手くいきません。 下のプログラムのように組んでいるのですが、どこが問題なのかご教授願いたいです。 もし、下記のプログラムのようなことができないのでしたら、代替案を提示してもらえると助かります。 環境はVC++です。よろしくお願いします。 struct DATA{ int x; char name[32]; }; void info(DATA *status[]); int main(void){ DATA student[3] = { { 1, "佐藤" }, { 2, "高橋" }, { 3, "田中" }, }; info(&student[]); return 0; } void info(DATA *status[]){ for (int i = 0; i < 3; i++){ printf("%d\n%s", status[i]->x, status[i]->name); } }

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

  • ベストアンサー
回答No.3

お礼への返信です。 > VC++ってCもC++も対応していませんでしたっけ? 対応しているというのは混ぜて書けるという意味ではないですよね。 例えば、GNU Compiler Collection (gcc)は C、C++だけでなくFortran、Java、Adaなんかにも対応していますが、ソースファイルに特殊な命令などを書かず、混ぜて書くことはできません。 あと、C言語とC++は文法がたまたま似ているだけの全く別の言語だと思ったほうがよいです。C言語で自然な書き方とC++で自然な書き方は全く異なります。 C++で書くとしたら、例えばこう書くのではないでしょうか。(C++11に対応していないコンパイラーではコンパイルできません) #include<vector> #include<iostream> using std::vector; struct DATA{ int x; char name[32]; }; void info(const vector<DATA>& students); int main(void){ vector<DATA> students = { { 1, "a" }, { 2, "b" }, { 3, "c" }, }; info(students); return 0; } void info(const vector<DATA>& students){ for (const auto& student : students) { std::cout << student.x << " " << student.name << std::endl; } } > この書き方ならポインタ宣言の*は書く必要はなく、 > 関数にアドレスが渡っているということですか? info関数の中身を見る限り全く必要ありません。C言語でvoid info(struct DATA status[])とvoid info(struct DATA *status)とは同じ意味になります。配列変数は配列の先頭要素のアドレスが格納されていますので、それを引数に渡すということはアドレスを渡すということです。また、配列を受け取るということは、配列の先頭要素のアドレスを受け取るということです。 質問者のように書いたらどういう意味になると思いますか?struct DATAの配列へのポインターを受け取るわけですので、2次元配列を受け取ることになってますが、それは意図通りなのでしょうか? 配列変数は配列の先頭の要素のアドレスが入っていますから、status[0]も*statusも同じデータを示します。ちなみに、C言語でstatus[0] と *(status + 0) と *(0 + status) と 0[status]が同じ意味になるのを知っていますか? > あと、->は使えないんですか? 使う必要ありません。 そもそも、->がどういう意味かご存知でしょうか? (*a).xと書く代わりに、a->xと書けるわけで、info関数のどこにその必要性がったのでしょうか? あえて使うコードを考えるなら、statusの値をインクリメントしながら表示するコードにするなどがあるかもしれません。.x == 0を番兵 (http://ja.wikipedia.org/wiki/%E7%95%AA%E5%85%B5 )として置いておき、こんなふうに書くこともできます。 int main(void){ struct DATA student[] = { { 1, "a" }, { 2, "b" }, { 3, "c" }, { 0, "sentinel"}, }; info(student); return 0; } void info(struct DATA status[]){ for (;status->x != 0;status++) { printf("%d %s\n", status->x, status->name); } } あと、技術者同士の交流は相互扶助し、切磋琢磨しあうのが基本です。初心者だからだと気後れせず、答えられそうな質問を見つけたらどんどん回答してみてください。

leonard2000
質問者

お礼

対応ってそういうことだったんですね。 C++はCのちょっとした上位互換だと思っていたのでそこまで書き方が変わるとは思っていませんでした… >配列変数は配列の先頭要素のアドレスが格納されていますので、それを引数に渡すということはアドレスを渡すということです。 つまり、例えば、a[3]という配列があったら ・a = &a[0] ということで、  aを関数に渡すということは先頭配列のアドレスを渡しているということ。 ・関数の仮引数を struct DATA *statusにすることで、関数はアドレスを受け取っている。  さらに、struct DATA *status と struct DATA status[] は意味が同じだから、  hanabutakoさんが書いてくださったコードにはポインタ宣言の*は必要がなかった。 という解釈で合ってますか? 何回も質問を重ねてしまって申し訳ないです。 >status[0] と *(status + 0) と *(0 + status) と 0[status]が同じ意味になるのを知っていますか? 0[status]なんて書き方もあるんですか!?知らなかったです。 ->は使わない方が繰り返しとかは見やすいですね。 わざわざコードを提示していただいてありがとうございますm(_ _)m 答えられる質問を増やすためにもこれから精進したいと思います! 長くなってすいません。

その他の回答 (3)

回答No.4

#3のお礼への返信です。 > つまり、例えば、a[3]という配列があったら > ・a = &a[0] ということで、 >  aを関数に渡すということは先頭配列のアドレスを渡しているということ。 そうです。 > ・関数の仮引数を struct DATA *statusにすることで、関数はアドレスを受け取っている。 >  さらに、struct DATA *status と struct DATA status[] は意味が同じだから、 >  hanabutakoさんが書いてくださったコードにはポインタ宣言の*は必要がなかった。 という解釈で合ってますか? そうです。

leonard2000
質問者

お礼

お礼遅くなってしまい申し訳ありません。 糖衣構文がよく分からなくてずっとつまづいていたので 今回、自分なりの理解ができてよかったです。 最後までこんな初歩的な質問に付き合ってくださってありがとうございました。

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.2

struct DATA{ int x; char name[32]; }; void info(DATA *status); int main(void){ DATA student[3] = { { 1, "佐藤" }, { 2, "高橋" }, { 3, "田中" }, }; info(student); return 0; } void info(DATA *status){ for (int i = 0; i < 3; i++){ printf("%d\n%s", status[i].x, status[i].name); } } ただし、info() の中では渡されたものの長さがわからないため、 void info(DATA *status, int size){ for (int i = 0; i < size; i++){ printf("%d\n%s", status[i].x, status[i].name); } } とした方がいいでしょう。

leonard2000
質問者

お礼

要素数の確認忘れてました… おかげさまでたぶんエラーはなくなりました! error LNK2019とかいうのが出てきてまだ試せていませんが… ともあれ、ご回答ありがとうございました。

回答No.1

C言語なのかC++なのか書かれていませんが、C言語なら、構造体を使うときはstruct 構造体名としなくてはいけません。 DATAではなく、struct DATAです。 また、関数の引数が変です。 main関数のstudentにはその構造体配列のアドレスが入っているので、渡すならinfo(student)です。受ける側もvoid info(struct DATA status[])と受けます。 #include <stdio.h> struct DATA{ int x; char name[32]; }; void info(struct DATA status[]); int main(void){ struct DATA student[3] = { { 1, "佐藤" }, { 2, "高橋" }, { 3, "田中" }, }; info(student); return 0; } void info(struct DATA status[]){ for (int i = 0; i < 3; i++){ printf("%d %s\n", status[i].x, status[i].name); } }

leonard2000
質問者

お礼

ご回答ありがとうございます。 VC++ってCもC++も対応していませんでしたっけ? C言語はstruct付けないといけないんですね。 自分の勉強不足さが身に染みてわかりました… 二つ疑問が… この書き方ならポインタ宣言の*は書く必要はなく、 関数にアドレスが渡っているということですか? あと、->は使えないんですか? 初心者でよくわかってないので説明していただけると嬉しいです。

関連するQ&A

  • C言語で、引数が構造体の場合

    生徒の名前、点数、順位を表示するプログラムをつくりたいのですが、(下のような関数を用いることを前提として) void rank1(struct data *x,int n) { int i,j; for(i=0;i<n;i++) x[i].rank=1; for(i=0;i<n;i++) for(j=0;j<n;j++) if(x[i].score<x[j].score) x[i].rank++; } このような場合、関数の引数として、構造体が用いられているわけですよね? 引数が構造体の場合、どのように引数の部分を書けばいいのか分かりません。 私が考えたプログラムは下記の通りです。 もちろんうまくいきませんでした。 たぶん最後のprintfの所のrank1の引数が間違っているだけだと思うんですが、どうでしょうか? include<stdio.h> struct data { char name; int score; int rank; }; void rank1(struct data *x,int n) { int i,j; for(i=0;i<n;i++) x[i].rank=1; for(i=0;i<n;i++) for(j=0;j<n;j++) if(x[i].score<x[j].score) x[i].rank++; } void main(void) { int m; static struct data x[] = {{'A',56,1}, {'B',79,1}, {'C',34,1}, {'D',91,1}, {'E',69,1}}; for(m=0;m<5;m++) printf("%c君 %d点 %d位\n",x[m].name,x[m].score,rank1(x,m)); }

  • 構造体の構造体 引数

    構造体の中の構造体の関数の引き渡し方法がわかりません。 下記ソースで試したのですが、うまくいきませんでした。 助言お願いいたします。 //repo.c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define NUM 20 #define MAX 15 struct seiseki{ float shu[3]; }; struct seito{ char name[NUM]; int age; struct seiseki kekka; }; void input(struct seito *p); void s_input(struct seiseki *p); void ss_input(struct seiseki *data); int main(){ int i; struct seito data[2]; for(i=0;i<2;i++){ printf("------------------------------\n"); printf("%d人目",i+1); input(&data[i]); } printf("%f\n",data[0].kekka.shu[0]); printf("%f\n",data[0].kekka.shu[1]); printf("%f\n",data[0].kekka.shu[2]); //data[1]に格納できない。 printf("%f\n",data[1].kekka.shu[0]); printf("%f\n",data[1].kekka.shu[1]); printf("%f\n",data[1].kekka.shu[2]); return 0; } void input(struct seito *p){ printf("名前->"); scanf("%s",p->name); printf("年齢->"); scanf("%d",p->age); s_input(&(p->kekka)); } void s_input(struct seiseki *data){ printf("国語->"); ss_input(data); printf("算数->"); ss_input(data); printf("英語->"); ss_input(data); } //下記関数で成績をchar型で受け取り、数値化したい。 void ss_input(struct seiseki *data){ char p[100]; int i=0; static int o=0; scanf("%s",p); while( p[i] != '\0'){ if(isdigit(p[i])==0){ printf("再入力してください"); scanf("%s",p); } i++; } data->shu[o]=atof(p); printf("%f\n",data->shu[o]); o++; }

  • 構造体についてです。

    typedef struct student{ int id; char name[20]; int kokugo; int sansu; int eigo; }STUDENT; と、 struct student{ int id; char name[20]; int kokugo; int sansu; int eigo; }; の違いはなんでしょう? 私は下記をよく使うのですが・・・。 typedefについて詳しく知りたいです。

  • 文字列の構造体キャスト

    文字列を構造体にキャストした際に、メンバ変数は以下のようには、 取得できないのでしょうか? typedef struct { int year; /* 学年 */ int clas; /* クラス */ int number; /* 出席番号 */ char name[64]; /* 名前 */ } student; int main(void) { student *data=NULL; char c[] = "123456789012abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij1234"; char* tmp; tmp = &c[0]; student_print(data, tmp); return 0; } void student_print(student *data, char *mkg) { void* buff = NULL;    buff = (student*)mkg; printf("[year]:%s\n", buff ->year);←ここ return; }

  • 関数への構造体の配列の渡し方<c言語初心者>

    こんにちは、関数への構造体の配列の渡し方で理解できない点があるため、質問させていただきます。 以下がスクリプトになります。3人の名前と年齢をinput関数で入力し、それらのデータをoutput関数で出力するのが目的です。 #include <stdio.h> typedef struct{ char name[64]; int age; }property; void input(property *data[]); void output(property *data[]); int main(void){ property data[3]; printf("Input data of three people.\n"); input(&data); output(&data); return 0; } void input(property *data[]){ int i; for(i=0;i<3;i++){ printf("%d banme\n",i+1); printf("name:"); scanf("%s",&data[i]->name); printf(" age:"); scanf("%3d",&data[i]->age); } return; } void output(property *data[]){ int i; for(i=0;i<3;i++){ printf("%d banme\n",i+1); printf("name:%s\n",data[i]->name); printf("age :%3d\n",data[i]->age); } return; } コンパイル時のエラーメッセージは以下のようになりました。(ファイル名はstructure5.c) structure5.c: In function ‘main’: structure5.c:14:2: warning: passing argument 1 of ‘input’ from incompatible pointer type [enabled by default] input(&data); ^ structure5.c:8:6: note: expected ‘struct property **’ but argument is of type ‘struct property (*)[3]’ void input(property *data[]); ^ structure5.c:15:2: warning: passing argument 1 of ‘output’ from incompatible pointer type [enabled by default] output(&data); ^ structure5.c:9:6: note: expected ‘struct property **’ but argument is of type ‘struct property (*)[3]’ void output(property *data[]); ^ structure5.c: In function ‘input’: structure5.c:24:3: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[64]’ [-Wformat=] scanf("%s",&data[i]->name); ^ 構造体の配列をinput関数やoutput関数に渡すときにエラーが発生しているようなのですが、自分で調べても解決できなかったため、質問させて頂きます。 皆様のお知恵を貸してください。なおプログラミング言語自体初心者のため、できる限りわかりやすいお言葉でご教授願います。よろしくお願い致します。

  • 構造体について

    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; }

  • C言語 構造体配列 list

    プログラミングでこの問題がわからないので教えてください! 下記の構造体タグseisekiを使って,表に示すデータをもつ構造体配列listを作成する. 構造体配列listを利用して,一番点数の高い 者を探し,その名前を表示する. struct seiseki{ char name[30]; int score; name score }; 表 佐藤 80 鈴木 75 田中 95 高橋 90

  • 構造体配列

    いつもお世話になっています。 今日構造体配列を勉強した際に下の演習をしていたのですが、いまいち基礎的な関数や配列のことやコマンドライン引数のことが理解できていません。一応自分なりにプログラムを書いてみたのですが、エラーがでます。 どなたかアドバイス・ご指摘・解説・例などをおねがいいたします。 問題はコマンドライン引数で人数を指定し,人数分のデータを標準入力(キーボード)から構造体配列に入力し,標準出力(ディスプレイ)に出力するプログラムです。 #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へファイル出力に出力するプログラムというおまけの問題もあります。 こちらの問題のヒントもいただけませんか?

  • 構造体についてです。

    身体測定表を作っていて最初に作ったデータを変更して表示したいのですが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> struct seiseki { /* 構造体の宣言 */ int no; char name[20]; double average; }; int main(void) { int i; struct seiseki seito1, seito2[20]; /* 構造体変数と構造体配列の宣言 */ >char name[20] というのは、NAMEの領域を20文字 確保すると言うことですよね? >struct seiseki seito1, seito2[20] ここの箇所が分からないのですが seito2[20]の20というのは どうして20なのですか? NAMEだけではないので もっと大きな数字になるような気がするのですが… またseito1の方は どうして数字が何もないんですか? 考え違いをしているところを ご指摘して頂ければ幸いです。

専門家に質問してみよう