トップページ⇒tech
1001コメント295KB

C言語なら俺に聞け(入門篇) Part 29

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん2008/06/01(日) 23:04:59
言語の入門者向け解説スレです。

教えて欲しいのではなく宿題を丸投げしたいならこちらへ。
 C/C++の宿題を片付けます 108代目
 http://pc11.2ch.net/test/read.cgi/tech/1211980711/

・C++言語はスレ違いです。
・分からない事をなるべく詳しく書いて下さい。
・ソースコードを晒すと答えやすくなるかもしれません。
・開発環境や動作環境も晒すと答えが早いかもしれません。
・質問者は最初にその質問をした時のレス番号を名前欄に書いて下さい。

前スレ
C言語なら俺に聞け(入門篇) Part 28
http://pc11.2ch.net/test/read.cgi/tech/1211198816/
過去スレ
http://makimo.to:8000/cgi-bin/search/search.cgi?q=%82b%8C%BE%8C%EA%82%C8%82%E7%89%B4%82%C9%95%B7%82%AF&andor=AND&sf=0&H=&view=table&D=tech&shw=5000
0153デフォルトの名無しさん2008/06/03(火) 20:34:08
>>151
それはすれ違い。
0154デフォルトの名無しさん2008/06/03(火) 20:35:30
>>152
ん?極端に言うと、stdio.h無しだと何もコンパイルできない、と言っている?
0155デフォルトの名無しさん2008/06/03(火) 20:38:24
>>154
逆。大抵の関数はエラーにならない。
0156デフォルトの名無しさん2008/06/03(火) 20:40:39
stdio.h
stdlib.h
まあ、この二つをググッて調べてみるといいよ。
どういう関数が使えるようになるかわかる
0157デフォルトの名無しさん2008/06/03(火) 20:45:52
>>155
やってみたら警告で済ませてくれた。
コンパイラやさしいな!
0158デフォルトの名無しさん2008/06/03(火) 20:46:41
何の警告が出たんだ?
0159デフォルトの名無しさん2008/06/03(火) 20:46:42
実は簡易的なHTMLの<この中の内容>を取り出す関数を作ろうと思っているのですが、
html->nextはHTMLの内容
#define BODY_SIZE 214
/* <>の切り出し */
html->body = (char *)malloc((size + 1) * sizeof(char));
if(html->body == NULL) goto END;

char *tmp;
while(*html->next++ != '<' && *html->next != '\0');
for(int len=0; html->next[len] != '\0'; len++){
if(html->next[len] == '>'){
html->body[len] = '\0';
break;}
if(len >= size - 1){
size += BODY_SIZE;
tmp = (char *)realloc(html->body,size);
if(tmp != NULL)
html->body = tmp;
else
goto END;}
html->body[len] = html->next[len];
}
HTMLの<>内を取得していくにあたり、動的なヒープ領域が足りなくなれば、
reallocを使って拡張し、また取得していく、という処理なのですが、
コードが複雑になり、非常に読み難いものになってしまい、
これをもっと簡潔には出来ないものでしょうか?
0160デフォルトの名無しさん2008/06/03(火) 20:48:10
>>158
printfは組み込み関数じゃないよって警告。
0161デフォルトの名無しさん2008/06/03(火) 20:50:11
>>159
それこそ線形リストがいいんじゃね?
0162デフォルトの名無しさん2008/06/03(火) 20:55:18
>>161
今は>>159のコードを簡潔にしたいです。
0163デフォルトの名無しさん2008/06/03(火) 20:55:53
あー、printfは使うのね
0164デフォルトの名無しさん2008/06/03(火) 21:02:09
>>163
てか、各種ライブラリを使わずに使える関数って何があるの?
read と write は知ってるんだけど
0165デフォルトの名無しさん2008/06/03(火) 21:09:33
>>159
そのソースの全体的な思想が分からないからなんともいえないんだけど
'<'から、次に見つかる'>'までがとにかく取れればいい、というのであれば
strposとかでキュッキュすればいいんじゃないかな。
<<>とか<hoge foo=">">とか無視していいならね。
0166デフォルトの名無しさん2008/06/03(火) 21:11:26
>を多用しているソースは苦手だなw
0167デフォルトの名無しさん2008/06/03(火) 21:14:40
環境はVS2005、Windowsなのですが、
strposをMSDNで調べましたが、見つかりません。
0168デフォルトの名無しさん2008/06/03(火) 21:18:11
>>167
アイヤー。ごめん。strposはphpですた。
Cだとstrstr?
0169デフォルトの名無しさん2008/06/03(火) 21:21:46
>>168
はい
0170デフォルトの名無しさん2008/06/03(火) 21:23:00
>>168
なるほど、
ではreallocの部分は簡潔になりますでしょうか?
0171デフォルトの名無しさん2008/06/03(火) 21:23:59
コピーの開始地点と終了地点がわかってから一気にmalloc()すれば
realloc()必要ないでしょ。

