C言語なら俺に聞け! Part 123
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
2006/02/26(日) 13:58:25質問する前には最低限検索を。
GUIなどの標準Cではできない事の質問,ソース丸投げ、宿題、書籍 は専門の別スレッドがあるのでそこへさようなら。
エラー(警告含む)が起きたのならばエラーメッセージを書きましょう。
C FAQ 日本語訳
http://www.kouno.jp/home/c_faq/
Cプログラマ必読 ・プログラミング言語C(通称 K&R)
http://www.amazon.co.jp/exec/obidos/ASIN/4320026926/
他の過去ログはここに
http://nssearch.hp.infoseek.co.jp/clang/
前スレ
C言語なら俺に聞け! Part 122
http://pc8.2ch.net/test/read.cgi/tech/1139570025/
0655デフォルトの名無しさん
2006/03/10(金) 13:19:27最適化を切っているとか度合いを低く抑えているとか、
或いはお前が末尾再帰だと思い込んでいるだけで実際には末尾再帰でないという可能性もある。
0656・∀・)っ-●○◎- ◆Pu/ODYSSEY
2006/03/10(金) 13:43:19クィックソートあたりの実装を参考にするといいお。
こっちが再帰コール版
http://www.comp.dit.ie/rlawlor/Alg_DS/sorting/quickSort.c
再帰コールせず自前スタック管理とループで実現
http://www.d.umn.edu/~gshute/C/examples/quicksort.C.html
まぁ俺ならこんなコードにするかな。細かい部分は端折るが。
int depth = 0; //現在の階層; 0がトップ
LPNODE p = tree->head;
LPNODE *stack = (LPNODE*) malloc( sizeof (LPNODE) * 100 ) ;
for ( ;; ) {
if ( p->child ) { //ネストあり
開始タグ出力
stack[depth++] = p; //push, 下の階層に逝く
p = p->child;
}
出力とか
if ( !p->next ) { //同階層の終端に達した
p = stack[depth--]; //pop , 上の階層に戻る
終了タグ出力
if (depth == -1) break;
}
p = p->next; //同階層の次の要素を参照
}
free(stack);
0657デフォルトの名無しさん
2006/03/10(金) 13:48:49ちょうど団子先生がいるんで聞きたいんだが
末尾再帰とそのループ展開について解説してるいいサイト無い?
0658デフォルトの名無しさん
2006/03/10(金) 13:50:530659デフォルトの名無しさん
2006/03/10(金) 13:52:240660デフォルトの名無しさん
2006/03/10(金) 13:55:34その糞コードで'|'や' 'をどうやってはさむつもりだ?wwwww
馬鹿も休み休み言えよwwwww
0661・∀・)っ-●○◎- ◆Pu/ODYSSEY
2006/03/10(金) 13:58:59関数再帰コールベースなら簡単にできるとでも?馬鹿も休み休み言えよwwwwww
0662デフォルトの名無しさん
2006/03/10(金) 14:01:59俺団子じゃないけどいいかな。
http://d.hatena.ne.jp/yaneurao/20051008
http://d.hatena.ne.jp/yaneurao/20051025
0663デフォルトの名無しさん
2006/03/10(金) 14:03:25スタックオーバーフローだけを心配するなら2分割したうちの短い方だけを再帰にして、長い方をループにするのが簡単
末尾再帰が最適化されることを前提にするなら短い方を先に呼び出す
自前でスタックを用意するなら長い方を先に積む
これでスタックの深さは確実に O(log n)以下になる
0664デフォルトの名無しさん
2006/03/10(金) 14:04:42gccとかなら-Sでも指定してアセンブラ吐き出せば
末尾再帰になってるのが一目瞭然ですが( ´_ゝ`)
0666デフォルトの名無しさん
2006/03/10(金) 14:09:230667デフォルトの名無しさん
2006/03/10(金) 14:10:060668デフォルトの名無しさん
2006/03/10(金) 14:12:540669デフォルトの名無しさん
2006/03/10(金) 14:13:28ループでは簡単に出来ないことを認めたな?wwwww
0670デフォルトの名無しさん
2006/03/10(金) 14:14:25サンクス、ちょっと読んでくる
0671デフォルトの名無しさん
2006/03/10(金) 14:17:190672デフォルトの名無しさん
2006/03/10(金) 14:18:41関数の部分を見ると確かにループになってる。
gccって末尾再帰を最適化してくれるのか。知らんかった
__Z4factii:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl 12(%ebp), %eax
jmp L4
.p2align 4,,7
L7:
imull %edx, %eax
decl %edx
L4:
testl %edx, %edx
jne L7
popl %ebp
ret
0673デフォルトの名無しさん
2006/03/10(金) 14:19:40http://pc8.2ch.net/test/read.cgi/tech/1084676298/
0674・∀・)っ-●○◎- ◆Pu/ODYSSEY
2006/03/10(金) 14:29:25端折ってるだけですが。単純化したほうが解りやすいだろ?
とりあえず関数の再帰を使うと簡単に書けることを証明してくれ。
インデント量をいちいちグローバル変数やパラメータで渡す必要がある時点で論外なのだが。
出力も厳密にはキューに溜め込んで、遅延処理することを想定してる。
入れ子になってる要素数に応じて、複数行に分けたり分けなかったりしたいからね。
0675デフォルトの名無しさん
2006/03/10(金) 14:31:23目的と労力との天秤じゃね?
0676デフォルトの名無しさん
2006/03/10(金) 14:39:01>>656�dクス
そういえば>>621でも言ってるけど関数の引数を追加するとなんかまずいの?
0677デフォルトの名無しさん
2006/03/10(金) 14:43:060678デフォルトの名無しさん
2006/03/10(金) 14:43:130679・∀・)っ-○○◎- ◇Pu/ODYSSEY
2006/03/10(金) 14:52:100680・∀・)っ-●○◎- ◆Pu/ODYSSEY
2006/03/10(金) 14:53:29関数のプロトタイプが変わっちゃうでしょ。仕様変更に柔軟に対応しにくい。
何より、渡す引数が増えればその分だけ関数コールスタックの消費も増える。
>>675
XMLの解析なら、さすがにXercesやMSXML使うかな。
労力の少なさ重視ならCじゃなしにインタプリタ言語でも使いますわ。
実際のコンパイラやインタプリタのソース見れば再帰コールなんて、まず使ってませんわ。
バグの根源っす。
0681デフォルトの名無しさん
2006/03/10(金) 15:01:51俺はfindの実装すらも再帰以外では書けないヘタレだから無理だけどな
0682デフォルトの名無しさん
2006/03/10(金) 15:03:04??変わっちゃうってどういうこと?
そもそも再帰コールで書くつもりで始めたのなら追加も何もないんじゃないの?
0683デフォルトの名無しさん
2006/03/10(金) 15:08:40末尾再帰を最適化できないようなコンパイラを選定してる時点でダメ。
0684デフォルトの名無しさん
2006/03/10(金) 15:12:580685デフォルトの名無しさん
2006/03/10(金) 15:16:29ちゃちゃっと書いてテストするときって 先に再帰のほうを想像しないか?
いきなりループで思考するとかえってドツボ&バグの温床のような…
0686デフォルトの名無しさん
2006/03/10(金) 15:19:010687デフォルトの名無しさん
2006/03/10(金) 15:20:48void showTree(TREE* tree)
{
static char indent[INDENT_LENGTH] = "";
showTreeBody(tree->head, indent, 0, 0);
}
void showTreeBody(LPNODE current, char *indent, int above, int below)
{
static const char *nextIndent[] = {"  ","| "};
if(current) {
showTreeBody(current->child, strncat(indent, nextIndent[above], INDENT_LENGTH), 0, 1);
indent[strlen(indent)-2] = '\0';
printf("%s*-+(%d)\n", indent, current->data);
showTreeBody(current->next, strncat(indent, nextIndent[below], INDENT_LENGTH), 1, 0);
indent[strlen(indent)-2] = '\0';
}
}
0688デフォルトの名無しさん
2006/03/10(金) 15:20:48ループだと不自然だろ?
0689デフォルトの名無しさん
2006/03/10(金) 15:31:46ループで非再帰化したBNF記法のようなもの登場か!!!
…イラネ
0690デフォルトの名無しさん
2006/03/10(金) 15:39:030691・∀・)っ-●○◎- ◆Pu/ODYSSEY
2006/03/10(金) 15:56:29LRLRと自由文脈で英文法チェックルーチン(もどき)作るの講義でやったなぁ。懐かしい。
普通に自前スタックに退避で実現できるんじゃね?
Bisonあたりのソース参考にすればいい?ソースとってきてトレースして関数コールツリー
みてるけど、さて、再帰コールしてる箇所ってどこにあ(ry
findって要するにディレクトリツリーの中身全部展開して取得するだけでいいっしょ。
つい最近ディレクトリの中身を無駄なファイル除いてまとめてパックするプログラムとか
書かされたいたけど普通に再帰コールなしで出来たよ。いちおう参考までに。
>>682
共有しないといけないパラメータが、初期に想定してた分より変わるかもわからんね。
>>684
組み込みは無視ですか><
0692デフォルトの名無しさん
2006/03/10(金) 17:35:360693デフォルトの名無しさん
2006/03/10(金) 19:04:37組み込みでも再帰は使うよ
案件によっては禁止の場合もあるってだけ
使う場合のノウハウはちゃんとある
0694デフォルトの名無しさん
2006/03/10(金) 19:07:57{
char buf[256];
printf("Y/N?");
gets(buf);
if(strcmp(buf, "Y")==0) return 1;
if(strcmp(buf, "N")==0) return 0;
return confirm();
}
0695デフォルトの名無しさん
2006/03/10(金) 19:11:32やっぱ思考の過程をそのまま記述するのが自然でよいな。
その上で問題があるなら ループ⇔再帰 の置換を行えばいいし。
0696デフォルトの名無しさん
2006/03/10(金) 19:17:32うわー懐かし
新米の頃、似たようなこと書いて怒られたっけ(恥
0697デフォルトの名無しさん
2006/03/10(金) 20:52:21ヒットしたので試しに読んだらスレッドとタスクの違いが良く分からなくなってきますた。
そんなC言語を習得中の漏れに解説して頂けるもっさエロイ人キボン。
0698デフォルトの名無しさん
2006/03/10(金) 20:55:38スレ違い。
0699デフォルトの名無しさん
2006/03/10(金) 21:18:16prg2ch.libとか?
0700デフォルトの名無しさん
2006/03/10(金) 21:20:330701デフォルトの名無しさん
2006/03/10(金) 21:54:350702デフォルトの名無しさん
2006/03/10(金) 22:36:27何が間違っているのかご指摘を本当にお願いします。
#include <stdio.h>
void change(int *data);
int main(void)
{
int input;
puts("値の入力");
scanf("%d",&input);
change(&input);
printf("%d",input);
return 0;
}
void change(int *data)
{
int *temp;
while(*data / 2 != 0){
*temp++ = *data % 2;
*data = *data / 2;
}
}
0703デフォルトの名無しさん
2006/03/10(金) 22:38:45と言いますか、全ての数字において0が帰ってきます。助けて下さい。
コンパイラはgccです。
0704デフォルトの名無しさん
2006/03/10(金) 22:42:122進数で表示したいというのなら文字列にしないと
changeについては殆ど意味のない関数になってる
単にdataが0か1になるまで割り算していってるだけ
tempもまったく意味がない
0705デフォルトの名無しさん
2006/03/10(金) 22:42:270706デフォルトの名無しさん
2006/03/10(金) 22:44:49ほんとですか・・・文字列で書き直して再度聞きに来ます。ありがとうございます!!
>>705
それをぜひ教えて頂きたいです。
0707デフォルトの名無しさん
2006/03/10(金) 22:50:11こんな感じで良いよ。
void change(int *data)
{
int temp=0;
int i=1;
while(temp = temp+*data%2*i,*data / 2 != 0){
i*=10;
*data = *data / 2;
}
*data = temp;
}
0708デフォルトの名無しさん
2006/03/10(金) 22:56:04dataでかいとあふれるぜ
0709デフォルトの名無しさん
2006/03/10(金) 22:58:29うぁぁ・・・むずかしい・・・orz。
少しwhile式内を考えてみます。わざわざ解答書いてくださりありがとうございます!
0710デフォルトの名無しさん
2006/03/10(金) 22:59:20仕様ですw
>>709
>>707は急いで書いたから変になったけど、こう書いたほうが読みやすいかもしれない。
void change(int *data)
{
int temp=0,i=1;
while(*data != 0){
temp = temp + *data%2 * i;
*data = *data / 2;
i *= 10;
}
*data = temp;
}
0711デフォルトの名無しさん
2006/03/10(金) 23:04:39表示だけしたいのならこういう手もある
void print_bin(int n)
{
if(n < 0){
putchar('-');
print_bin(-n);
} else {
if(n/2 != 0)
print_bin(n/2);
printf("%d",n%2);
}
}
int main(void)
{
int n;
scanf("%d",&n);
print_bin(n);
putchar('\n');
return 0;
}
0712・∀・)っ-○●◎- ◆Pu/ODYSSEY
2006/03/10(金) 23:07:18C:\Documments and Settings\だんご 食べたい\My Documents\Visual Studio Projects\
ってパス名が含まれるからですか?><
0713デフォルトの名無しさん
2006/03/10(金) 23:11:16じゃないのか。
0714デフォルトの名無しさん
2006/03/10(金) 23:11:32-2147483648
0715デフォルトの名無しさん
2006/03/10(金) 23:13:17仕様で(ry
まじごめん
0716デフォルトの名無しさん
2006/03/10(金) 23:24:32式内の仕組みがやっと分かりました!!ありがとうございます!
これを参考にして16進数とかに挑戦してみます。
0717707
2006/03/10(金) 23:35:49特に変換処理をしなくても
printfで%xを指定したら自動的に16進数で表示してくれるよ
printf("%x",input);
0718デフォルトの名無しさん
2006/03/10(金) 23:36:03期待して書くのってやっぱり(仕事でやる場合)良くないこと
なんですかね? 組織のポリシー次第と言えばそれまでですが…
自分は再帰の回数が十分少ないと断言できる場合のみ
使っています。楽ですし。
0719デフォルトの名無しさん
2006/03/10(金) 23:42:52書式指定子の変更で16進に変換可能できるんですか!凄いですね(^ω^;)
ではいろいろネットで違う基本を学んできます。
0720・∀・)っ-○●◎- ◆Pu/ODYSSEY
2006/03/10(金) 23:43:290721デフォルトの名無しさん
2006/03/10(金) 23:45:39仕事なら、性能要件を満たす限りはなるべく分かりやすいコードがよい。
0722デフォルトの名無しさん
2006/03/10(金) 23:46:25○>>718
0723デフォルトの名無しさん
2006/03/10(金) 23:47:46最適化に限ったことじゃないが「保証されている」かどうかが仕事では超重要
0724デフォルトの名無しさん
2006/03/10(金) 23:49:37あるけど、これって末尾再帰最適化してくれるの?
0725・∀・)っ-○●◎- ◆Pu/ODYSSEY
2006/03/10(金) 23:51:000726デフォルトの名無しさん
2006/03/11(土) 00:31:06Cの規格でぜったい保障されてる範囲でしかコードを書かないってことになったら、
まともに実用のコードなんてかけないよ。
0727デフォルトの名無しさん
2006/03/11(土) 00:37:040728・∀・)っ-○●◎- ◆Pu/ODYSSEY
2006/03/11(土) 00:46:36ここは俺的に要ブックマーク
0729デフォルトの名無しさん
2006/03/11(土) 00:46:50おめー、厳密規格合致プログラムのことを言っているのか?
処理系定義だって立派に保証されている動作だし、
void hoge(int); だって、それを出荷しているベンダーが保証している場合もあるぞ?
自分の仕事の成果に対する責任範囲と「移植性」を近藤しとるんちゃうか?
金もらう時点でここで引っかかる奴はいないはずだが・・・
0730デフォルトの名無しさん
2006/03/11(土) 00:54:04この話の流れで、なんでそういう方向に行くのか分かりません。
0731デフォルトの名無しさん
2006/03/11(土) 01:15:140732デフォルトの名無しさん
2006/03/11(土) 08:21:190733デフォルトの名無しさん
2006/03/11(土) 10:57:05あまりにもトリッキーで環境依存なコードも問題あるが。
・・・とここのスレを見て感じました。
0734デフォルトの名無しさん
2006/03/11(土) 10:58:22意味もなくノーコストで得られる移植性を損なう奴もアホ。
0735デフォルトの名無しさん
2006/03/11(土) 11:02:36ないでしょうか? 以下は例です。
for (i=1;i<=10; i++) {
malloc( i*4096 );
}
0736デフォルトの名無しさん
2006/03/11(土) 11:05:25その例は別の意味で問題ある
0737デフォルトの名無しさん
2006/03/11(土) 11:15:10別の問題とは、どういう問題でしょうか?
0738デフォルトの名無しさん
2006/03/11(土) 11:15:510739デフォルトの名無しさん
2006/03/11(土) 11:17:180740デフォルトの名無しさん
2006/03/11(土) 11:37:240741デフォルトの名無しさん
2006/03/11(土) 11:40:06確かにそうですね。例の誤りですね。
0742デフォルトの名無しさん
2006/03/11(土) 11:45:14static char a[M+1][N+1];と宣言してあって
その後、a[i][j]++;とかすぐにインクリメントしたりしてるんですが
この宣言方法の場合、最初に0で初期化しなくても0が挿入されてるんですか?
0743デフォルトの名無しさん
2006/03/11(土) 11:46:290744デフォルトの名無しさん
2006/03/11(土) 11:52:01ありがとうございます
流れ見ていく限り、どうもすべてに0が入っているのを
前提とした感じだなぁっていうのはわかったんですが
static使ったことなくて、調べても次に呼び出されたとき
値が変化しない静的としか書かれてなかったんでわかりませんでした
0745デフォルトの名無しさん
2006/03/11(土) 20:28:13規格ではゼロ初期化ってことになってるけど
このルールには従っていない処理系が結構あるから
ちゃんと確認したほうがいいぞ
0746デフォルトの名無しさん
2006/03/11(土) 20:29:360747デフォルトの名無しさん
2006/03/11(土) 20:31:35そんな処理系無いだろ
少なくとも普通に手に入るであろう処理系ではの話だが
とゆうかstatic変数がゼロクリアされるのはC89で既に規格化されてるんだから
C89にすら準拠してないような糞処理系は窓からry
0748デフォルトの名無しさん
2006/03/11(土) 20:48:43結構あると言い切ってるんだから
まずは話を聞いてみようじゃないか。
0749デフォルトの名無しさん
2006/03/11(土) 21:06:39言っていいのはここまで
特に 747 みたいなのがいるところで言ったらシャレにならん
0750デフォルトの名無しさん
2006/03/11(土) 21:16:54何か厨臭いな
0751デフォルトの名無しさん
2006/03/11(土) 21:23:55標準Cなんて信用するなといってみたり
なかなか初心者に辛いスレだな。
0752デフォルトの名無しさん
2006/03/11(土) 21:35:30ANSIなどと書かれてるコンパイラならクリアされてるはずだわな
0753デフォルトの名無しさん
2006/03/11(土) 21:56:170754736
2006/03/11(土) 22:03:17736=743=754
■ このスレッドは過去ログ倉庫に格納されています