掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.25369

無限ループ
投稿者---johan(2006/01/15 12:54:22)


XP VC++

//Eを入力するまで文字列を入力し、文字を種類別にわけるプログラムを
つくりたいのですが、1回目に//Eと入力するとなぜか無限ループしてしまいます。どなたかご教授お願いします。


#include<stdio.h>
void main(void);

void main(void){
    /*変数を宣言*/
    char retu[256];
    int i;
    int l;
    int k;
    double kuhaku_k;
    kuhaku_k=0;
    char eiji[53]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    double eiji_k;
    eiji_k=0;
    char suuji[11]="1234567890";
    double suuji_k;
    suuji_k=0;
    char kigou[31]="!\"#$%&\'()=~^|\\@{}[]*/+-?<>.;:_";
    double kigou_k;
    kigou_k=0;
    double tab_k;
    tab_k=0;
    double other_k;
    other_k=0;
    int total;
    total=0;
    int retu_k;
    retu_k=0;
    int node[5]={0,1,2,3,4};
    double count[5];
    char *str[5];
    /*//Eが入力されるまで文字列を入力して種類別に分ける*/
    while (retu[0] != '/' && retu[1] != '/' && retu[2] != 'E'){
        gets(retu);
        if(retu[0]=='/'){
            if(retu[1]=='/'){
                if(retu[2]=='E'){
                    break;
                }
            }
        }
        /*文字列処理*/
        i=0;
        while(retu[i]!='\0'){
            /*空白*/
            if(retu[i]==' '){
                kuhaku_k++;
                i++;
            }
            /*タブ*/
            else if(retu[i]=='  '){
                    tab_k++;
                    i++;
            }
            /*数字*/
            else{
                for(l=0;l<10;l++){
                    if(retu[i]==suuji[l]){
                        suuji_k++;
                        i++;
                        break;
                    }
                }
            }
            if(l==10){
            /*記号*/
                for(l=0;l<30;l++){
                    if(retu[i]==kigou[l]){
                        kigou_k++;
                        i++;
                        break;
                    }
                }
                if(l==30){
                    /*英字*/
                    for(l=0;l<52;l++){
                        if(retu[i]==eiji[l]){
                            eiji_k++;
                            i++;
                            break;
                        }
                    }
                    if(l==52){
                        /*その他*/
                        other_k++;
                        i++;
                    }
                }
            }
        }
        total=total+i;
        retu_k++;
    }
    printf("単位 %% 0----1----2----3----4----5----6----7----8----9----+");
    /*割合を求める*/
    kuhaku_k=(kuhaku_k/total)*100;
    kuhaku_k=kuhaku_k/2;
    str[0]="空白";
    count[0]=kuhaku_k;
    eiji_k=(eiji_k/total)*100;
    eiji_k=eiji_k/2;
    str[1]="英字";
    count[1]=eiji_k;
    suuji_k=(suuji_k/total)*100;
    suuji_k=suuji_k/2;
    str[2]="数字";
    count[2]=suuji_k;
    kigou_k=(kigou_k/total)*100;
    kigou_k=kigou_k/2;
    str[3]="記号";
    count[3]=kigou_k;
    tab_k=(tab_k/total)*100;
    tab_k=tab_k/2;
    str[4]="タブ";
    count[4]=tab_k;
    other_k=(other_k/total)*100;
    other_k=other_k/2;
    /*降順に並べ替える*/
    for(l=5;l>0;l--){
        for(i=0;i<l;i++){
            if(count[node[i]]<count[node[i+1]]){
                k=node[i];
                node[i]=node[i+1];
                node[i+1]=k;
            }
        }
    }
    /*]の表示*/
    for(i=0;i<5;i++){
        printf("\n\n%s   |",str[node[i]]);
        for(l=0;l<count[node[i]];l++){
            printf("]");
        }
    }
    printf("\n\nその他 |");
    for(l=0;l<other_k;l++){
        printf("]");
    }
    printf("\n\n           総文字数 %d  入力文字列数 %d  平均文字数 %d\n",total,retu_k,total/retu_k);
}




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:無限ループ 25371 kz3 2006/01/15 13:46:56
<子記事> Re:無限ループ 25372 επιστημη 2006/01/15 14:39:19
<子記事> Re:無限ループ 25373 iijima 2006/01/15 14:41:57
<子記事> Re:無限ループ 25374 επιστημη 2006/01/15 14:59:55


No.25371

Re:無限ループ
投稿者---kz3(2006/01/15 13:46:56)