0172デフォルトの名無しさん2008/06/03(火) 21:31:27
>>171
strstrで二点間(<>)の出現場所を計算して
mallocする、ということでしょうか?
ではstrstrを使わない場合で
>>159のreallocの部分を簡潔にするためにはどうすればいいでしょうか?
0173デフォルトの名無しさん2008/06/03(火) 21:33:07
>>172
双方の出現場所が分かれば必要なサイズが分かるでしょ?
んでmalloc。
出現場所を調べる部分を簡潔にしたかったのでstrstr案を
出したわけでして、なぜ却下されたのだろう。ふしぎ!
0174デフォルトの名無しさん2008/06/03(火) 21:34:54
>>172
なぜstrstr()やらstrchr()を使わない?

サイズが事前にわからないのならrealloc()するのは仕方ない。それが嫌
ならコピー元のhtml->nextの残りサイズと同じサイズをmalloc()してお
くしかない。
Cではこのへんが限界だよ。C++ならもっとすっきり。

0175デフォルトの名無しさん2008/06/03(火) 21:37:47
>>174
strchr!思い出させてくれてありがとう。
indexofとかじゃなかったっけ?とかせっせと探してたんだw
0176デフォルトの名無しさん2008/06/03(火) 21:38:46
とゆーか構造体htmlの仕様がなんか怪しくね
0177デフォルトの名無しさん2008/06/03(火) 21:40:20
単にソースをすっきりさせるだけなら、size を html->body_size にして、
bool html_ensure_capacity(html_t *html, size_t new_size) {
void *tmp;
if (new_size < html->body_size-1) return true;
html->body_size += BODY_SIZE;
tmp = realloc(html->body, html->body_size);
if (tmp == NULL) return false;
html->body = tmp;
return true;
}
で、html_ensure_capacity(html, len);を呼ぶ。
0178デフォルトの名無しさん2008/06/03(火) 21:41:42
>>173
私が先程聞いたのは、strstrを使わない場合に
>>159のコードのreallocを簡潔にする方法は無いか、という事です。
却下ではなく、場合の話です。
新しく聞いている訳で、あなたが教えてくれたstrstrを使う案を退けたつもりはありません。
0179デフォルトの名無しさん2008/06/03(火) 21:42:52
簡潔という言葉が一体何を意味するのかがいまいち判然としないが、たぶん無い
0180デフォルトの名無しさん2008/06/03(火) 21:44:25
俺だったら内容コピーしたりせずに先頭を示すポインタと長さを表す変数で済ませるね
0181デフォルトの名無しさん2008/06/03(火) 21:46:22
あ、boolとか書いちゃったよ。てへ☆
0182デフォルトの名無しさん2008/06/03(火) 21:47:23
本当に簡潔に済ませたいならreallocなんか使わずに済む方法を考えること
見たところファイルを全部メモリにロードしてるようだし、
範囲確定してから戻ってmalloc & strncpyすればいいじゃない
0183デフォルトの名無しさん2008/06/03(火) 21:48:06
ではとりあえず
>>179
>>180
>>168
で試していきます。では
0184デフォルトの名無しさん2008/06/03(火) 21:48:40
>>178
あ、タグを見つける部分を簡潔にするのと
realloc周りを簡潔にすることのどちらかしか行わないのね。
両方すればいいのにな、と思っただけですスミマセンスミマセン。
0185デフォルトの名無しさん2008/06/03(火) 21:51:16
短い=簡潔
と思っているフシがあるのかな?
goto使ってたり、}の場所が、とか。

