• 締切済み

ブールリストについて

以下のようなブールリストからall_list[list_count][M]からlist[N][M]を引いた結果をother_list[other_list_count][M]に格納したいのですが上手くいきません。どこがいけないのか答えていただければ幸いです。 #define N 4 //与えられたboolリストの数 #define M 4 //与えられたboolリストの長さ #define list_count M * M //全てのboolリストの数 #define other_list_count list_count - N //与えられたboolリスト以外のリストの数 //与えられたboolリスト char list[N][M] = { { 't' , 't' , 't' , 'f' }, { 't' , 't' , 't' , 't' }, { 't' , 'f' , 't' , 'f' }, { 'f' , 't' , 't' , 'f' } }; //boolリストの全てのパターン char all_list[list_count][M] = { { 't' , 't' , 't' , 't' }, { 't' , 't' , 't' , 'f' }, { 't' , 't' , 'f' , 't' }, { 't' , 't' , 'f' , 'f' }, { 't' , 'f' , 't' , 't' }, { 't' , 'f' , 't' , 'f' }, { 't' , 'f' , 'f' , 't' }, { 't' , 'f' , 'f' , 'f' }, { 'f' , 't' , 't' , 't' }, { 'f' , 't' , 't' , 'f' }, { 'f' , 't' , 'f' , 't' }, { 'f' , 't' , 'f' , 'f' }, { 'f' , 'f' , 't' , 't' }, { 'f' , 'f' , 't' , 'f' }, { 'f' , 'f' , 'f' , 't' }, { 'f' , 'f' , 'f' , 'f' } }; //与えられたboolリスト以外のリスト char other_list[other_list_count][M]; int i,j,k,s = 0; //与えられたboolリスト以外のリストの作成 for(i=0;i<list_count;i++){ k = 0; for(j=0;j<N;j++){ if((strcmp(all_list[i],list[j])) == 0) {k++;} } if(k==0){ strcpy(other_list[s],all_list[i]); s++; } }

みんなの回答

回答No.2

