50264


### 前提・実現したいこと

任意の桁数の2進数の全通りを配列に格納してそれを出力するようなプログラムを作りたいです．  
例えば，2桁であれば

[code]

    [1,1]
    [0,1]
    [1,0]
    [1,1]
    
[/code]

三桁であれば

[code]

    [1,1,1]
    [0,1,1]
    [1,0,1]
    [0,0,1]
    [1,1,0]
    [0,1,0]
    [1,0,0]
    [0,0,0]
    
[/code]

というふうに格納・出力をしたいですが，以下のような出力になってしまいます．  
どこがおかしいのか，どなたか教えてください．．．

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

3桁の時について，  
出力すると

[code]

    0 0 1 
    1 0 0 
    0 0 32563 
    0 32765 0 
    32765 0 0 
    1664188935 3 -1 
    
[/code]

というように，代入がうまくできていないようです．．．

[code]

    #include<stdio.h>
    
    int pow_2(int digit);   /*2の引数乗を戻す*/
    void make_binary(int len1,int len2, int n, int (*a)[n]);    
    /*len1(=len2)×nの二次元配列に0または1を代入し，n桁?の全ての2進数を作成*/
    int main(void){
        int i,j;
        int digit,len;
        digit=3;
        len=pow_2(digit);
        int a[len][digit];　/*ここでは，3桁の二進数(先頭が0でも良い)が8通り存在するので8×3の配列を用意*/
        make_binary(len, len, digit-1,a);
    
        for(i=0; i<len; i++){
            for(j=0; j<digit; j++){
                printf("%d ",a[i][j]);
            }
            printf("\n");
        }
    
        return 0;
       }
    int pow_2(int digit){
        int i;
        int a=1;
        for(i=0; i<digit; i++){
            a=a*2;
        }
        return a;
    }
    void make_binary(int len1,int len2, int n, int (*a)[n]){
        int i,j;
        i=0;
        if (n==-1){
             return ;
        }
        else{
            while(i<len1){
                for(j=0; j<len2/2; j++){
                    printf("%d %d ",i,j);
                    printf("\n");
                    a[i++][n]=1;
                }
                for(j=len2/2; j<len2; j++){
                    printf("%d   %d ",i,j);
                    printf("\n");
                    a[i++][n]=0;
                }
            }
            make_binary(len1, len2/2, n-1, a);
        }
    }
    
[/code]


CC BY-SA 4.0
2018-11-12T16:57:54.393
50262
2018-11-13T00:16:34.393
2018-11-13T00:16:34.393
3060
30960
question
c
C 言語で任意の桁数の二進数の全ての通り数を配列に格納したい


とりあえず `int a[len][digit];`は、`unsigned int a[len][digit];`の方が良い気がします。

それはおいておいて、直接の原因は、2次元配列`a`をうまく渡せていないためと思われます。  
`C99`だと、 func(int x, int y, int
array[x][y])と宣言して、`x`×`y`の２次元配列`array`を受け取れますので、`make_binary`を

[code]

    void make_binary(int len1,int len2, int n, int (*a)[n])
    
[/code]

から

[code]

    void make_binary(int len1,int len2, int x, int y, int a[x][y])
    
[/code]

と、書き替えれば動くと思います。  
（`y`は`n`でも良かったのですが、`int x, int n`だと据わりが悪かったので）

呼び出す際は、

[code]

    make_binary(len1, len2, (max - 1), (digit -1), a);
    
[/code]

の様にして呼び出します。

ちなみに、該当ビットの`0/1`判断がロジックを追いにくいものになっているので、直接、その数字の該当ビットを見て判断するサンプルプログラムを作ってみました。  
よろしければ、参考にしてください。

[code]

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    void makeArray(int digit);
    
    int main(int argc, const char * argv[]) {
        // insert code here...
        int digit = atoi(argv[1]);
        makeArray(digit);
    
        return 0;
    }// end int main
    
    void makeArray(int digit)
    {
        int max = pow(2, digit);
        // allocate allay
        unsigned short array[max][digit];
        // create data
        int currentBit = 0;
        int value = 0;
        for (value = max - 1; value >= 0; value--) { // 最大値 -1 から０まで逆順に
            for (currentBit = digit - 1; currentBit >= 0; currentBit--) { // 大きい方のビットから小さい方のビットへ
                    // ビット演算の値が0なら、0, そうでないならそのビットは1
                array[value][currentBit] = (value & (1 << currentBit)) == 0 ? 0 : 1;
            }// end foreach bit
        }// end foreach value
    
        // print value
        for (value = max - 1; value >= 0; value--) {
            printf("%d : [", value);
            for (currentBit = digit - 1; currentBit >= 0; currentBit--) {
                if (currentBit != 0) {
                    printf("%d,", array[value][currentBit]);
                } else {
                    printf("%d", array[value][currentBit]);
                }
            }// end foreach bit
            printf("]\n");
        }// end foreach value
    }// end int **makeArray
    
[/code]


CC BY-SA 4.0
2018-11-12T20:05:25.670
50264
2018-11-12T20:05:25.670
14745
50262
answer


一番の問題点は、

[code]

    void make_binary(int len1,int len2, int n, int (*a)[n]);    
    
[/code]

のように関数宣言しているのに、呼び出し側が、

[code]

    make_binary(len, len, digit-1,a);
    
[/code]

とか、

[code]

        make_binary(len1, len2/2, n-1, a);
    
[/code]

とかなってしまっていることですね。

`int n, int
(*a)[n]`と言う宣言により`a`に渡される2次元配列の2次元目の要素数は`n`でないといけません。あなたのコードでは、`digit=3`の状態で`int
a[len][digit]`と宣言しているのですから、`int (*a)[n]`の`n`は常に`3`でないといけません。

`main`内の`a`

[code]

         (オフセットは`int`単位)
         +-----------+-----------+-----------+
    a -> |[0][0]-> +0|[0][1]-> +1|[0][2]-> +2|
         +-----------+-----------+-----------+
         |[1][0]-> +3|[1][1]-> +4|[1][2]-> +5|
         +-----------+-----------+-----------+
         |...                                |
    
[/code]

このように作られた配列の先頭アドレス`a`を`int
(*a)[2]として渡してしまうと、渡された側では`a`の1要素は`int[2]`、つまり2次元めの要素数は2として扱われてしまいます。

`make_binary`内の`a` (`n`が2の場合)

[code]

         +-----------+-----------+
    a -> |[0][0]-> +0|[0][1]-> +1|
         +-----------+-----------+
         |[1][0]-> +2|[1][1]-> +3|
         +-----------+-----------+
         |[2][0]-> +4|[2][1]-> +5|
         +-----------+-----------+
         |...                    |
    
[/code]

あなたが`make_binary`内で`a[1][1]`の中身を書き換えると、`main`側の視点では`a[1][0]`を書き換えてしまっているのです。(どちらもメモリ内でオフセット+3の位置。)

色々と修正方法はあるでしょうが、割り当てられた領域のサイズと、処理に必要な`n`の値を別に管理してやるのが一番簡単でしょう。

プロトタイプ宣言を、

[code]

    void make_binary(int len1, int len2, int n, int size, int (*a)[size]);
    
[/code]

とかにしてやって、呼び出す側は、

`main`内:

[code]

    make_binary(len, len, digit-1, digit, a);
    
[/code]

`make_binary`内:

[code]

        make_binary(len1, len2/2, n-1, size, a);
    
[/code]

としてみて下さい。


CC BY-SA 4.0
2018-11-12T20:53:06.257
50265
2018-11-12T20:53:06.257
13972
50262
answer