なんか、いろいろ違和感を感じるコードだなって思うわ。
とりあえず試行錯誤しながらがんばって成長してくだされ。
0186デフォルトの名無しさん2008/06/03(火) 21:53:51
構造体の仕様とか名前付けのセンスとかでいろいろ察してしまう
個別のタグ内容を割り当てる構造体にファイル全体へのポインタを含めて
そこからデータをコピーしてくるってのは正直気色悪い
0187デフォルトの名無しさん2008/06/03(火) 21:56:02
>>186
あなたが気持ち悪くならない方法を教えて下さい。
0188デフォルトの名無しさん2008/06/03(火) 21:57:02
まあタグ以外の内容がいらないなら一つ一つバラしてコピーした後に
ファイル全体のバッファを捨てることになるんだろうけど
ふつーテキストと合わせてなんかやるよね
0189デフォルトの名無しさん2008/06/03(火) 21:58:33
>187
ファイル全体のバッファ(のどこか)を指しているポインタは独立で用意して関数の引数で渡す
だけ
0190デフォルトの名無しさん2008/06/03(火) 21:58:47
>>186
まだ成長途中なんだなあって思えてほのぼのするよね。

自分が昔書いたコード見たら気持ち悪い、というか、
なんでこう書いちゃったのwwって思う場所がよく見つかる
0191デフォルトの名無しさん2008/06/03(火) 22:04:14
>>189
その様にした理由を教えて下さい。
0192デフォルトの名無しさん2008/06/03(火) 22:06:49
>191
気色悪いから
0193デフォルトの名無しさん2008/06/03(火) 22:10:36
>>192
論理的理由を聞いている訳ですが、
0194デフォルトの名無しさん2008/06/03(火) 22:11:23
>193
ない
0195デフォルトの名無しさん2008/06/03(火) 22:24:34
>>193
経験で分かるようになるよ。
「気持ち悪い」っていう感覚ってかなり重要だよ。
0196デフォルトの名無しさん2008/06/03(火) 22:45:12
C言語なんだけど

終了しますか?(Y/N)とか、終了(1)
継続(0)とか、入力をさせる。
んで入力値をscanfで取って判断してるんだけど、
scanfって直前のEnterとか認識不能なコードをストリームに
残しておくとのこと

おかげでバグだらけで困っているのだ…
他にキーボードからの入力を受け取れて不具合の無い関数は無いかな?
初歩くさくてすまんが…
0197デフォルトの名無しさん2008/06/03(火) 22:46:04
getcharとかそんなのなかったか?
0198デフォルトの名無しさん2008/06/03(火) 22:49:32
動作が定義されている環境ならば
fflush(stdin)
でいいかな。
0199デフォルトの名無しさん2008/06/03(火) 22:50:51
>>196
標準入力は全てfgets()で済む。
0200デフォルトの名無しさん2008/06/03(火) 22:51:43
早速ありがとう。けど使い方がよくわからん

今ケータイだから使用例なんかを挙げて
もらえるとすごく助かるかも@新入社員、今帰り

明日午前中にコードレビューだから帰ったら今日中に
仕上げなきゃ…
0201デフォルトの名無しさん2008/06/03(火) 22:54:30
printf("終了しますか?(Y/N)");
do {
c = getchar();
} while(c == 'y');