>どこがいけないのか strcmpとstrcpyを使うのがいけない。 strcmpやstrcpyは「引数に与える文字列には、文字列の終端記号が必要」です。 char list[N][M] = { { 't' , 't' , 't' , 'f' }, { 't' , 't' , 't' , 't' }, { 't' , 'f' , 't' , 'f' }, { 'f' , 't' , 't' , 'f' } }; の配列や char all_list[list_count][M] = { { 't' , 't' , 't' , 't' }, { 't' , 't' , 't' , 'f' }, (略) の配列には「文字」は入っていますが「文字列」は入っていません。 「そんな筈は無い!」と疑問に思うなら、以下の文を試してみましょう。 printf("list[0]=%s\n",list[0]); printf("list[1]=%s\n",list[1]); printf("all_list[0]=%s\n",all_list[0]); printf("all_list[1]=%s\n",all_list[1]); もしlist[0]やlist[1]、all_list[0]やall_list[1]に「strcmpやstrcpyで使える、終端記号が付いた文字列」が入っているなら list[0]=tttf list[1]=tttt all_list[0]=tttt all_list[1]=tttf と言う表示になる筈です。 でも、そうはなりません。やってみると「なんじゃこりゃ!」って結果になります。 修正方法は、2つあります。 その1。配列の中身が「文字列」になるよう、文字列の終端記号を足す。 char list[N][M + 1] = { { 't' , 't' , 't' , 'f' ,0 }, { 't' , 't' , 't' , 't' ,0 }, { 't' , 'f' , 't' , 'f' ,0 }, { 'f' , 't' , 't' , 'f' ,0 } }; //boolリストの全てのパターン char all_list[list_count][M + 1] = { { 't' , 't' , 't' , 't' ,0 }, { 't' , 't' , 't' , 'f' ,0 }, (略) { 'f' , 'f' , 'f' , 't' ,0 }, { 'f' , 'f' , 'f' , 'f' ,0 } }; //与えられたboolリスト以外のリスト char other_list[other_list_count][M + 1]; (以下略) 配列の中身を上記のように直すと printf("list[0]=%s\n",list[0]); printf("list[1]=%s\n",list[1]); printf("all_list[0]=%s\n",all_list[0]); printf("all_list[1]=%s\n",all_list[1]); の結果が list[0]=tttf list[1]=tttt all_list[0]=tttt all_list[1]=tttf と言う表示になる筈です。 なお char list[N][M + 1] = { { 't' , 't' , 't' , 'f' ,0 }, { 't' , 't' , 't' , 't' ,0 }, { 't' , 'f' , 't' , 'f' ,0 }, { 'f' , 't' , 't' , 'f' ,0 } }; は char list[N][M + 1] = { { "tttf" }, { "tttt" }, { "tftf" }, { "fttf" } }; または char list[N][M + 1] = { "tttf" , "tttt" , "tftf" , "fttf" }; と書いても同じです。 つまり "tttf" と書くと、自動的に「文字列の終端記号」も付加され { 't' , 't' , 't' , 'f' ,0 } と書いたのと同じになるのです。 その2。strcmpやstrcpyを使わない。 if((strcmp(all_list[i],list[j])) == 0) {k++;} ↓ if((memcmp(all_list[i],list[j]),M) == 0) {k++;} strcpy(other_list[s],all_list[i]); ↓ memcpy(other_list[s],all_list[i],M); memcmp、memcpyは「文字列ではなくメモリの中身を、バイト単位で比較、コピー」します。 比較やコピーの長さを引数で指定するので「文字列の終端記号」は無関係です。「文字列の終端記号」は「あってもなくても関係ない」ので、今回のような「文字列の終端記号が入ってなくて文字列として扱う事が出来ない、文字のみが入った配列の中身を比較、コピーするのに使う」事ができます。 蛇足ですが #define list_count M * M //全てのboolリストの数 #define other_list_count list_count - N //与えられたboolリスト以外のリストの数 は間違い。 #define list_count (1 << M) //全てのboolリストの数 #define other_list_count (list_count - N) //与えられたboolリスト以外のリストの数 が正解。 「すべての組み合わせ」は「2通り×2通り×2通り×2通り」で「2の4乗通り」でなければならない。 今回、偶然に「Mが4で、2の4乗=16=4×4」だから問題が無かったけど、これが「Mが3」とか「Mが5」だったら、変な数値になる。 Mが3なら、「2通り×2通り×2通り」で「2の3乗通り」で「8通り」でなければならないが「M×M=9」で、数値が合わなくなる。 Mが5なら、「2通り×2通り×2通り×2通り×2通り」で「2の5乗通り」で「32通り」でなければならないが「M×M=25」で、数値が合わなくなる。 また「M * M」や「1 << M」や「list_count - N」のような演算子を含む式を定義する場合は、必ず、式の全体を括弧でくくる事。 括弧を付けないと、other_list_countの2倍の要素数の配列が欲しくて char other_list_x2[other_list_count * 2][M]; って書いた時に、とんでもない事になる。 なぜなら、括弧が無いと char other_list_x2[other_list_count * 2][M]; は char other_list_x2[list_count - N * 2][M]; になる。これは、*の方が先に計算されるから char other_list_x2[list_count - (N * 2)][M]; であって char other_list_x2[list_count - N - N][M]; と同じだから、2倍にはならない。 簡単に確かめるなら printf("other_list_count=%d\n",other_list_count); printf("other_list_count * 2=%d\n",other_list_count * 2); を実行してみよう。 other_list_count=12 other_list_count * 2=8 になってしまう。 ちゃんと括弧でくくれば other_list_count=12 other_list_count * 2=24 になる。

satoshi551
質問者

お礼

ありがとうございます。とても丁寧でわかりやすかったです。 '\0'がポイントですね^^

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.1

#include <stdio.h> #include <string.h> #define N 4 //与えられたboolリストの数 #define M 4 //与えられたboolリストの長さ #define list_count M * M //全てのboolリストの数 #define other_list_count list_count - N //与えられたboolリスト以外のリストの数 int main(void) { //与えられたboolリスト char list[N][M+1] = { "tttf", "tttt", "tftf", "fttf", }; //boolリストの全てのパターン char all_list[list_count][M+1] = { "tttt", "tttf", "ttft", "ttff", "tftt", "tftf", "tfft", "tfff", "fttt", "fttf", "ftft", "ftff", "fftt", "fftf", "ffft", "ffff", }; //与えられたboolリスト以外のリスト char other_list[other_list_count][M+1]; int i, j, s = 0; //与えられたboolリスト以外のリストの作成 for (i = 0; i < list_count; i++) { for (j = 0; j < N; j++) { if ((strcmp(all_list[i], list[j])) == 0) { break; } } if (j == N) { strcpy(other_list[s], all_list[i]); printf("%s\n", other_list[s]); s++; } } return 0; }

satoshi551
質問者

お礼

ありがとうございます。そういうやり方もあったんですね。

関連するQ&A