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

C言語なら、ぬるぽに聞け! Part 〈53〉

■ このスレッドは過去ログ倉庫に格納されています
0001ぬるぽNGNG
まず問題を冷静に吟味してCの話か否かをはっきりさせてから質問しましょう。
質問する前には最低限Googleで検索を。

GUIなどの標準Cではできない事の質問は使用している開発環境のスレへGo!
ソース丸投げ、宿題、書籍 は専門の別スレがあるのでそこへさようなら。

コンパイラを探しているなら >>2-13 を。

上記を逸した場合の結果は激しく未定義だゴルァ!!

  ∧_∧
 ( ´∀`)< ぬるぽ

C FAQ 日本語訳
http://www.catnet.ne.jp/kouno/c_faq/c_faq.html
Cプログラマ必読 ・プログラミング言語C(通称 K&R)
http://www.amazon.co.jp/exec/obidos/ASIN/4320026926/
0159デフォルトの名無しさんNGNG
>>158
新しい型を定義したんだからint等と全く同じように使える。
0160151NGNG
ということは、ヘッダで、途中でいきなり
void func(Foo *f);
という関数宣言がでてきても、Cコンパイラから
未知の型:Foo
とかおこられないで、大丈夫なの?

C++なら
struct Foo;
void func(Foo *f);
とFooについて宣言する必要があるけど…
0161デフォルトの名無しさんNGNG
>>157
log()とか使って計算するしかないのでは?
0162デフォルトの名無しさんNGNG
>>155
sprintfでも使ってeの後だけ切り出す手もあるねぇ
0163デフォルトの名無しさんNGNG
>>160
試せばいいだろ!(怒)
0164制御屋さん見習中NGNG
>>161

ありがとう!
それは思いつきませんでした。
0165デフォルトの名無しさんNGNG
>>160
なんでその宣言の前にtypedefを書こうと思わないわけ?
0166151NGNG
>>160に補足
なんと聞けばいいのかな…

extern typedef Foo;
とかできるの?
つまり、型定義の宣言(?)みたいな
0167デフォルトの名無しさんNGNG
>>166

typedef struct{
int a;
char *b;
} Foo;

void func(Foo *);

こうだよこう。
0168151NGNG
>>167
これだと、Fooについての実体をかいてますよね?
つまり、Fooの実体を変えるた場合、コンパイルを
やり直す必要がある(コンパイル依存が生じる)。

必要なのは「(構造体への)ポインタ」だけなのに…

ポインタであることさえわかれば、構造体の実体が
どうなっていても、ポインタのサイズは一定値なので
不要なコンパイル依存性を除去できるのですが…
0169デフォルトの名無しさんNGNG
int (*fns[])(struct gmstat*) = {gmmain, gmrank, gment, };
を誰か説明してください。お願いします。わけわからんです。
0170デフォルトの名無しさんNGNG
>>151
とりあえずやってみろよ。
話はそれからだ。
0171デフォルトの名無しさんNGNG
>>161>>164
log()じゃなくてlog10()使えよ。
>>162
それだったらecvt()の方がよくないか?
0172151NGNG
>>168の補足
C++だとヘッダファイルは以下ですむ

#ifndef FOO_FUNC_H
#define FOO_FUNC_H

struct Foo;
void func(Foo *f);

#endif

Fooの実体については何も書いていないので
コンパイラ依存がない。

つまり、Fooが定義されているfoo.hが変更されても
foo_func.hは関与しない
0173デフォルトの名無しさんNGNG
>>168
ヘッダーファイルに関数の宣言を書くということは、他のファイルからもその関数を呼び出すんだろ?
0174デフォルトの名無しさんNGNG
>>168
ポインタのサイズは一定でも、「なにの」ポインタかはコンパイラが意識する必要があると思え。
0175デフォルトの名無しさんNGNG
一度stdio.hでも見てみればいいのに。
0176デフォルトの名無しさんNGNG
>>169
順番に型宣言でもして分解すればわかるだろう?
>int (*fns[])(struct gmstat*) = {gmmain, gmrank, gment, };
intを返す、struct gmstat*を唯一の引き数とする、関数へのポインタの配列fns、
それをgmmain, gmrank, gmentの3つの要素で初期化する。
つまり、
struct gmstat foo;
int rtn = fns[0](&foo);
と
int rtn = gmmain(&foo);
が等価なわけだな。
で、どうせなら
static int (*const fns[])(struct gmstat*) = {gmmain, gmrank, gment, };
にしておけ。
0177151NGNG
> ポインタのサイズは一定でも、「なにの」ポインタかはコンパイラが意識する必要があると思え。

それは、実際に必要な時まで、コンパイラが意識するタイミングを
送らせる(プログラマが調整させる)ことができますよね?

「Effective C++」の34項
「コンパイルするファイル間の依存性はできるだけ減らそう」
の話をしているつもりです…

これのC版のsttructはどうするのかなぁ、と。

やっぱりタグ名を使って冗長(?)に
extern struct Foo_tag;
void func(struct Foo_tag *f);
とでもするのでしょうか?
0178デフォルトの名無しさんNGNG
C++でできるならC++でやればいいのに。
0179151NGNG
> C++でできるならC++でやればいいのに。

それはそうなのですが…(^^;
Cでやるにはどうするのかな、と。

すみません、マルチポストっぽくって申し訳ないのですが
これからC++のスレでも質問させてもらいます…
0180デフォルトの名無しさんNGNG
>>168
要するに、構造体のメンバを隠蔽したいということか?
だったら、構造体を不完全型として宣言すればいい。
構造体へのポインタ「だけ」が必要な関数には、

typedef struct foo foo;

という宣言だけを見せて、メンバへのアクセスが必要な関数には、

struct foo { ... };

という宣言を見せればいい。
0181デフォルトの名無しさんNGNG
関数を使う側が構造体の中身や大きさを全く知る必用のない関数といえば・・・・fopenを初めとするファイル操作関数か?
それはそれで構造体の構造を変更しても、関数を使う側のファイルはコンパイルし直さなくても良いような気がする。
0182デフォルトの名無しさんNGNG
>>179
> これからC++のスレでも質問させてもらいます…

C++での方法を知っているのになぜ質問する。
0183デフォルトの名無しさんNGNG
>>151
冷やかしに来たのなら失せろ
0184デフォルトの名無しさんNGNG
内部を隠蔽したいならC++を使うのが正解だと思う。
>>180の言うようにCでもできるがダブルスタンダードになって
保守性が落ちるだけのような気がして気持ち悪い。
「C++でできることがCではどうなるか」疑問に思うのはいいが、
違う言語なのだから必ずしも同じように使わなくてもいいと思うのだが。
#名前空間の所為で、Cだとtypedef struct foo {int foo;} foo;なんてできるのだし。
0185sageNGNG
ぬるぽに相応しいスレになってきたな
0186151NGNG
えと、興味本位で聞いているわけでなく、
実際にCでかいていまして…
0187デフォルトの名無しさんNGNG
Cの構造体でプライベートメンバを書くにはどう書くの?




という質問が次は来るに 2,000ヌルポ
0188デフォルトの名無しさんNGNG
CでできることはC++でもできるんじゃないの?ならまだしも、C++でできるのならCでもできるんじゃないの?と思うのはおかしい。
0189デフォルトの名無しさんNGNG
コンパイルし直さなくてはならなくなるとまずいの?
コンパイル時間がもったいないとか?
0190189NGNG
>>168に対してね。
0191デフォルトの名無しさんNGNG
151からはJava厨の臭いがする
0192151NGNG
Javaはさわったことがないです…
やってみたいと思っているんだけど…

しいていうならC++厨です

C++スレで質問したのですが、CならCの流儀にしたがえ
とアドバイスをうけました。
ですので、タグ名をつかってみることにします
(typedefをせずに)

荒らす気はなかったのですが、みなさんに迷惑を
かけてしまいました。
どうもすみませんでした。
0193デフォルトの名無しさんNGNG
C++スレに答え出てるぞ。
がんがれ
0194デフォルトの名無しさんNGNG
C言語の型の概念について教えてください。
もしくは説明されてるサイト教えてください
0195デフォルトの名無しさんNGNG
>>1のリンク先くらい嫁
0196デフォルトの名無しさんNGNG
>>194
林の本でもいいから初心者本買えよ
http://www.google.com/search?num=50&hl=ja&lr=lang_ja&q=C%8c%be%8c%ea%82%cc%8c%5e+%8aT%94O
0197151NGNG
C++スレでも、スレ違いだとの指摘をうけました。
それで、CスレでもC++スレでも、質問を終わります

C++スレでの終わりの意見はここです
http://pc2.2ch.net/test/read.cgi/tech/1047560042/623

たくさんアドバイスをしてくださって
どうもありがとうございました
0198タマちゃんNGNG
#include "stdio.h"
main()
{
func1();
}

func1()
{
printf("a");
}

をコンパイルしようとすると、

5: Warning: function 'func1' undefine -- assumed to be int

って返ってきてしまいます。
どこが間違ってると思います?
0199デフォルトの名無しさんNGNG
>>198
解1)
#include "stdio.h"
func1()
{
printf("a");
}

main()
{
func1();
}

解2)
#include "stdio.h"
void func();
main()
{
func1();
}

void func1()
{
printf("a");
}
0200タマちゃんNGNG
>>199

神よ
ありがとう
0201199NGNG
解説するとCはコンパイル時に前方参照しない。

mainの中でfunc1が出てきたときにはコンパイラはfunc1のプロトタイプは知らない。
知らないから、ファイルを読み進んでその先にあるかもしれないfunc1の
プロトタイプを知ろうとはしない。これが前方参照をしないの意味だ。

で、プロトタイプがわからない関数にぶち当たったときコンパイラは
intを返す関数だと仮定して処理を進める。これはCの規約でもある。
コンパイラがだしてるwarningはそのことを言ってる。
そのwarningを意訳すると、
「funcなんてしらねえよボケ、intを返すと見なすからそのつもりでいろや」
と言ってる。

んで、解1の方は前もってfuncの定義をしておくもので、
解2はコンパイラにfuncのプロトタイプを与えるというものだ。
0202デフォルトの名無しさんNGNG
intとint long intの違いってなんですか??
0203デフォルトの名無しさんNGNG
sizeof(long int) >= sizeof(int)
intは処理系にとってもっとも自然な整数型。
同じサイズの処理系もあるし、違うサイズの処理系があってもよい。

たぶんおまいのさわれるコンパイラはサイズが同じなので違いはない
0204デフォルトの名無しさんNGNG
仮引数をポインタとして定義することによって、
実引数にも影響を及ぼすことができるサンプルプログラミングですが
本に書いてあるとおりにやって何度も確認してるのですが
どこが間違えてるか分かりません。おしえてください。

#include <stdio.h>

void swap(int *pX,int *pY);

int main(void)
{int num1=5;
int num2=10;
printf("変数num1の値は%dです。\n",num1);
printf("変数num2の値は%dです。\n",num2);
printf("変数num1とnum2の値を交換します。\n");

swap(num1,num2);
printf("変数num1の値は%dです。\n",num1);
printf("変数num2の値は%dです。\n",num2);
return 0;
}

void swap(int *pX,int *pY)
{int tmp;

tmp=*pX;
*pX=*pY;
*pY=tmp;}

0205デフォルトの名無しさんNGNG
>>204
>swap(num1,num2);

swap(&num1,&num2);
&がない。よく本見てみ
0206デフォルトの名無しさんNGNG
swap(&num1,&num2);
0207デフォルトの名無しさんNGNG
>>205>>206
ありがとうございます!!正常な数値がでました。
ところで何故こうなるのでしょうか??

void swap(int *px,int *py);で宣言するときに
*pxおよび*pyは数値ですよね?
で、呼び出すときは swap(&num1,&num2);
と &num1および&num2はアドレスですよね?
つまり、&num(アドレス)を*px(数値)に代入することなんてできるんでしょうか? 
0208デフォルトの名無しさんNGNG
int a=10;
int *ap;
ap=&a;
これをやってるのと同じ。
0209デフォルトの名無しさんNGNG
可変長配列を管理する構造体?

struct name {
  int namelen;
  char namestr[1];
};

ってのが,C FAQ に載っていますが,
この使用に関して危険性は無いのでしょうか?

素人目には,かなり恐い感じがするのですが.
namestr[xx] のアドレスが危険な領域である可能性は無いのでしょうか?
0210デフォルトの名無しさんNGNG
>>207
関数内でint *px; を宣言して
引数のアドレスがコピーされるようなもの。
0211デフォルトの名無しさんNGNG
>>209
超ある。
ってかnamelenを何に使うのか説明してくれ。
0212デフォルトの名無しさんNGNG
>>209
ていうか
mallocとかであらかじめメモリーを確保するから大丈夫
0213デフォルトの名無しさんNGNG
struct name *pname;
pname=malloc( sizeof(struct name) +9 );
としたら
pname->namestr[9] まで問題ない。しかしそれ以降は危険。
0214デフォルトの名無しさんNGNG
僕は、VisialC++6.0のコンパイラを使っています。
すごく初心者の友達がプログラムを覚えたいらしく、教えてあげることになり
ました。(僕もそんなに知識はありませんが)。使える言語が少ないのでC言語を
教えることにしました。ただ、友達はただがいいらしいのでそれを探したところ、
Borland等があるみたいですね。教えるために僕もBorland等をインストール
しようと思っているのですが、VC++が有るパソコンにそれを入れるとどうなりますか。
ぶつかって動作がおかしくなったりしませんか。教えてください。長文ですいません。
0215デフォルトの名無しさんNGNG
>>214
もうまんたい
0216デフォルトの名無しさんNGNG
自分で実験しろ! あと結果報告も書いてね。
0217209NGNG
>>211-213 わかりました.
この場合 namelen はプログラマが陽に管理することになるんですね?

pname=malloc( sizeof(struct name) +9 ); のとき
pname->namestr[9]              までOKなので,例えば
pname->namelen = 10;            と設定してやるとか.

struct name {
  int namelen;
  char * namestr;
};

とすれば
struct neme namae; のとき
namae.namestr = xx;
namae->namestr = (char*)malloc(xx);

と出来ますよね?こっちのほうがいいような.freeしにくいのか?
この構造体のメリットは配列長情報を格納できることなのでしょうか?
いまいちピンとこないのですが,有効な利用法などはあるのですか?
0218デフォルトの名無しさんNGNG
Win のビットマップファイルのフォーマットにこんな感じの構造体使ってなかったっけ。
0219デフォルトの名無しさんNGNG
http://www.catnet.ne.jp/kouno/c_faq/c2.html
209はCFAQでもダメだって書いてる。
どうやって
"配列namestrが複数の要素を持つように振る舞わせる"んだろ
char namestr[1];みたいな場合
namestr=ポインタ;
みたいな表現は許されないような気がした

217の方の使い方はいろいろあります。
最初にxxの大きさで割り当てた後
もっと大きいサイズが途中で必要になったりしたときとか長さが無いと困るし
そういうことをする関数を作った場合引数がごちゃごちゃしないとかかなあ
0220デフォルトの名無しさんNGNG
>A: この技巧は人気がある。ただしDennis Ritchieは「Cの実装への根拠 のない馴れ馴れしさ」と呼んだ。
>公式な解釈によると上の技巧は Cの 規格に厳密には準拠していないと考えられる。
>(この技法が正しいか どうかを取り巻く議論を尽くすことは、このFAQの守備範囲を越えて いる。)
>しかし世の中に知られている全てのコンパイラの実装で、こ の方法は移植性が高いようである
>(配列の境界を注意深くチェックす るコンパイラは警告を出すかもしれない)。
>別のやり方としては、可変長の要素の大きさを、小さく取るより、非 常に大きく取ることが考えられる。上の例でいえば、
>char namestr[MAXSIZE];
>ここでMAXSIZEは配列namestrに保存されうるどんな名前よりも大きい。 しかしながらこの技法も、規格の厳密な解釈によると許されないよう だ。

駄目とは書いてないような・・
0221220NGNG
>>219
今読み直したら厳密な解釈では駄目ってことか。 汚してスマン。
0222デフォルトの名無しさんNGNG
>>217
ファイルフォーマットに可変長データ部分がある場合
ヘッダを一気に読んでこういう構造体にあてはめると効率が良いよ。
コンパイラの特性に依存してるから、移植性はほとんどないけど。
0223デフォルトの名無しさんNGNG
>>221
しかし、C99 では認められている気配。
0224デフォルトの名無しさんNGNG
LSI-Cの試食版でないコンパイラを使っている人はどれくらいいるんだろう・・・
0225デフォルトの名無しさんNGNG
それくらい。
0226デフォルトの名無しさんNGNG
>>224
そういえば、>>9のコンパイラ一覧にLSI-Cの試食版は入ってないな。
俺も昔はお世話になったが、やはりintが2byteはもう過去の遺物だろう。
0227デフォルトの名無しさんNGNG
でも、LSI-Cの試食版使いやすいよな。
俺がC始めたときは環境変数とか全然分からなかったから、
自動でパス通してくれるのは本当にありがたかったよ。
0228デフォルトの名無しさんNGNG
>>198
#include "stdio.h"

ビクビクガタガタ

ところで、純粋にC言語の勉強をするだけなら、gcc(cygwin)がお勧め。
ネットにさえ繋がればインストールは難しくないし、無料。
ただし、グラフィック関連は難しいので、あくまでも「C言語だけ」の世界だが。
0229デフォルトの名無しさんNGNG
cygwinなんて歪なもん勧めんなよ。
0230デフォルトの名無しさんNGNG
まったくだ
0231デフォルトの名無しさんNGNG
純粋にC言語の勉強がしたいならcygwinに対応しているOSは糞
0232デフォルトの名無しさんNGNG
割と意味不明だな
0233デフォルトの名無しさんNGNG
cがchar nがint型として
c=n;とすれば良い所を可読性を良くする為、あえて
c=(char)n;としても遅くなったりしませんか(ループ内とかで)?
内部的な動作は良く知らないので教えてください。
0234デフォルトの名無しさんNGNG
>>233
とてつもなく遅くなる。禁じ手。
0235デフォルトの名無しさんNGNG
>>234
うほっ、そりゃまずいっす。 情報サンクス!
0236デフォルトの名無しさんNGNG
>>235
信じるな。
0237デフォルトの名無しさんNGNG
>>233
よく知らないけど
ハンガリアン表記すりゃあ、そんな必要無くなる罠。
0238デフォルトの名無しさんNGNG
>>233
> cがchar nがint型として
> c=n;とすれば良い所を可読性を良くする為、あえて
> c=(char)n;としても遅くなったりしませんか
処理系依存なのでアセンブラに落として同じコードになるか確かめろ。
0239デフォルトの名無しさんNGNG
まあたいていは、全く同じになるので遅くならない。
0240デフォルトの名無しさんNGNG
>>237 ハンガリー人キター
0241デフォルトの名無しさんNGNG
それだけなら、まあ変わらないだろうけど、int a, b; char c;
c=(char)(a+b);
c=(char)a+(char)b;
みたいなのだと、結果は同じでも速度は変わる。
0242モナ王NGNG
教えてください。
以下のようなプログラムを実行します。

int main()
{
int i, j, n_1, n_2;
double K[M][N];

n_1 = 4;
n_2 = 2;

printf(" n_1 =%d\n", n_1);
printf(" n_2 =%d\n", n_2);

func( A, B, P, G, n_1,n_2,K);

printf(" n_1 =%d\n", n_1);
printf(" n_2 =%d\n", n_2);

return EXIT_SUCCESS;
}


すると、n_1とn_2の値が、func()の後で どちらも0になります。
func()内部で、n_1、n_2は値を参照しているだけです。
(for文のループに使用)
何故変わるのか理解できません。

宜しくお願いします。
0243デフォルトの名無しさんNGNG
funcが分からん
これだけの情報で分かったら神

引数を値を代入するような用途に使うのはいかがなものかと
0244デフォルトの名無しさんNGNG
>>242
funcがスタック内容を壊してるから
0245デフォルトの名無しさんNGNG
> 引数を値を代入するような用途に使うのはいかがなものかと

正規の方法では、ポインタを使わない限り、それは意図しようが無い。
唯一 K がポインタ渡しになっていると思われるので、その扱いを間違えた func() の
バグだろう。
0246モナ王NGNG
>>244

>funcがスタック内容を壊してるから


これってどう言う意味ですか?

0247245NGNG
唯一でもないか・・・A, B, P, G の正体もわからん。
0248デフォルトの名無しさんNGNG
(´-`).。oO( func晒せばいいのに
0249モナ王NGNG
>>248
長いのですが、、、

int func( double a[N][N], double b[N][M], double p[L][N], double g[M][N],
int Ncol,int Nrow,double K[M][N])
{
int i,j,k;
double InvF[N][N],s,tmp[10][10];

for (Pole_Count = 0; Pole_Count < Ncol; Pole_Count ++){

if(p[1][Pole_Count] == 0){
if(Pole_RealCal( a, b, p, g, Ncol) == 0){
/* エラー処理 */
return 0;
}
}else{
if(Pole_ImgCal( a, b, p, g, Ncol) == 0){
/* エラー処理 */
return 0;
}
}
}

for (i = 0; i < N; i++)
for (j = 0; j < M; j++) K[i][j] = 0.0;

return 1;
}
0250モナ王NGNG

>>249 自己レスです。

バグが分かりました。
K[][]の初期化を誤っていました。
(NとMが逆)

for (i = 0; i < N; i++)
for (j = 0; j < M; j++) K[i][j] = 0.0;


大変失礼しました。
当方win98 +Cygwin +gcc -Wall でコンパイルしています。
この様なバグは、見つけるのが難しいと思います。
皆さんはどのようにして、発見しているのですか?
0251デフォルトの名無しさんNGNG
NだのMだのわかり辛い変数名は使わない
0252デフォルトの名無しさんNGNG
配列の範囲外まで弄ったのか。
>>244の予想どうりでワロタ
0253デフォルトの名無しさんNGNG
・二次元配列は使わない。
・ループ制御変数であっても一文字は避ける。
・ループの中身が一文だけであってもブロック化する。
・変数名を大文字で始めない。
・配列全体の初期化はmemset()を使う。
0254モナ王NGNG
>>251、253

ありがとうです。

行列を扱いたいので、2次元配列を使いたいです。

・ループ制御変数であっても一文字は避ける。
これは、どういう意味ですか? i、jはやめろということですか?

・ループの中身が一文だけであってもブロック化する。
{}を付けろということですね。

・変数名を大文字で始めない。
了解です。

・配列全体の初期化はmemset()を使う。
これは知りませんでした。情報ありがとうございます。
0255デフォルトの名無しさんNGNG
>>248
私ならば、こうすると言う話だが。

Cの二次元配列は一次元目を固定サイズにしないといけないので使い難いと思わないか?
だから二次元配列の代わりに一次元配列で済ませるのが習慣になっている。
例えば配列全体の平均値を返す関数にするならこんな感じだ。
double CalcAverage(double const *pArray, size_t width, size_t height)
{
 double sum = 0;
 int iy;
 for (iy = 0; iy < height; iy++) {
  int ix;
  for (ix = 0; ix < width; ix++) {
   sum += pArray[ix + iy * width];
  }
 }
 return sum / (width * height);
}
もしix + iy * widthが鬱陶しいなら、
#define pos(x, y, w) ((x) + (y) * (w))
とでもすればいい。そうすればpArray[pos(ix, iy, width)]と書ける。
0256デフォルトの名無しさんNGNG
最大値がsize_tでループ変数がintってのはどういうもんかとチャチャ入れ
0257デフォルトの名無しさんNGNG
あ、間違えた(w
コピペしたもんだからそういうことに。
指摘THX>>256
0258デフォルトの名無しさんNGNG
いったいどこが間違ってるんですか?

#include <stdio.h>
int main(int c, char **v)
{
c--;
if(c<0)return 0;
printf("%s ", v[c]);
return main(c, v);
}
■ このスレッドは過去ログ倉庫に格納されています