構造体が戻り値の関数についてわかりません

このQ&Aのポイント
  • 構造体を使用して文字列を保存するメモリ領域を定義するという問題です。
  • 質問者は、文字列を構造体のメンバ変数にコピーしようとした際にコンパイルエラーが発生しました。
  • また、辞書的に後ろの文字を長い文字列とする方法や、文字列の結合にスペースを挿入する方法が分からないといった質問があります。
回答を見る
  • ベストアンサー

構造体が戻り値の関数についてわかりません

問題文:文字列を保存する構造体word_pairを下記の様に定義する。 typedef struct word_pair{ char longer_word[10]; char shorter_word[10]; char combined_word[20]; int longer_word_length; int shorter_word_length; }word_pair_t; この構造体を新たに作成し、データをセットして返す関数 word_pair_t create_word_pair(char *a, char *b); を作成せよ。create_word_pairは以下の仕様を満たす。 create_word_pairは2つの文字列a,bを比較し、長い文字列をlonger_wordに、短い文字列をshorter_wordに代入する。また、これらの長さが同じ場合には辞書的に後ろのものをlonger_wordに、前のものをshorter_wordに代入する。もし、a,bがまったく同じ文字列であれば、エラーメッセージを出力した上で、longer_wordに入力された文字列をshorter_wordに空の文字列を代入する。またcombined_wordにはlonger_word とshorter_wordをスペース区切りで結合したものを代入する。 標準入力から文字列を2つ読み取り、create_word_pairを用いて、新たにそれらのデータが代入された構造体を作成した後に、これらのメンバ変数を全て、標準出力に表示するプログラムを作成せよ。 という問題で、とりあえず自分で細かい条件は無視して文字列を標準入力してから構造体のメンバに文字を格納するところまでやろうとしたのですが、strcpyするのに型が違うとコンパイルエラーが出たのですが、型は一緒だと私は思っているため、なぜ違うのかわかりません。 また辞書的に後ろ前をif文でどのように表現すればいいのかと、文字列結合にstrcatを使うと思うのですが、結合の合間にスペースをいれる方法が分かりません。以下自分のコード。 #include<stdio.h> #include<string.h> #define max 50 typedef struct word_pair{ char longer_word[10]; char shorter_word[10]; char combined_word[20]; int longer_word_length; int shorter_word_length; }word_pair_t; word_pair_t create_word_pair(char *a, char *b); int main() { char a[max],b[max]; word_pair_t *str; printf("文字列を2つ入力してください。\n"); printf("1つ目:"); scanf("%s\n",a); printf("2つ目:"); scanf("%s\n",b); create_word_pair(a,b); printf("長い方の文字列%s\n",str->longer_word); printf("短い方の文字列%s\n",str->shorter_word); printf("連結した文字列%s\n",str->combined_word); printf("長い方の文字列の長さ%d\n",str->longer_word_length); printf("短い方の文字列の長さ%d\n",str->shorter_word_length); return 0; } word_pair_t create_word_pair(char *a, char *b) { int d, e; char c[max]; word_pair_t *str; d = strlen(a); e = strlen(b); if(d > e){ strcpy(str->longer_word, a); strcpy(str->shorter_word, b); c = strcat(a,b); strcpy(str->combine_word, c); strcpy(str->longer_word_length, d); strcpy(str->shorter_word_length, e); } if(d < e) { strcpy(str.longer_word, b); strcpy(str.shorter_word, a); c = strcat(a,b); strcpy(str.combine_word, c); strcpy(str.longer_word_length, e); strcpy(str.shorter_word_length, d); } }

noname#160632
noname#160632

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.5