こんなんとかか?CUI系の関数使うの久々だから自信ない
0202デフォルトの名無しさん2008/06/03(火) 23:04:51
>>200
ケータイだから使用例をってどういう流れだ?
conio.hのgetchとかもいいんでないの?
0203デフォルトの名無しさん2008/06/03(火) 23:33:03
確定的にある入力を捕まえたいなら
プロンプトを表示する前にずべての文字を読み捨てておく
それが唯一の汎用な解
0204デフォルトの名無しさん2008/06/03(火) 23:44:12
しかし、すべての文字を読み捨てたのかまだ文字が残ってるのかを知る術はない
0205デフォルトの名無しさん2008/06/03(火) 23:50:46
バグが出るのはscanf()が悪いんじゃなくて使い方を理解してないのが悪い。
まあ、きちんとした使い方を理解させないで安易にscanf()で入力させる入門書や教師が一番悪いんだが。
0206デフォルトの名無しさん2008/06/03(火) 23:59:22
仕事を持ち帰らせる会社が悪い。新入社員なら特に。
0207デフォルトの名無しさん2008/06/04(水) 00:05:14
>>196だけど、様々ありがとう!
とりあえずgetcharを用いて行ってみるよ

文字として受けるから書式指定せずにいけるからね

これから実装だ…
0208デフォルトの名無しさん2008/06/04(水) 00:12:37
fseek(stdin,0,SEEK_END) って未定義だっけ?
0209デフォルトの名無しさん2008/06/04(水) 00:13:20
>>206
納期は明日の午前だからしょうがない
別に業務じゃないけど、納期に遅れる訳にはいかないことを
教えるためだと思う
0210デフォルトの名無しさん2008/06/04(水) 00:13:53
wikipediaには改行コードまで読み飛ばすって方法が載ってるけど、scanf()が行単位で動作してないんだから、
そんなことしてたら、エラーのときと正常動作のときと動きがちがってくるとか面倒なことがありそう。

stdinをfflush()したりファイルポインタを先頭にもどすとかってフラッシュのやりかたがあるけど、移植性ないし
リダイレクトとかされたら、どう動くかわからんし。

fgets()とかで行単位で読み込んで、sscanf()を使うなり自力で解釈するのがシンプルで紛れのないやりかた。
0211デフォルトの名無しさん2008/06/04(水) 00:23:35
>>209
業務では無いみたいだし、つか勝手に持って帰ってるだけだと思うけど
「納期に遅れる訳にはいかない」なら会社に泊まらせた方がまだいいなぁ
0212デフォルトの名無しさん2008/06/04(水) 00:25:34
C言語で、リスト構造によるスタックとキューから要素数を取得する方法を教えてください(><)
0213デフォルトの名無しさん2008/06/04(水) 00:27:34
要素数を別に記憶していないなら、先頭から始めて末尾まで順に辿ってその回数を数えるしかない
0214デフォルトの名無しさん2008/06/04(水) 01:13:26
>>211
泊まり込みなんてほんとにあんのかなあ?
寝ないと逆に集中出来ないんじゃね?
0215デフォルトの名無しさん2008/06/04(水) 01:16:47
3日ぐらい寝ずに仕事すれば覚醒する。
0216デフォルトの名無しさん2008/06/04(水) 01:18:40
寝ないと集中できない は真
泊り込みなんてほんとにある も真
0217デフォルトの名無しさん2008/06/04(水) 01:25:08
会社で寝ればすべて解決
0218デフォルトの名無しさん2008/06/04(水) 01:57:58
>>217
移動時間が節約できるんだよね。
あとは思い立った瞬間に仕事ができるんだよね。
夜2時とかにひらめくこともある。
0219デフォルトの名無しさん2008/06/04(水) 08:19:08
132のプログラムを118〜120のプログラムの中に入れたいんですけど、どこに入れたらいいですか?教えてください
0220デフォルトの名無しさん2008/06/04(水) 08:35:54
>>219
1〜9の範囲の整数を入力してくれなかったら困るなあってところにいれる
0221デフォルトの名無しさん2008/06/04(水) 19:35:54
>>218
無理をすると、あとでしっぺ返しがくる。
無理をしなければ納期に間に合わないようであれば、納期を延ばしてもらう。
これがいい。
そういう調整能力を身につけることも、プログラマーにとっては重要。
0222デフォルトの名無しさん2008/06/04(水) 21:51:52
>>221
それがヒューマンスキルってやつ?違う?
0223デフォルトの名無しさん2008/06/04(水) 21:54:28
何かの大賞とった川柳思い出した
無理をさせ 無理をするなと 無理を言い
だったけな?
0224デフォルトの名無しさん2008/06/04(水) 22:17:30
ベーシックのスレは何処でつか?
0225デフォルトの名無しさん2008/06/04(水) 22:18:08
(*p)++と*(p++)の違いがわかりません。
0226デフォルトの名無しさん2008/06/04(水) 22:20:36
(*p)++は、
int n = *p;
n++;
*p = n;


