while文の動作が毎回ちがい、間違いがわかりません。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
mokopoko

while文の動作が毎回ちがい、間違いがわかりません。

#1

投稿記事 by mokopoko » 13年前

いぜんは2度、お世話になりました。(御礼の返答をきちんとしていないトピックがございます。失礼しました。)
またよろしくお願いします。次のコードを作ったのですが、毎回反応が違うのです。

目標) 
str[][16]に格納した単語を、str2[][]にランダムに格納しなおす。

例)
char str[][16] = {"abcd", "efghi","jklm","nopq","rstu","vwx","yz","dd","feafe","feaf"};
→char str2[10][16] = { "nopq","abcd","rstu","vwx","jklm","yz","dd","feafe","efghi","feaf"};

現状)
i = 9になると、だいたい次のような結果を表示して終わってしまう。
start
i = 9 : j = 0 : x = 9 for
i = 9 : j = 1 : x = 9 for
i = 9 : j = 2 : x = 9 for
i = 9 : j = 3 : x = 9 for
i = 9 : j = 4 : x = 9 for
i = 9 : j = 5 : x = 9 for
i = 9 : j = 6 : x = 9 for
i = 9 :Program ended with exit code: 0
たまに for構文を抜けて、配列str2の表示(最後のfor構文です)に到達するが、????となっている。

質問)
毎回出力結果が違うのは何が原因でしょうか?

追加の質問)
またよろしければ、二次元配列を別の二次元配列に入れ替えるのは最下段のfor構文であってるでしょうか?別のmain関数内で試しましたが、うまくいってなんです。

恐縮ですがよろしくお願いします。

コード:

 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main (void)
{
    char str[][16] = {"abcd", "efghi","jklm","nopq","rstu","vwx","yz","dd","feafe","feaf"};
    char str2[10][16];
    int k = (unsigned)(sizeof(str) / sizeof(str[0]));
    int num[k];
    printf("%d \n", k);
    for (int i = 0; i < k ; i++) {
        int j;
        int x = 0;
        srand((unsigned)time(NULL));
        do{
            printf("start\n");
            j = 0;
            x = rand() % k ;          
            for (;j <= i; j++) {
                printf(" i = %d : j = %d : x = %d for\n", i, j, x); //ここが表示されています。
                if (i == 0 && x == 0) {
                    num[i] = x;
                    break;
                }
                if (num[j] == x) {
                    printf("break x = num [%d] = %d \n ", j, num[j]);
                    break;
                }
            }
        printf(" i = %d : j = %d : x = %d : k = %d for\n", i, j, x, k);//
        }while (j < i);
        num[i] = x;
        printf("----------------------------------------------OK!num[%d] = %d\n", i, x);
    }
    for (int i = 0; i < k; i++) {
        printf("num[%d] = %d\n", i, num[i]);
    }
//------------------------ 以下はたまに表示されるが????が並んでいるだけが多いです。
    printf("ならべかえ\n");
    for (int i = 0; i <= k; i++) {
        for (int j = 0; str[i][j] != '\0'; j++) {
            printf("%c", str2[i][j]);
        }
        printf("\n");
    }
}


non
記事: 1097
登録日時: 15年前

Re: while文の動作が毎回ちがい、間違いがわかりません。

#2

投稿記事 by non » 13年前

何をしたいのかわかりません。
プログラムにコメントを入れてもらえますか?
特に、どこで、str2[][]に格納しているのか示してください。
ついでに 配列numの目的も。

毎回反応が違うと言うことですが、乱数を使っているからではないですか?
non

box
記事: 2002
登録日時: 15年前

Re: while文の動作が毎回ちがい、間違いがわかりません。

#3

投稿記事 by box » 13年前

mokopoko さんが書きました:

コード:

 
    char str[][16] = {"abcd", "efghi","jklm","nopq","rstu","vwx","yz","dd","feafe","feaf"};
    int k = (unsigned)(sizeof(str) / sizeof(str[0]));
str[][] の要素数は10個ですね。変数 k の値も10のはずですね。この状態で、
mokopoko さんが書きました:

コード:

 
    for (int i = 0; i <= k; i++) {
        for (int j = 0; str[i][j] != '\0'; j++) {
            printf("%c", str2[i][j]);
        }
ループ制御変数 i を k(==10) まで回してしまうと、
str[j] の i が、配列の定義範囲をオーバーしてしまいませんか?大丈夫ですか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

box
記事: 2002
登録日時: 15年前

Re: while文の動作が毎回ちがい、間違いがわかりません。

#4

投稿記事 by box » 13年前

シャッフルできればいい、というだけなら…。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define M (10)
#define N (16)
#define C (20)  // シャッフルする回数(適当に決めてください)

void init(char (*d)[N], char (*s)[N])
{
    int i;

    for (i = 0; i < M; i++) {
        strcpy(d[i], s[i]);
    }
}

void shuffle(char (*s)[N])
{
    char t[N];
    int i, m, n;

    for (i = 0; i < C; i++) {
        m = rand() % M, n = rand() % M;
        strcpy(t, s[m]);
        strcpy(s[m], s[n]);
        strcpy(s[n], t);
    }
}

void print(char (*s)[N])
{
    int i;

    for (i = 0; i < M; i++) {
        printf("%s\n", s[i]);
    }
}

int main (void)
{
    char str[M][N] = {
        "abcd", "efghi", "jklm", "nopq",  "rstu",
        "vwx",  "yz",    "dd",   "feafe", "feaf",
    };
    char str2[M][N];

    srand((unsigned) time(NULL));
    init(str2, str);
    printf("【シャッフル前】\n");
    print(str2);
    shuffle(str2);
    printf("【シャッフル後】\n");
    print(str2);
    return 0;
}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

mokopoko

Re: while文の動作が毎回ちがい、間違いがわかりません。

#5

投稿記事 by mokopoko » 13年前

①boxさん
ご返信ありがとうございます。コードまで掲載していただきすごくうれしいです。
strcpyを使うんですね。つぎの部分は本でよく見るswap関数の中身によく似ています。

コード:

 
strcpy(t, s[m]);
strcpy(s[m], s[n]);
strcpy(s[n], t);
②nonさん、boxさん
実はわたしなりに、前記の私の稚拙コードの
12行目から33行目にかけて(doーwhile文)は本に記載されていたコードを参考にしてみました。
(下記に参考にしたコードを乗せておきます。)
一次元配列にランダムに重複せずに数字を格納するコードですが、
私はそれを使って2次元配列の先頭の要素番号(str[★][] つまり、★の部分)に代入してシャッフルしたかったのです。
どこがまちがってるんだろう・・・

boxさんのコードはすごくすっきりしてわかりやすいですね。
「シャッフル」とくれば「bonさんが記述されたようにswap関数的なものの」流れがいちばんいいのでしょうかね?

コード:

int allocate _integer(int d[], int n){
    int i, j, x;
    num[0] = 0;
    for( i = 1; i <10; i++){
        do{
            x = rand() % 7;
            for(j = 0; j < i; j++){
                if(num[j] == x)
                    break;
            } while (i != j);
            num[i] = x;
        }
        j = rand() % 10;
        if(j != 0)
            swap(int, num[0], num[j])
    }
}

mokopoko

Re: while文の動作が毎回ちがい、間違いがわかりません。

#6

投稿記事 by mokopoko » 13年前

参考したコードをまちがえていました。訂正しておきます。すみません。

コード:

int allocate _integer(int num[], int n){ //d[]→num[]
    int i, j, x;
    num[0] = 0;
    for( i = 1; i <10; i++){
        do{
            x = rand() % 7;
            for(j = 0; j < i; j++){
                if(num[j] == x)
                    break;
            } while (i != j);
            num[i] = x;
        }
        j = rand() % 10;
        if(j != 0)
            swap(int, num[0], num[j])
    }
}

non
記事: 1097
登録日時: 15年前

Re: while文の動作が毎回ちがい、間違いがわかりません。

#7

投稿記事 by non » 13年前

後で、添付されたコードも恐らく間違っています。
non

mokopoko

Re: while文の動作が毎回ちがい、間違いがわかりません。

#8

投稿記事 by mokopoko » 13年前

失礼しました。rand() を割る数のところは10以上じゃないと重複してしまいますね。

コード:

int allocate _integer(int num[], int n){ //d[]→num[]
    int i, j, x;
    num[0] = 0;
    for( i = 1; i <10; i++){
        do{
            x = rand() % 15; //重複しない数字でなければならないから10以上じゃないとだめですね。
            for(j = 0; j < i; j++){
                if(num[j] == x)
                    break;
            } while (i != j);
            num[i] = x;
        }
        j = rand() % 10;
        if(j != 0)
            swap(int, num[0], num[j])
    }
}

non
記事: 1097
登録日時: 15年前

Re: while文の動作が毎回ちがい、間違いがわかりません。

#9

投稿記事 by non » 13年前

do while の位置が違ってます。
引数として、nが渡されていますが使われていません。
non

non
記事: 1097
登録日時: 15年前

Re: while文の動作が毎回ちがい、間違いがわかりません。

#10

投稿記事 by non » 13年前

mokopoko さんが書きました:失礼しました。rand() を割る数のところは10以上じゃないと重複してしまいますね。
いや、10ぴったりの方が・・・
non

mokopoko

Re: while文の動作が毎回ちがい、間違いがわかりません。

#11

投稿記事 by mokopoko » 13年前

nonさん
なんどもすみません。
たしかにnはつかれていないですし、10にしたほうがいいですね。
ありがとうございます。

ですが、do-whileがどうして良くないのかがわかりません。

コード:

int allocate _integer(int num[]){ //d[]→num[]
    int i, j, x;
    num[0] = 0;
    for( i = 1; i <10; i++){
        do{
            x = rand() % 10; //重複しない数字でなければならないから10以上じゃないとだめですね。
            for(j = 0; j < i; j++){
                if(num[j] == x)
                    break;
            } while (i != j);
            num[i] = x;
        }
        j = rand() % 10;
        if(j != 0)
            swap(int, num[0], num[j])
    }
}

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: while文の動作が毎回ちがい、間違いがわかりません。

#12

投稿記事 by beatle » 13年前

mokopoko さんが書きました: ですが、do-whileがどうして良くないのかがわかりません。

コード:

int allocate _integer(int num[]){ //d[]→num[]
    int i, j, x;
    num[0] = 0;
    for( i = 1; i <10; i++){
        do{
            x = rand() % 10; //重複しない数字でなければならないから10以上じゃないとだめですね。
            for(j = 0; j < i; j++){
                if(num[j] == x)
                    break;
            } while (i != j);
            num[i] = x;
        }
        j = rand() % 10;
        if(j != 0)
            swap(int, num[0], num[j])
    }
}
これでコンパイルできるならいいんですよ?でもこれではコンパイルできないでしょう。
なぜなら do と while (i != j); の位置が対応していないからです。

mokopoko

Re: while文の動作が毎回ちがい、間違いがわかりません。

#13

投稿記事 by mokopoko » 13年前

beatleさん。
ご返信、ご指摘有り難うございます。確認もせず、失礼、ご迷惑をおかけしました。
あらためて直して、動くことを確認したので(mac)、下記にしるしておきます。

コード:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define swap(type, x, y) do { type t = x; x = y; y = t;} while(0)
int allocate_integer(int []);
int main (int argc, const char * argv[])
{
    int str[10] = {0,1,2,3,4,5,6,7,8,9};
    printf("mojiirete\n");
    allocate_integer(str);
    for (int j = 0; j <=9; j++) {
        printf("str[%d] = %d\n", j, str[j]);
    }
}

int allocate_integer(int num[]){//d[]→num[]
    int i, j, x;
    num[0] = 4;
    for( i = 1; i <10; i++){
        do{
            x = rand() % 10;
            for(j = 0; j < i; j++){
                if(num[j] == x)
                    break;
            }
            num[i] = x;
        }while (i != j);
        j = rand() % 10;
        if(j != 0)
            swap(int, num[0], num[j]);
            }
    return j;
}

閉鎖

“C言語何でも質問掲示板” へ戻る