質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

3115閲覧

C言語でババ抜き:手札の生成がうまくいかない

ryota1017stars

総合スコア21

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2018/08/27 23:52

前提・実現したいこと

C言語でババ抜きを開発しています。
53枚のカードのまとまり(デッキ)を作成し、それを3人のプレイヤーに順に配る処理(CreateHand)で以下のエラーが発生しました。

CreateDeck関数で生成したデッキを、CreateHand関数に渡し、player_cards配列を生成したいです。

発生している問題・エラーメッセージ

Main.c:22:12: warning: incompatible pointer to integer conversion returning 'char [53][4]' from a function with result type 'char' [-Wint-conversion] return deck; ^~~~ Main.c:26:17: warning: type specifier missing, defaults to 'int' [-Wimplicit-int] char CreateHand(array[]) { ^ Main.c:34:9: warning: implicitly declaring library function 'strcpy' with type 'char *(char *, const char *)' [-Wimplicit-function-declaration] strcpy(player_cards[player_number][j],array[i]); ^ Main.c:34:9: note: include the header <string.h> or explicitly provide a declaration for 'strcpy' Main.c:34:47: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *' [-Wint-conversion] strcpy(player_cards[player_number][j],array[i]); ^~~~~~~~ Main.c:41:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ Main.c:47:16: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'int *' [-Wint-conversion] CreateHand(deck1); ^~~~~ Main.c:26:17: note: passing argument to parameter 'array' here char CreateHand(array[]) {

該当のソースコード

C

1char CreateDeck() { 2//デッキを作成する 3 char deck[53][4] = {"S1","S2","S3","S4","S5","S6","S7","S8","S9","S10","S11","S12","S13", 4 "H1","H2","H3","H4","H5","H6","H7","H8","H9","H10","H11","H12","H13", 5 "C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13", 6 "D1","D2","D3","D4","D5","D6","D7","D8","D9","D10","D11","D12","D13","J0" 7 }; 8 return deck; 9} 10 11char CreateHand(array[]) { 12//3人分の手札を生成する 13 14   //3人の手札として使う配列 15 char player_cards[3][18][4]; 16 17 int player_number = 0; 18 int j = 0; 19 for (int i = 0; i < 53; i++) { 20 21 //Aさん、Bさん、Cさん、Aさん、Bさん、Cさん、の順番でデッキからカードが無くなるまで配る 22 strcpy(player_cards[player_number][j],array[i]); 23 24 player_number++; 25 if (player_number >= 3) { 26 player_number = 0; 27 j++; 28 } 29 } 30} 31 32int main(void){ 33 34 char deck1 = CreateDeck(); 35 CreateHand(deck1); 36} 37

試したこと

関数にせず、全てのコードをmain関数に記述して実行すると、うまくいきました。

補足情報(FW/ツールのバージョンなど)

paiza.ioでコードを実行しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2018/08/28 00:37

“//3人の手札として使う配列”の前にUNICODEのスペースが入っているd^^
guest

回答3

0

気づいたところをいくつか。

char deck[53][4]

ローカル変数なので、関数を抜けると消滅します。

char CreateDeck() {
return deck;

変数の型と戻り値の型が一致していません。

char CreateHand(array[]) {

引数の型が未定義です。
また戻り値の型を定義しているのにreturnしていません。

投稿2018/08/28 00:54

ttyp03

総合スコア16998

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryota1017stars

2018/08/28 01:39 編集

ご回答ありがとうございます。 ・引数の型が未定義です。また戻り値の型を定義しているのにreturnしていません。 この部分ですが、以下のように引数の型を定義し、戻り値を設定しました。 この関数も同じようにローカル変数を戻り値に設定していますので、そこも修正します。 ``` char CreateHand(char array[]) { char player_cards[3][18][4]; int player_number = 0; int j = 0; for (int i = 0; i < 53; i++) { strcpy(player_cards[player_number][j],array[i]); player_number++; if (player_number >= 3) { player_number = 0; j++; } } return player_cards; } ```
ttyp03

2018/08/28 01:43

また型が一致してませんよ。 この手のプログラムの場合、関数内で領域を用意するのではなく、メインもしくはグローバル(極力避けてください)に置いて、それを各関数に渡すほうがよいと思いますよ。 入れ物を用意したので関数内でここに入れてくださいね、といった具合です。
ryota1017stars

2018/08/28 04:21

"関数内で領域を用意するのではなく、メインもしくはグローバル(極力避けてください)に置いて、それを各関数に渡すほうがよい" とありますが、以下のコードのようにmainの中で配列を宣言して、mainの中で複数の関数にその配列を渡してそれぞれ処理をする、という解釈で合ってますでしょうか? int main(void){ //デッキの入れ物だけを生成 char deck[53][4]; //デッキの入れ物にカードを入れる関数 FunctionA(deck); //デッキの中身をシャッフルする関数 FunctionB(deck); }
ttyp03

2018/08/28 04:23

あってます。
ryota1017stars

2018/08/28 05:17

ありがとうございます。理解出来ました!
guest

0

ベストアンサー

まずいところをいくつか。

char CreateDeck() {

引数の定義がない。引数がないなら void をいれとこう

return deck;

戻り値は char のはずなのに、char** を返している <<1つ目のワーニング

char CreateHand(array[]) {

array の型が無い <<2つ目のワーニング
また、この関数の戻り値がない

雰囲気でコードを書いてはいけません


最初の配列を真面目に記述するなら、

C

1typedef char* CARD_DECK[4][13]; 2 3CARD_DECK CreateDeck() { 4 static CARD_DECK deck={ 5 { "S1", ... }, 6 { "H1", ... }, 7 { "C1", ... }, 8 { "D1", ... }, 9 }; 10 11 return deck; 12}

とゆーふーになろうかと思われます
#あ、ジョーカーをど~しよう

投稿2018/08/28 00:03

編集2018/08/28 05:36
y_waiwai

総合スコア87749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryota1017stars

2018/08/28 01:21

ご回答ありがとうございます。 ・戻り値は char のはずなのに、char** を返している <<1つ目のワーニング ここが理解出来なかったのですが、私は配列deckを戻り値として返しているつもりでしたが、 解釈が違っていますか?実際にはポインタを戻り値にしていたということでしょうか?
y_waiwai

2018/08/28 01:39

配列名は相当のポインタと読み替えられます この場合、戻り値が char のため、アドレスの一部しか返されません。 正しくは、戻り値の型を、char** とすればいいです、が、 他の方の指摘にある通り、AUTO変数は関数抜けると消滅しますのでこれでもダメです
ryota1017stars

2018/08/28 05:15

"AUTO変数は関数抜けると消滅"とありますが、以下のように変数xを関数内で 書いて、戻り値で返して外に出す書き方もNGでしょうか? int test(void) { int x = 10; return x; } int main(void){ int ten = test(); printf("%d\n", ten); }
y_waiwai

2018/08/28 05:22

それはかまいません。変数の値を戻しているので。 元質問の例では、配列のアドレスを返してますが、その中身が、関数を抜けた時点で消滅します 配列のアドレス値を返すんですが、その指し先が不定となります
ryota1017stars

2018/08/28 08:22

配列名自体がその配列の先頭のアドレスを指しており、"return 配列名"は配列のポインタである、 という風に理解しました。 "最初の配列を真面目に記述するなら"以降のコードで質問があるのですが、 CARD_DECK CreateDeck() のCARD_DECKは、char*と同じ意味でしょうか? なぜtypedefで記載名を変更したのでしょうか?
y_waiwai

2018/08/28 08:27

char* ではないです char* の[4][13]のサイズの配列です。
ryota1017stars

2018/08/28 10:45

投稿した質問の本質と離れてきてしまったため、一旦締め切りたいと思います。 今回の投稿で様々な疑問点が生まれました。また質問を投稿した際にはお力をお貸しいただけたらと思います。 ありがとうございました。
guest

0

ちょっと見ですが、char deck[53][4]はオート変数(関数内変数)になってます。したがって、関数を抜けると無効になります。なので、staticまたはstatic constにしないと消滅してしまいます。

投稿2018/08/28 00:02

cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryota1017stars

2018/08/28 01:31

ご回答ありがとうございます。 static char deck[53][4]とすれば、プログラム終了まで値を保持する、というところまで理解出来ました。 このようにstaticをローカル変数につけて関数外でも使用するのと、グローバル変数で宣言して関数外でも使用するのとは、どう使い分ければ良いでしょうか?
cateye

2018/08/28 01:58 編集

基本的に、グローバル変数は使用しないようにします。ただ、今回のように表があってそれをプログラム全体で参照するようであればいいと思います。ただその場合も、contにするなりして外部から変更が出来ないようにする必要もあるかと思います。constにしておけば、変更を行う処理をコンパイラが見つけてくれます。私は、staticは初期値有りの関数固有のカウンタ等に使うぐらいです。また、main()内で宣言したデータは、呼び出先にデータなり、ポインタを渡せばたいてい解決します。ので、main()内にデータを持たす方ですねd^^
ryota1017stars

2018/08/28 08:23

グローバル変数は極力使用しない、するとしたらconstして定数にする、と理解しました。 "main()内で宣言したデータは、呼び出先にデータなり、ポインタを渡せばたいてい解決します" この部分が理解出来なかったのですが、main内でローカル変数を宣言して、他の関数にポインタを渡せば良いということでしょうか?
cateye

2018/08/28 08:32

main()で宣言した変数は、プログラム終了(mainを抜ける)まで存在します。なので、他の関数を呼び出すときにポインタを渡すことで、その変数は利用可能となります。
ryota1017stars

2018/08/28 10:42

なるほど、、ポインタの概念がまだ理解しきれてないので、勉強します。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問