intを返す関数を考えたときに int func(){ int a; ~ return a; } int main(){ int a ; ~ a = func() ; ~ } みたいになりますよね? このとき、funcのaとmainのaはともに関数内だけのローカル変数になっていて、互いに関係無い、っていうのも大丈夫ですね。 名前が同じでややこしければ int func(){ int func_a; ~ return func_a; } int main(){ int main_a ; ~ main_a = func() ; ~ } と考えれば、とりあえずはよいでしょう。 /* ここがわからなければ、とりあえず、過去の学習内容を復習してください */ 構造体は、intなどとほぼ同じ「型」です。ですから、int→構造体に書き換えたものが「構造体を返す関数」の基本になります。 struct A func(){ struct A a; ~ return a; } int main(){ struct A a ; ~ a = func() ; ~ } ごく古いC言語の仕様だと、構造体を直接返したり、=で代入したりができませんでしたが、今は可能です。 /* メンバーにポインタが入っていると、注意する必要があります。 興味があったら ナローコピー/ディープコピーで検索。 今回の例では問題ありません */ > 最初に構造体宣言をしているからポインタで構造体の中の数値は変えることができるんじゃないんですか? 「構造体」は宣言されています。 しかし、その「構造体の変数」は宣言されていません。 これは「int」はどこでも使えるけど、「int型の変数」は宣言した範囲でしか使えない、というのと同じです。 また、ポインタでの操作、というのは、なんらかの形(通常は引数)でポインタを関数に渡すことで、そのポインタを通じて呼び出し側の構造体を操作するものです。 void func(struct A * a ){ ~ a->b = 0 ; /* a->b は (*a).b の意味 */ ~ } int main(){ struct A c ; ~ func(&c) ; /* c.b == 0 */ ~ } このような時に ・mainのcのアドレスが引数aとしてfuncに渡される ・ -> 演算子で、ポインタaが指すアドレスにある構造体Aのメンバーbを操作 = aはmain関数内の変数cを指しているので、cのメンバーbが変化する となります。 これも、他の型を同じです。 このプログラムだと、word_pair_t *str;と宣言しているだけで、何もアドレスを入れていません。 C言語では、このような場合に、何が入っているか保証されていません。 このままstr-> 等として「strのアドレスにあるもの」にアクセスしたとき、どうなるかわかりません。

その他の回答 (4)

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.4

>hkadai4-3.c:75: 警告: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast >hkadai4-3.c:75: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast この警告は >strcpy(str->longer_word_length, d); に対する警告だと思いますが(元のソースの行番号がわからないから推測)、これが警告になる理由がわからないということでしょうか。 strcpyのプロトタイプはだいたいこんな感じ char *strcpy(char *, const char *); 対して longer_word_lengthとdの型はint これでなぜ警告になるのかわからないのでしたら、型や変数について勉強し直した方がいいです。 まさかこういう間違いされてるとは思ってなかったんで . と -> のとこかと思ってました(もちろん . と -> の理解も怪しいですが)

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.3

create_word_pair()で使っている word_pair_t *str; のポインタはいったいドコ指しているんでしょうか? mainのword_pair_t *str;もドコを指しているんでしょう? >c = strcat(a,b); 配列に代入できません。 strcpy(c, a); strcat(c, b); なんじゃないですか? あふれかえってメモリ破壊するかも知れませんけど。 50バイト+50バイトは50バイトでしょうか? そして、50バイト(100バイト?)のデータをcombine_word(combined_word?)の20バイトにどうやって押し込みましょうか? >文字列結合にstrcatを使うと思うのですが、結合の合間にスペースをいれる方法が分かりません。 strcpy(c, a); strcat(c, " "); strcat(c, b); ですか? sprintf(c, "%s %s", a, b); なんてのもありでしょうか? # やっぱり溢れかえる可能性はあるワケですが。 >strcpy(str->longer_word_length, d); >strcpy(str->shorter_word_length, e); int型のコピーにstrcpy()は使いません(使えません)。 create_word_pair()は何も返していません。 returnで指定された型の戻り値を返す必要がありますが…。 で、returnで返しても… >create_word_pair(a,b); 捨てています。 >printf("長い方の文字列%s\n",str->longer_word); >  : >printf("短い方の文字列の長さ%d\n",str->shorter_word_length); create_word_pair()kstrとmain()のstrは別物ですので何も入っていません。 # 最初に指摘したとおりどこを指しているのか不定です。 ツッコミどころ満載ですね…本当に……。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

とりあえず mainのword_pair_t *str;と create_word_pairのword_pair_t *str;とは別ものだって理解してます? create_word_pairが値返してない、とかでませんか? create_word_pairが返した値、受け取ってません。 構造体が戻り値になっていても、基本の作り方は、int等と同じです。

noname#160632
質問者

補足