> どなたかご教授お願いします。
とりあえず原因探る前に読みにくいです。
文字の種類の判定にis〜系の関数を使わないのは何故ですか?

if-elseとか画面内に収まらなくてチェックも難しいですよ。
自分がチェック難しくて出来ないのに他人のソースを読むのはもっと
難しいということを意識してください。

# と偉そうに言ってみました。


この投稿にコメントする

削除パスワード

No.25372

Re:無限ループ
投稿者---επιστημη(2006/01/15 14:39:19)


>//Eを入力するまで文字列を入力し、文字を種類別にわけるプログラムを
>つくりたいのですが、1回目に//Eと入力するとなぜか無限ループしてしまいます。どなたかご教授お願いします。

# そもそもこれ、Cじゃない。コンパイルエラーになる。

    int node[5]={0,1,2,3,4};
    double count[5];
...
    /*降順に並べ替える*/
    for(l=5;l>0;l--){
        for(i=0;i<l;i++){
            if(count[node[i]]<count[node[i+1]]){


l = 5 のとき、i は4までの値をとる。すると、
if(count[node[4]]<count[node[5]]){
となるが、node[5]は存在しない。ここでオカシクなる。




この投稿にコメントする

削除パスワード

No.25373

Re:無限ループ
投稿者---iijima(2006/01/15 14:41:57)


> 1回目に//Eと入力するとなぜか無限ループしてしまいます。

試してみよー。

#include <stdio.h>

int main( void )
{
    char retu[ 256 ];

    while( retu[0] != '/' && retu[1] != '/' && retu[2] != 'E' ){
        printf( "Input > " );
        gets( retu );
        if( retu[ 0 ] == '/' ){
            if( retu[ 1 ] == '/' ){
                if( retu[ 2 ] == 'E' ){
                    break;
                }
            }
        }
        printf( "continue\n" );
    }
    printf( "finish\n" );
    
    return 0;
}

実行結果:
Input > //E
finish

「無限ループ」は再現しませんねぇ。
while文の条件式はロジックがヘンなので、//E以外の入力でも繰り返さずに
終了しちゃいますが。



この投稿にコメントする

削除パスワード

No.25374

Re:無限ループ
投稿者---επιστημη(2006/01/15 14:59:55)


>//Eを入力するまで文字列を入力し、文字を種類別にわけるプログラムを
>つくりたいのですが、1回目に//Eと入力するとなぜか無限ループしてしまいます。どなたかご教授お願いします。

せめて

printf("単位 %% 0----1----2----3----4----5----6----7----8----9----+");

の前か後かくらいは報告すべし。

僕とこでは↑の後で、おかしなアクセスのために強制停止となりました。
やっちゃいかんことやっちゃったんだから無限ループだったり強制終了
だったり、最悪の場合それっぽい答がでちゃいます。

# …それにしてもこれほど"すさまじい"コードを読んだのは久しぶりだ。


この投稿にコメントする

削除パスワード

No.25378

Re:無限ループ
投稿者---RAPT(2006/01/15 15:39:31)


最初に //E と入力すると、total == 0 のまま。
で、
    kuhaku_k=(kuhaku_k/total)*100;

思いっきり、ゼロ除算してるよね。
すでに指摘されている配列の範囲外アクセスと、ゼロ除算が原因と思われます。

最初に未初期化の retu[] にアクセスしているのも問題ですね。
変数は必ず使用前に初期化するクセをつけましょう。

# なるべく元の構造に近い形で書き直したら76行になりました。
# 一番大きいブロックでも24行。



この投稿にコメントする

削除パスワード

No.25414

Re:無限ループ
投稿者---RiSK(2006/01/16 00:06:14)


># なるべく元の構造に近い形で書き直したら76行になりました。
># 一番大きいブロックでも24行。
リファクタリング(もどき)してみた。
#include<ctype.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define LENGTH(array) (sizeof(array)/sizeof((array)[0]))
int IsSpace(int c){return c==' ';}
int IsTab(int c){return c=='\t';}
typedef struct{
    char*name;
    int (*isThis)(int);
    int frequency;
}CharFamily;
int cmp(const void*e1,const void*e2){
    const CharFamily*const c1=e1;
    const CharFamily*const c2=e2;
    return c2->frequency-c1->frequency;
}
int main(void){
    CharFamily table[]={
        {"空白",IsSpace,0},
        {"英字",isalpha,0},
        {"数字",isdigit,0},
        {"記号",ispunct,0},
        {"タブ",IsTab,0},
    };
    int other_k=0,total=0,retu_k=0;
    //入力
    {
        char retu[256];
        while (gets(retu)&&strcmp(retu,"//E")!=0){
            int i;
            for(i=0;retu[i];++i){
                int j;
                for(j=0;j<LENGTH(table);++j){
                    if(table[j].isThis(retu[i])){
                        ++table[j].frequency;
                        break;
                    }
                }
                if(j==LENGTH(table))++other_k;
            }
            total+=i;
            ++retu_k;
        }
    }
    //ソート
    qsort(table,LENGTH(table),sizeof(table[0]),cmp);
    //出力
    if(total){
        int i;
        printf("単位 %% 0----1----2----3----4----5----6----7----8----9----+");
        for(i=0;i<LENGTH(table);i++){
            int j;
            printf("\n\n%s   |",table[i].name);
            for(j=0;j<(double)table[i].frequency/total*100/2;++j)printf("]");
        }
        printf("\n\nその他 |");
        for(i=0;i<other_k;i++)printf("]");
        printf("\n\n           総文字数 %d  入力文字列数 %d  平均文字数 %d\n",total,retu_k,total/retu_k);
    }
}



この投稿にコメントする

削除パスワード

No.25424

Re:無限ループ
投稿者---RAPT(2006/01/16 23:52:25)


>># なるべく元の構造に近い形で書き直したら76行になりました。
>># 一番大きいブロックでも24行。
>リファクタリング(もどき)してみた。

あえて構造体を使用しないで書いてみたんです。
これ以上変えると元の構造のカケラもなくなってしまう。

#include <stdio.h>
#include <string.h>
#include <ctype.h>

enum TYPE { kuhaku, eiji, suuji, kigou, tab, other };
char *FGETS(char *buff, size_t size)
{
    size_t length;
    fgets(buff, size, stdin);
    length = strlen(buff);
    // 末尾が改行文字なら除去
    if( buff[length-1] == '\n' ){
        buff[length-1] = '\0';
    }
    return buff;
}
int main(void)
{
    // 変数を宣言
    static const char *str[] = {"空白", "英字", "数字", "記号", "タブ", "その他"};
    char retu[256] = {0};
    int i, l, k, total = 0, retu_k = 0, node[] = {0,1,2,3,4,5}, count[6] = {0};

    // "//E"が入力されるまで文字列を入力して種類別に分ける
    for(;;){
        FGETS(retu, sizeof(retu));
        if(strcmp(retu, "//E") == 0){
            break;
        }
        // 文字列処理
        for(i = 0; retu[i]; ++i){
            if(retu[i] == ' '){            // 空白
                count[kuhaku]++;
            }else if(retu[i] == '\t'){     // タブ
                count[tab]++;
            }else if(isdigit(retu[i])){    // 数字
                count[suuji]++;
            }else if(isalpha(retu[i])){    // 英字
                count[eiji]++;
            }else if(isgraph(retu[i])){    // 記号
                count[kigou]++;
            }else{                         // その他
                count[other]++;
            }
        }
        total += i;
        retu_k++;
    }
    if( total == 0 ){
        printf("入力文字はありません.\n");
        return 1;
    }
    // 降順に並べ替える
    for(l = 4; l > 0; l--){
        for(i = 0; i < l; i++){
            if(count[node[i]] < count[node[i + 1]]){
                k = node[i];
                node[i] = node[i + 1];
                node[i + 1] = k;
            }
        }
    }

    // 結果出力
    printf("単位 %% 0----1----2----3----4----5----6----7----8----9----+");
    for(i = 0; i < 6; i++){
        printf("\n\n%-6s |", str[node[i]]);
        k = count[node[i]] / total * 100 / 2;
        for(l = 0; l < k; l++){
            printf("]");
        }
    }
    printf("\n\n           総文字数 %d  入力文字列数 %d  平均文字数 %d\n",total,retu_k,total/retu_k);
    return 0;
}



この投稿にコメントする

削除パスワード

No.25425

Re:無限ループ
投稿者---johan(2006/01/17 13:15:32)


>επιστημηさん
> int node[5]={0,1,2,3,4};
> double count[5];
>...
> /*降順に並べ替える*/
> for(l=5;l>0;l--){
> for(i=0;i<l;i++){
> if(count[node[i]]<count[node[i+1]]){

たしかにそうですね・・・反省します。

>kz3さん,iijimaさん
コーディングルールで許可された関数以外使用禁止なので・・・
書いておくべきでした。すいません。

みなさんありがとうございました。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