*(p++)は、
int* p2 = p + 1;

くらいだと思っとけ
0227デフォルトの名無しさん2008/06/04(水) 22:24:39
(*p)++;
は中身をインクリメント

*(p++) 及び *p++ は
はポインタをインクリメント
0228デフォルトの名無しさん2008/06/04(水) 22:46:52
文字列の配列ってどうやって作るんですか?
char str[5]
str[1] ="文字列1"
str[2] ="文字列2"
str[3] ="文字列3"
printf(%s\n,str[1]);
とやってもエラーになるんですが。
0229デフォルトの名無しさん2008/06/04(水) 22:48:06
それは文字列の配列じゃなくて
文字の配列だからね
どうしてもしたいなら二次元配列使う
0230デフォルトの名無しさん2008/06/04(水) 22:49:41
str[][8] = { "文字列1", "文字列2", "文字列3" }
0231デフォルトの名無しさん2008/06/04(水) 22:50:15
せめてこうだな
char* str[5]
まー、何がやりたい分からないから、これがベストとはとても言えないが
0232デフォルトの名無しさん2008/06/04(水) 23:10:12
>>228
厳密な意味での文字列の配列とは、文字の二次元配列の各行要素に文字列が入っているものを言う。

char strlist[3][8];

このように宣言したとき、strlist[0] 〜 strlist[2] は、それぞれが char str[8]; と宣言した str と等価となる。

しかし、上記の配列では、全ての行要素の配列の大きさが同じである必要がある。
つまり、それぞれの行に入る文字列の長さが違っても、最も長いものに合わせなければならず、メモリを浪費しがちである。

それが嫌な場合には、主に文字列へのポインタの配列が使われる。

char *strlist[3];
char str0[5], str1[8], str2[4];
strlist[0]=str0;
strlist[1]=str1;
strlist[2]=str2;

見ての通り、strlist[0] 〜 strlist[2] は charへのポインタであり、それぞれが対応する配列の先頭を指している。
ということはそれぞれを文字列として扱うことができ、しかもそれぞれに対応する配列の大きさを個別に設定できる。

ただし、実際にはこのように静的な配列を行要素に使うことはほとんどない。通常、malloc() で割り付けた動的な領域を使う。
malloc() の扱いには熟練を要するので、安易に手を出すのは控えること。

それと念のために言っておくが、Cの配列の添字は 0 から始まる。char str[5]; と宣言したら各要素は str[0] 〜 str[4] である。
0233デフォルトの名無しさん2008/06/04(水) 23:13:28
早い話、C言語に文字"列"型というものは存在しない
0234デフォルトの名無しさん2008/06/04(水) 23:17:15
>>233
それを言ってもまったく早くはならないと思うが
0235デフォルトの名無しさん2008/06/04(水) 23:40:55
早い話、文字列は使わないほうがいい

こうですか
0236デフォルトの名無しさん2008/06/04(水) 23:58:14
文字列をしっかり理解してないのに文字列の配列に手を出すな

