【掲示板ご利用上の注意】

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

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


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

No.22870

カンマ編集と再帰関数
投稿者---あきき(2005/08/29 00:05:45)


ある数字のカンマ編集のプログラムを用いて再帰関数の学習中です
次のプログラムで疑問点が生じました

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

void edit(unsigned long num);
void ditail_print(long num);

int main(void)
{
    long decimal;
    char buff[256];

    printf("整数を入力してください\n" "Input : ");
    scanf("%ld",&decimal);
    ditail_print(decimal);
    
    puts("終了します。");
    puts("いずれかのキーを押してください");
    getch();
        printf("\n");

    return 0;
}

void ditail_print(long num)
{
    if(num < 0)
    {
        putchar('-');
        edit(-num);
    }
    else
    {
        edit(num);
        putchar('\n');
    }
}

void edit(unsigned long num)
{
    static i=0;

    if( num >= 1000 )
    {
        edit(num/1000);
        printf("再帰%d回目(true) ,%03u\n", ++i, num%1000);
    }
    else
    {
        printf("再帰%d回目(false) %u\n", ++i, num);
    }
}



1上記のプログラムを”123456789”で起動するとします。
 その時、再帰1回目 123と表示されるのは分かります。ですが、2回目以降のeditの引数の値は何でしょうか?変化するnumの値が分かりません。
2そして、カンマ編集するに当たって、限界桁数があるような気がするのですが、例えば9の9桁は正常にカンマ編集しますが、10桁目からおかしくなります。負の数についてはその範囲は確認中です 


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:カンマ編集と再帰関数 22871 nop 2005/08/29 00:32:07
<子記事> Re:カンマ編集と再帰関数 22872 si 2005/08/29 01:01:59


No.22871

Re:カンマ編集と再帰関数
投稿者---nop(2005/08/29 00:32:07)


>1上記のプログラムを”123456789”で起動するとします。
> その時、再帰1回目 123と表示されるのは分かります。ですが、2回目以降のeditの引数の値は何でしょうか?変化するnumの値が分かりません。

引数の値も一緒に表示すれば判るのではないでしょうか?

>2そして、カンマ編集するに当たって、限界桁数があるような気がするのですが、例えば9の9桁は正常にカンマ編集しますが、10桁目からおかしくなります。負の数についてはその範囲は確認中です 

long、unsigned long で表現できる最大値を確認しましょう。
例えば、VC++などではunsigned longは4294967295が最大で、
9999999999は表現出来ません。


この投稿にコメントする

削除パスワード

No.22872

Re:カンマ編集と再帰関数
投稿者---si(2005/08/29 01:01:59)


>2回目以降のeditの引数の値は何でしょうか?変化するnumの値が分かりません。

再帰呼び出し部 edit(num/1000);

>10桁目からおかしくなります。負の数についてはその範囲は確認中です 

long 型の表現範囲を越えているのでしょう
void ditail_print(long num)関数で
printf("num = %ld\n",num); してみて下さい。
long が 32ビットなら、2の32乗(4294967296)種類の整数値しか表現できません。
intであれば、この半分ー1の数 2147483647 まで


この投稿にコメントする

削除パスワード

No.22877

Re:カンマ編集と再帰関数
投稿者---あきき(2005/08/29 10:39:54)


以下のように訂正します
>>2回目以降のeditの引数の値は何でしょうか?変化するnumの値が分かりません。そして、処理手順の仕方も。だれかディレールポイントの作成について教えてください。
>
>再帰呼び出し部 edit(num/1000);←ここの引数numの値とここからの処理です
>
>>10桁目からおかしくなります。負の数についてはその範囲は確認中です 
>
>long 型の表現範囲を越えているのでしょう
>void ditail_print(long num)関数で
>printf("num = %ld\n",num); してみて下さい。
>long が 32ビットなら、2の32乗(4294967296)種類の整数値しか表現できません。

次のようにプログラムを修正しましたが、どこかおかしいでしょうか?

void ditail_print(long num)
{
    if(num < 0)
    {
        putchar('-');
        edit(-num);
        printf("num = %ld\n",num); //表示値
    }
    else
    {
        edit(num);
        printf("num = %ld\n",num); //表示値
        putchar('\n');
    }
}