コンパイルエラーの内容です。関数内で使う変数は関数内でしか参照できないって事が違いですか?最初に構造体宣言をしているからポインタで構造体の中の数値は変えることができるんじゃないんですか?あと戻り値についてですがどういう風に書けばいいんでしょうか? hkadai4-3.c: In function ‘create_word_pair’: hkadai4-3.c:73: error: incompatible types in assignment hkadai4-3.c:74: error: ‘word_pair_t’ has no member named ‘combine_word’ hkadai4-3.c:75: 警告: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:75: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:76: 警告: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:76: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:83: error: request for member ‘longer_word’ in something not a structure or union hkadai4-3.c:84: error: request for member ‘shorter_word’ in something not a structure or union hkadai4-3.c:85: error: incompatible types in assignment hkadai4-3.c:86: error: request for member ‘combine_word’ in something not a structure or union hkadai4-3.c:88: error: request for member ‘longer_word_length’ in something not a structure or union hkadai4-3.c:88: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:89: error: request for member ‘shorter_word_length’ in something not a structure or union hkadai4-3.c:89: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.1

>という問題で、とりあえず自分で細かい条件は無視して文字列を標準入力してから構造体のメンバに文字を格納するところまでやろうとしたのですが、strcpyするのに型が違うとコンパイルエラーが出たのですが、型は一緒だと私は思っているため、なぜ違うのかわかりません。 本当にエラーメッセージはそのような内容でしたか? . と -> はどう違うのか理解してますか? 他にも突っ込みどころ満載だけど・・・

noname#160632
質問者

補足

コンパイルエラー内容です hkadai4-3.c: In function ‘create_word_pair’: hkadai4-3.c:73: error: incompatible types in assignment hkadai4-3.c:74: error: ‘word_pair_t’ has no member named ‘combine_word’ hkadai4-3.c:75: 警告: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:75: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:76: 警告: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:76: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:83: error: request for member ‘longer_word’ in something not a structure or union hkadai4-3.c:84: error: request for member ‘shorter_word’ in something not a structure or union hkadai4-3.c:85: error: incompatible types in assignment hkadai4-3.c:86: error: request for member ‘combine_word’ in something not a structure or union hkadai4-3.c:88: error: request for member ‘longer_word_length’ in something not a structure or union hkadai4-3.c:88: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast hkadai4-3.c:89: error: request for member ‘shorter_word_length’ in something not a structure or union hkadai4-3.c:89: 警告: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast

関連するQ&A

  • 構造体宣言したポインタ変数に値を代入するには?

    strcpy(p -> key ,name);と打ってp -> key に入力した名前を格納したいのですがうまくいきません。 ほかにもp -> key = nameなども試してみましたがコンパイルエラーが出現してダメでした。 うまく格納できるやり方があれば教えてください。よろしくお願いします。 #include<stdio.h> #include<string.h> #define WORD_LENGTH 50 /* 文字列の最大長 */ typedef struct cell{ char key[WORD_LENGTH]; struct cell *next; /* 次のセルへのポインタ */ } CELL; void main(void) { char name[WORD_LENGTH]; CELL *p; printf("名前入力\n"); scanf("%s\n", name); strcpy(p -> key ,name); printf("%s\n", p -> key); }

  • 文字列のコピー

    C言語で、文字列をコピーする関数で、処理が止まってしまいます。 以下が実行したプログラムです。 #include<stdio.h> #include<string.h> void copy(char *str2 ,char *str3){ strcpy(str2,str3); } void input(char* str){ scanf("%s",str); } int main (void){ char *a; char *b="TEST"; printf("%s\n",b); input(a); copy(b,a); printf("%s",b); return(0);} copy(b,a);で処理が止まってしまいます。入力した文字列を表示できるように、御指摘お願いします。

  • 関数の戻り値なんですが...

    VC++を使用し以下のような関数additionで文字列を返したいのですが アドレスしか返しません。配列はその先頭のポインタだということは しっているのですが.... additionは、二つの文字列(32や47などの数字のやつ)を引数とし、そ れを整数型に変換し、その加算を行い、その結果を文字列型に変換し 、その文字列をかえす関数です。 関数の定義などが間違っているのですか?? #include<iostream.h> #include<string.h> #include<string> char *addition(char *,char *); void main(){ using namespace std; char a[] = "1000"; char b[] = "456"; cout << addition(a,b) << '\n'; } char *addition(char *a,char *b){ int c = 0; c = atoi(a)+atoi(b); char p[20]; _itoa(c,p,10); cout << p <<'\n'; return (*p); }

  • C言語の文字列の取り扱いが分かりません

    こんにちは。 C言語で分からないことがあり、質問させていただきました。 学校で、文字列の取り扱いを習いました。 そこで質問なんですが、以下のソースコードをstrcpy , strcat , strcmp , strlen を使わずに書くことってできないですか? 先生に質問したところ、ポインタとかいうのを使うのだそうですが、それを使わずに書くことってできるんですか?もしよろしければお願いします。 以下のプログラムですが、ユーザーから2つの文字列を受けて、そこから4つの文字列関数を使ってみましょう、というやつです。実行結果も貼っておきますね。 #include <string.h> #include <stdio.h> int main(void) { char str1[80], str2[80]; int i; printf("INPUT 1st word-line. : "); gets(str1); printf("INPUT 2nd word-line. : "); gets(str2); /*文字列(word-line)の長さを確認します。*/ printf("%s is %d moji long.\n", str1, strlen(str1)); printf("%s is %d moji long.\n", str2, strlen(str2)); /*文字列を比較します。*/ i = strcmp(str1, str2); if (!i) printf("two word-lines are same length.\n"); else if (i < 0) printf("%s is smaller than %s.\n", str1, str2); else printf("%s is bigger than %s.\n", str1, str2); /*十分なスペースがあるのなら、str2をstr1の最後に結合させます。*/ if((strlen(str1) + strlen(str2)) < 80 ){ strcat(str1, str2); printf("%s\n", str1); } /*str2をstr1にコピーする*/ strcpy(str1, str2); printf("%s %s\n", str1, str2);

  • 文字列の扱いについて教えてください

    #include<cstdio> #include<cstring> #define _CRT_SECURE_NO_DEPRECATE 1 #define MAXBUFF 256 void s_swap(char* str_a, char* str_b) { char str_dummy[MAXBUFF]; strcpy_s(str_dummy,strlen(str_dummy),str_a); ★ strcpy_s(str_a,strlen(str_a),str_b); ★ strcpy_s(str_b,strlen(str_b),str_dummy); } void main(void) { char* str_a = "ABC"; char* str_b = "DEF"; int a; printf("呼出前:str_a=%s, str_b=%s\n", str_a, str_b); s_swap(str_a,str_b); printf("呼出後:str_a=%s, str_b=%s\n", str_a, str_b); } str_aとstr_bの中身を入れ替える処理で、エラーや警告はでないのですが ★のところで実行失敗します。 昔から文字列の処理は苦手でどのように攻略したらよいのか 解説していただけないでしょうか。

  • ライブラリ関数

    文字列をコピーする(strcpy) 文字列の長さを調べる(strlen) 配列の長さを調べる(sizeof) #include <stdio.h> #include <string.h> int main(void) { char s1[128] = "ABCD"; char s2[128] = "EFGH"; char s3[128] = "IJKL"; strcpy(s2, s1); strcpy(s3, s2); puts("s1をs2にs2をs3にコピーしました。"); printf("s1 = %s\n", s1); printf("s2 = %s\n", s2); printf("s3 = %s\n", s3); printf("文字列%sの長さは%uです。\n",s3,(unsigned)strlen(s3)); printf("文字列%sの長さは%uです。\n",s3,strlen(s3)); return (0); } char *strcpy(char *d, const char *s) { while (*d++ = *s++) printf("pointer=%s \n",d); } /* 文字列sをdにコピーする[配列版] */ char *strcpy(char d2[], const char s2[]) { unsigned i=0; while (d2[i] = s2[i]){ i++; printf("hairetsu=%s\n",&d2[i]); } } /*--- 文字列strの長さを返す[ポインタ版] ---*/ size_t strlen(const char *s) { size_t len = 0; while (*s++) len++; return (len); } /*--- 文字列strの長さを返す[配列版] ---*/ unsigned strlen(const char str[]) { unsigned len = 0; while (str[len]) len++; return (len); } c:\program files\microsoft visual studio 8\vc\include\string.h(73) : 'strcpy' の宣言を確認してください。 メッセージ: 'This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.' c:\program files\microsoft visual studio 8\vc\include\string.h(73) : 'strcpy' の宣言を確認してください。 メッセージ: 'This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.' c:\documents and settings\owner\my documents\visual studio 2005\projects\test8-3\test8-3\test8-3.c(48) : error C2084: 関数 'char *strcpy(char *,const char *)' は既に本体を持っています。 c:\program files\microsoft visual studio 8\vc\include\string.h(73) : 'strcpy' の前の定義を確認してください c:\documents and settings\owner\my documents\visual studio 2005\projects\test8-3\test8-3\test8-3.c(68) : error C2084: 関数 'size_t strlen(const char *)' は既に本体を持っています。 c:\program files\microsoft visual studio 8\vc\include\string.h(80) : 'strlen' の前の定義を確認してください 上記の問題が解決できません。助けてください><

  • C++ : cout << (数字) で実行時エラーが発生する理由

    ある特定の位置でcout を用いて数字を表示しようとするとエラーが発生してしまいます。 具体的には以下の関数内でのことなのですが、原因の分かる方がいましたら解答お願いします。 受け取った文字列を逆順にする関数です。 ---------------------------------------------------------- void rev_str(char *a) { int length = 0; cout << length; // ここでエラーが発生 while(true) { if(*(a + length) == '\0') break; length++; } for(int i = 0; i < length / 2; i++) { char temp = a[i]; a[i] = a[length - i - 1]; a[length - i - 1] = temp; } } --------------------------------------------------------- エラーの発生する部分ですが、数字ではなく文字・文字列なら問題なく表示されます。 このコードでは変数 length を表示しようとしていますが、length でなくても、またどのような『数』でも『この関数内』で cout を使用するとエラーが発生します。 この関数に何か間違いがあるのではないかと思うのですが、どうにも見つけることが出来ません。 コード全体はこの下に掲載します。 cout に何か制約があるのでしょうか。それとも、やはりコードのどこかに誤りがあるのでしょうか。わかる方がいましたら、解答お願いします。 全コード ------------------------------------------------------ #include <iostream> #include <cstring> using namespace std; void rev_str(char *a); void rev_str(const char *source, char *des); int main() { char a[80], b[80]; strcpy(a, "hello, world!"); rev_str(a, b); rev_str(a); cout << a << "\n"; cout << b << "\n"; return 0; } void rev_str(char *a) { int length = 0; cout << length; while(true) { if(*(a + length) == '\0') break; length++; } for(int i = 0; i < length / 2; i++) { char temp = a[i]; a[i] = a[length - i - 1]; a[length - i - 1] = temp; } } void rev_str(const char *source, char *des) { char *a = (char*)malloc(sizeof(source)); strcpy(a, source); rev_str(a); strcpy(des, a); free(a); }

  • 文字を置き換える関数で分からないことがあります。

    文字列strの中にある、文字列bagと共通の文字を空白に置き換える関数とその動作を確認するための、空白に置き換えた文字列strを表示するプログラムですが、戻り値が正しくないそうです。 ヒントでもいいのでどう直せばいいのかどなたかお教え下さい。 #include <stdio.h> char str_space(char str[], char bag[]){ int a, b, c, d; for(a = 0; a <= 99; a++){ if(str[a] == '\0'){ c = a; break; } } for(a = 0; a <= 99; b++){ if(bag[a] == '\0'){ d = a; break; } } for(a = 0; a <= c; a++){ for(b = 0; b <= d; b++){ if(str[a] == bag[b]){ str[a] = ' '; } } } return str[]; } int main(void){ char str[100], bag[100]; scanf("%s", str); scanf("%s", bag); printf("%s", str_space(str, bag)); return 0; }

  • プログラムの添削

    以下のようなプログラムを作りました.よりよい書き方,アドバイスなどお願いします. /*文字列の入力を繰り返し受け取るプログラムを作成しなさい.*/ #include<stdio.h> #include<string.h> int main(void) { char bigstr[101],str[31]; printf("文字列の入力を繰り返し受け取るプログラムです.\n"); strcpy(str,""); strcpy(bigstr,""); for(;;) { printf("文字列を入力してください.\n"); gets(str); if(strlen(str)>30) { printf("入力できる文字数の上限(20字)を超えました.\n"); return 0; } else if(strcmp(str,"quit")) { strcat(bigstr,str); if(strlen(bigstr)>100) { printf("入力できる文字数の上限(合計100字)を超えました.\n"); return 0; } } else break; } printf("%s\n",bigstr); return 0; }

  • str系関数を使わずに二つの文字を結合する方法

    自分で色々考えていたのですが中々分からなくて・・・ #include<stdio.h> #include<string.h> int moji(char* b1,char *b2) { char b[11]; int x; strcpy(b, b1); strcat(b, b2); x = strlen(b); return x; } main() { char a[4] = "alt"; char b[8] = "recorde"; int c; c = moji(a, b); printf("文字数は%d\n", c); } のプログラムでmoji関数の部分にあるstr~を全部接続節(for)等で作成してポイントで持ってきた文字を連結するにはどうすればいいでしょうか? strに慣れて自分で作れなくならないためにもお力をかしいただけると嬉しいです。

専門家に質問してみよう