だろ
0237デフォルトの名無しさん2008/06/05(木) 00:00:21
char str_array[N][]とchar *str_array[]じゃ、メモリ構成的にも全くの別物だしな
0238デフォルトの名無しさん2008/06/05(木) 00:26:26
いきなり好奇心からCを勉強するのはおバカさん
Cの前にPASCALを勉強することはお利口さん
ただし、ハマるとオ××に転落さん
そこにさえ気をつければ、本当はPASCALから入って欲しいのだが
Cの勉強は、PACALを初歩をマスターしてからという奴
Free-PASCAL/Turbo-Delphi/ラザルス(だったけ)
みたいなフリーな処理系がネットで入手可能だし、条件は
恵まれているのだが...
なにせ、良いPASCALの入門書は絶版に近いのがイタい。
やっぱり××ムの影響だろな。
0239デフォルトの名無しさん2008/06/05(木) 00:38:16
>>238
はいはいスレチスレチ
0240デフォルトの名無しさん2008/06/05(木) 00:58:13
Cは初心者にはかなりハードルが高いプログラミング言語だよ
0241デフォルトの名無しさん2008/06/05(木) 01:03:31
でもCから始めたよ
0242デフォルトの名無しさん2008/06/05(木) 01:11:20
>>240
書き方次第だよ

判定式の中に計算とかそういうのをやらなければどうってことはない。
0243デフォルトの名無しさん2008/06/05(木) 01:27:05
>>222
「約束を守る」という社会人の鉄則にすぎないのですが、なにか?
0244デフォルトの名無しさん2008/06/05(木) 01:27:45
基本はわかった
スキルあげるため、どういう本がいい?
0245デフォルトの名無しさん2008/06/05(木) 01:32:14
基本がわかったんなら自分で判断しろよw
0246デフォルトの名無しさん2008/06/05(木) 01:35:42
ある程度の大きさの配列を宣言するとき、256とか1024とかキリのいい数字で割り当てた方がいいですか?
0247デフォルトの名無しさん2008/06/05(木) 01:37:18
いや別に
0248デフォルトの名無しさん2008/06/05(木) 01:38:47
>>238-242
以前こんなコードみた
int split_tsv(char ****split,char *filename);

【仕様】
タブ区切り文字列のみで構成されるテキストファイルを読み込み
を文字列配列の配列に変換。 char ***(ポインタ変数)をsplitに参照渡しする。
(sはNULL不可) 戻り値は、行数.

こういったコード、ちょっとやればすぐに出てくるけど、これって初心者向けか?
初心者には絶対に弄らせたくないコードだよな。

構造型プログラミング言語の黎明期の時代に、多くのプログラミング言語(特に
PASCAL)が型の概念を導入したんだが、実プロジェクトに投入したら中間型が乱造
されてしまい名前空間管理が極度に困難になって開発が大停滞してしまった。
このことの反省を十分に取り入れたのがCなんだが、
型の概念を徹底的に学んでない初心者がCで上のようなコーディングをしなければな
らないんだとあせるのは、危険きわまりない。とは家、中間型(作業型)の問題も実
にやっかい。
この世界は、やはり余り普通の人が入ってくる世界じゃないよ。
0249デフォルトの名無しさん2008/06/05(木) 01:51:40
>>243
きめぇ
0250デフォルトの名無しさん2008/06/05(木) 02:12:04
**** はさすがに気色悪い
自分ならそこまでやるなら多段の構造体に仕込んじゃうかも…つーかC++(略
0251デフォルトの名無しさん2008/06/05(木) 02:19:31
char配列で表現した2進数を、頭から一文字ごとに比較したいのですが、
ソースAのような表記ではそもそも「error C2446: '==' : 'const char *' 型から 'int' 型への変換ができません。」が発生しコンパイルが通らず、
ソースBのような表記では、1文字ではなく、文字列全てを読んでしまって、if分岐に入ってくれません。
使用しているOSはWindowsXPHome, 使用しているコンパイラはVisual Studio 2005 Academic Editionです
どなたかご教授いただけないでしょうか

ソースA)
char tmp[8];
strcpy(&tmp[0], "11111000");
if (tmp[0] == "1")
{
...
}
if (tmp[1] == "1")
...
if (tmp[7] == "1")
{
...
}
0252デフォルトの名無しさん2008/06/05(木) 02:20:02
ソースB)
char tmp[8];
strcpy(&tmp[0], "11111000");
if (strcmp(&tmp[0], "1") == 0)
{
...
}
if (strcmp(&tmp[1], "1") == 0)
...
if (strcmp(&tmp[7], "1") == 0)
{
...
}
■ このスレッドは過去ログ倉庫に格納されています