void edit(unsigned long num)
{
    static i=0;
    printf("num = %ld\n",num); //引数numの値

    if( num >= 1000 )
    {
        edit(num/1000);
        printf("再帰%d回目(true) ,%03u ", ++i, num%1000);
        printf("num = %ld\n",num); 
    }
    else
    {
        printf("再帰%d回目(false) %u ", ++i, num);
        printf("num = %ld\n",num); 
    }
}


>intであれば、この半分ー1の数 2147483647 まで



この投稿にコメントする

削除パスワード

No.22878

Re:カンマ編集と再帰関数
投稿者---si(2005/08/29 14:57:06)


掲示のプログラムは、単なる"再帰プログラム"であれば
問題無いのでしょうが、プログラムとしては X ですので
(多分、整数を3桁のカンマ区切りで表示するのでしょう)
改造版を掲示します。

#include <stdio.h>

void edit(unsigned long long num);
void ditail_print(long long num);

int main(void)
{
   long long decimal;
   char buff[256];

   printf("整数を入力してください\n" "Input : ");
      // 注:1 私の環境では'\n'がバッファに残るので変更
   fgets(buff,256,stdin);
   sscanf(buff,"%lld",&decimal);

   ditail_print(decimal);
   puts("終了します。");
   puts("return キーを押してください");
      // 注1
   getchar();
   printf("\n");

   return 0;
}

void ditail_print(long long num)
{
   printf("number = %lld\n",num);
   if(num < 0) {
      putchar('-');
      edit(-num);
   } else {
      edit(num);
    }
   putchar('\n');
}

void edit(unsigned long long num)
{     // まず、3桁以下の数値を得て表示する
   unsigned long long rem = num % 1000;
     // num が 4桁以上であれば、再帰、','を出力
   num = num / 1000;
   if ( num ) {
      edit(num);
      putchar(',');
   }
   printf("%u",rem);
}



この投稿にコメントする

削除パスワード

No.22883

Re:カンマ編集と再帰関数
投稿者---あきき(2005/08/29 20:16:59)


再帰呼び出し部 edit(num/1000);←ここの引数numの変化と第2回・3回目の再帰関数のトレースをしたいのですが。

結果表示が10桁目からおかしくなるのが、long型のな表現範囲を越えていないのなら(4294967296)までなら結果は表示できるという事ですか。
その範囲の単位が分からないのです。
>
それから、siさんの改造版を実行してみましたが、結果が予想を反するものでした。入力値は999999999です。



この投稿にコメントする

削除パスワード

No.22884

Re:カンマ編集と再帰関数
投稿者---まきじ(2005/08/29 20:37:46)


>それから、siさんの改造版を実行してみましたが、結果が予想を反するものでした。入力値は999999999です。

si さんのソースは、unsigned long long が使われているから、
最大値が 18446744073709551615 となります。(999999999も範囲内)
long long は C99 からサポートされています。


この投稿にコメントする

削除パスワード

No.22887

Re:カンマ編集と再帰関数
投稿者---あきき(2005/08/29 22:13:52)


>再帰呼び出し部 edit(num/1000);←ここの引数numの変化と第2回・3回目の再帰関数のトレースをしたいのですが。
>
例えば、123456789と入力したとします。最初の再帰関数で1回目(false)で123と表示されるのはトレースで分かりますが、再帰関数2回目以降でどうしてもトレースの結果、再帰関数n回目(false)となり、
printf(",%03u ",num%1000);
を実行できません。どのような理由でそのようなトレースになってしまうのか。
私としては、
1 2回目以降の再帰関数への引数の値がわからない。
2 1の引数がわかったとしても、次のif文の中で、num/1000がedit関数の引数であれば、いずれ1000をきる様な気がします。
3 結果、上記の様に、printf(",%03u ",num%1000);が実行できないのです

void ditail_print(long num)
{
    if(num < 0)
    {
        putchar('-');
        edit(-num);
        printf("num = %ld\n",num); //表示値
    }
    else
    {
        edit(num);
        printf("num = %ld\n",num); //表示値
        putchar('\n');
    }
}

void edit(unsigned long num)
{
    static i=0;
    printf("editの先頭:num = %ld\n",num); //引数numの値

    if( num >= 1000 )
    {
        edit(num/1000);
        printf("再帰%d回目(true) ,%03u ", ++i, num%1000);
        printf("num = %ld\n",num); 
    }
    else
    {
        printf("再帰%d回目(false) %u ", ++i, num);
        printf("num = %ld\n",num); 
    }
}



この投稿にコメントする

削除パスワード

No.22889

Re:カンマ編集と再帰関数
投稿者---まきじ(2005/08/29 22:33:01)


edit(123456789) を実行

123456789 > 1000 は true なので edit(123456) を実行(一回目のedit())

123456 > 1000 は true なので edit(123) を実行(ニ回目のedit())

123 > 1000 は false なので 123 を出力。(三回目のedit())
そして、呼び出し元に戻る。(edit(123456))

edit(123) が呼び出された時の num は 123456 なので
num % 1000 で 456 が出力。
そして、呼び出し元に戻る。(edit(123456789))

edit(123456) が呼び出された時の num は 123456789 なので
num % 1000 で 789 が出力。
そして、呼び出し元に戻る。(digit_print())


この投稿にコメントする

削除パスワード

No.22890

Re:カンマ編集と再帰関数
投稿者---あきき(2005/08/29 23:44:35)


図に描いて整理してみます


この投稿にコメントする

削除パスワード

No.22910

Re:カンマ編集と再帰関数
投稿者---あきき(2005/08/30 23:43:50)


まきじさんの処理手順をHCP風に書いてみた所、処理手順が分かりました。そして、仮引数と実引数を混乱していた事がわかりました。

http://www.geocities.jp/ky_webid/c/022.html

この混乱に全然気がつきませんでした。自関数から自関数を参照(再帰関数)する時のと、自関数から他関数を参照する時の引数が両方とも実引数なんですね。

そして、まったく基本的なことなんですが、
>long long は C99 からサポートされています。
で、C99とは新しいC言語の文法書みたいなものでしょうか?



この投稿にコメントする

削除パスワード

No.22911

Re:カンマ編集と再帰関数
投稿者---まきじ(2005/08/30 23:52:22)


>>long long は C99 からサポートされています。
>で、C99とは新しいC言語の文法書みたいなものでしょうか?

「文法書」という表現があってるか否かは判りませんが。
C言語の規格です。


この投稿にコメントする

削除パスワード

No.22912

Re:カンマ編集と再帰関数
投稿者---まきじ(2005/08/31 00:06:12)


>自関数から自関数を参照(再帰関数)する時のと、自関数から他関数を参照する時の引数が両方とも実引数なんですね。

何かよく判りませんが、、
実引数は、関数を呼び出す時の括弧内の式の事で
仮引数は関数定義の括弧内の値を得る変数の事です。

>123 > 1000 は false なので 123 を出力。(三回目のedit())
>そして、呼び出し元に戻る。(edit(123456))

戻ってきたら、n は 123456 ですが、123 となってたのでは?


この投稿にコメントする

削除パスワード

No.22916

Re:カンマ編集と再帰関数
投稿者---あきき(2005/08/31 16:36:47)


>>自関数から自関数を参照(再帰関数)する時のと、自関数から他関数を参照する時の引数が両方とも実引数なんですね。
>
>何かよく判りませんが、、
>実引数は、関数を呼び出す時の括弧内の式の事で
>仮引数は関数定義の括弧内の値を得る変数の事です。
>
>>123 > 1000 は false なので 123 を出力。(三回目のedit())
>>そして、呼び出し元に戻る。(edit(123456))
>
>戻ってきたら、n は 123456 ですが、123 となってたのでは?

http://www.geocities.jp/ky_webid/c/022.htmlでは、

○ローカル変数
これまでの例のように、関数内で宣言された変数は、その関数内でしか使えません。このような、関数内で宣言された変数をローカル変数(局所変数)といいます。関数の仮引数もローカル変数です。

と書いています。
>>123 > 1000 は false なので 123 を出力。(三回目のedit())
の後、
>戻ってきて、同関数editへの引数n は 123456 となっていなければなりませんが、それをローカル変数と勘違いしてしまい、呼び出し元はedit(123456)となるはずなのに、なぜか呼び出し元がedit(123)になってしまったというわけです。
edit(123456789)から以降、123を出力した後の呼び出し元の引数がすべて123になってしまっていたのが、トレースミスの原因です。


この投稿にコメントする

削除パスワード

No.22917

Re:カンマ編集と再帰関数
投稿者---まきじ(2005/08/31 18:07:23)


>>戻ってきて、同関数editへの引数n は 123456 となっていなければなりませんが、それをローカル変数と勘違いしてしまい

n はローカル変数ですが?

123456789 が渡された時の、再帰関数を展開(?)すると
下記の様になります。

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

void edit1(unsigned long num);
void edit2(unsigned long num);
void edit3(unsigned long num);

int main(void){

    unsigned long n = 123456789;

    edit1(n);
    putchar('\n');
    
    return 0;
}

void edit1(unsigned long n){

    edit2(n/1000);
    printf(",%03u", n%1000);
}

void edit2(unsigned long n){

    edit3(n/1000);
    printf(",%03u", n%1000);
    
}

void edit3(unsigned long n){

    printf("%u", n);
    
}

edit1 edit2 edit3 の、n はローカル変数なので別オブジェクトです。


この投稿にコメントする

削除パスワード

No.22923

Re:カンマ編集と再帰関数
投稿者---あきき(2005/08/31 20:53:44)


>>>戻ってきて、同関数editへの引数n は 123456 となっていなければなりませんが、それをローカル変数と勘違いしてしまい
>
>n はローカル変数ですが?
>
まきじさんに誤解を招く表現をしてしまいました。

>>>戻ってきて、同関数editへの引数n は 123456 となっていなければなりませんが、それをローカル変数

このローカル変数のところですが、別々のオブジェクトであるにもかかわらず、呼び出し先edit()のローカル変数値を呼び出し元edit()のローカル変数値として使用しているとしてトレースしていた事です。

まさに、まきじさんが示してくれたプログラムが、私がHCP風で理解した内容をプログラム化したものです。


この投稿にコメントする

削除パスワード

No.22891

Re:カンマ編集と再帰関数
投稿者---くまさん(2005/08/30 09:07:47)


>例えば、123456789と入力したとします。最初の再帰関数で1回目(false)で123と表示されるのはトレースで分かりますが、再帰関数2回目以降でどうしてもトレースの結果、再帰関数n回目(false)となり、
>printf(",%03u ",num%1000);
>を実行できません。どのような理由でそのようなトレースになってしまうのか。

再帰の数(深さ)を数える方法が間違っているからです。
123と表示されるのは、再帰一回目ではありません。


この投稿にコメントする

削除パスワード

No.22880

Re:カンマ編集と再帰関数
投稿者---まきじ(2005/08/29 18:23:38)



>edit(-num);
>void edit(unsigned long num)

負数の時に、負数で渡して良いのですか?
unsigned で受け取ってるので、-1 だったら、
最大値(4294967295)が三桁区切りになりますが?
-123 だったら、4294967173 が三桁区切りになります。
絶対値を渡せば、-12345 なら -12,345 と表示される様に出来ます。


この投稿にコメントする

削除パスワード

No.22881

Re:カンマ編集と再帰関数
投稿者---REE(2005/08/29 18:55:17)


>
>>edit(-num);
>>void edit(unsigned long num)
>
>負数の時に、負数で渡して良いのですか?
>unsigned で受け取ってるので、-1 だったら、
>最大値(4294967295)が三桁区切りになりますが?
>-123 だったら、4294967173 が三桁区切りになります。
>絶対値を渡せば、-12345 なら -12,345 と表示される様に出来ます。

負数の時にマイナスをつけているので、絶対値になると思われますが・・



この投稿にコメントする

削除パスワード

No.22882

Re:カンマ編集と再帰関数
投稿者---まきじ(2005/08/29 19:24:57)


>負数の時にマイナスをつけているので、絶対値になると思われますが・・

本当ですね・・・
- を付けて絶対値とは、判りづらい。


この投稿にコメントする

削除パスワード

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