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

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

■ このスレッドは過去ログ倉庫に格納されています
0001処理系定義の名無しさん2008/07/09(水) 11:00:48
言語の入門者向け解説スレです。

教えて欲しいのではなく宿題を丸投げしたいだけなら宿題スレへ行ってください。
 C/C++の宿題を片付けます 110代目
 http://pc11.2ch.net/test/read.cgi/tech/1213796455/

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

前スレ
C言語なら俺に聞け(入門篇) Part 31
http://pc11.2ch.net/test/read.cgi/tech/1214569903/
過去スレ
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
0232デフォルトの名無しさん2008/07/12(土) 02:00:32
>>231
ここ
http://pc11.2ch.net/test/read.cgi/tech/1215348804/
0233デフォルトの名無しさん2008/07/12(土) 02:01:47
>>232
すみません。ありがとうございます
0234デフォルトの名無しさん2008/07/12(土) 02:19:41
>>232
そこちゃうやろ
0235デフォルトの名無しさん2008/07/12(土) 15:20:44
int A;

void func(void)
{
  int B;

  for (10000000回繰り返し) A = 9999;
  for (10000000回繰り返し) B = 9999;
}

変数AとBでアクセス速度に違いがあるかどうか教えてください。
0236デフォルトの名無しさん2008/07/12(土) 15:28:45
>>235
システムによって違うので、実際に測定しないとわからない。
↑というのが前提で。

最適化がまったくなかったら、グローバル変数のほうが速い場合がおおいような気がするけど、
いまどきローカル変数をレジスタに割り当てるとか当たり前だからBのほうが速いかもしれない。

0237デフォルトの名無しさん2008/07/12(土) 15:49:15
>>236
今時の最適化は、ループ自体が無くなる、は置いといて。
グローバルも、最適化ではレジスタ割り当ても有る。
優先順位としてはBの方が高いと思うけどね。

ではレジスター割り当てが出来ない場合は、Aがじか引き
Bはスタックエリアのインデックス引きでBが遅いかもしれない。

プログラムのアセンブルリストを見るのが一番速い
0238デフォルトの名無しさん2008/07/12(土) 16:09:00
インデックスレジスタでメモリアクセスのほうが速いCPUもあるな
0239デフォルトの名無しさん2008/07/12(土) 16:10:02
アセンブラみるより計測するほうが早いよ。
02402352008/07/12(土) 16:13:02
>>236 なるほど。自分の環境で計ると、

//void msgbox(char *string, char *title = "msgbox") { MessageBox(NULL, string, title, NULL); }

LARGE_INTEGER Frequency;
QueryPerformanceFrequency(&Frequency);

LARGE_INTEGER pcBef, pcAft;
LONGLONG ll1, ll2;

QueryPerformanceCounter(&pcBef);
fori (1000000) A = 9999;
QueryPerformanceCounter(&pcAft);
ll1 = pcAft.QuadPart - pcBef.QuadPart;

QueryPerformanceCounter(&pcBef);
fori (1000000) B = 9999;
QueryPerformanceCounter(&pcAft);
ll2 = pcAft.QuadPart - pcBef.QuadPart;

sprintf(g_, "%f", (double)ll1 / (double)Frequency.QuadPart);
msgbox(g_);
sprintf(g_, "%f", (double)ll2 / (double)Frequency.QuadPart);
msgbox(g_);


測定の仕方ってこれであってます?
両方ともかかる時間は0.0024秒付近でした。
最適化ありだとほとんど変わらないぽいですね。
02412352008/07/12(土) 16:43:21
↑すみませんA=9999の部分を削っても0.024秒でした…
代入による負荷は限りなく低くて無視できるようですね…
0242デフォルトの名無しさん2008/07/12(土) 16:43:29
>>240
大体の目安にはなるかもしれないけどソース埋め込みだとレジスタに置かれてたのがスタックに置かれたりして厳密な測定値は得られない
デバッガにブレークポイントからブレークポイントまでの時間を測る機能はないの?
0243デフォルトの名無しさん2008/07/12(土) 16:47:33
え、そんな機能あるんですか?
VC2008だけどあるかなぁ・・・
0244デフォルトの名無しさん2008/07/12(土) 17:53:09
CL /FAsc オプションでアセンブリリストださないとなんとも。
意味のないループは最適化されやすい。
0245デフォルトの名無しさん2008/07/12(土) 18:02:46
最適化なしだと違いはこれだけ命令コード長が3バイト異なるがクロックは同じ。
命令の並列化とかメモリキャッシュの具合で差が出るかもしれない。

c7 05 00 00 00 00 0f 27 00 00
mov DWORD PTR ?A@@3HA, 9999 ; A, 0000270fH

c7 45 fc 0f 27 00 00
mov DWORD PTR _B$[ebp], 9999 ; 0000270fH
0246デフォルトの名無しさん2008/07/12(土) 18:05:49
最適化ありの場合は既に意味のないループも代入も消えてなくなってしまった。
; 7    :   for (int i = 0; i <10000000; i++) A = 9999; 
mov  DWORD PTR ?A@@3HA, 9999    ; A, 0000270fH
; 8    :   for (int i = 0; i <10000000; i++) B = 9999; 
; 9    : } 
ret  0
0247デフォルトの名無しさん2008/07/12(土) 18:20:46
基本はCで、C++の最低限の機能をつかうのがいいとは言うけど、具体的にC++のどこが使えると言えるの?
0248デフォルトの名無しさん2008/07/12(土) 18:23:40
STLとか
0249デフォルトの名無しさん2008/07/12(土) 18:33:36
>>243
ごめん、242は組み込みおじさんなんで自分の感覚で書いてしまった
MSDNのヘルプ見たけどVCではコード埋め込むのが一般的なのかな?
プロファイラが別途必要なのか、VCは疎いのでわからない
0250デフォルトの名無しさん2008/07/12(土) 18:46:15
適当なとこにint 3でも埋め込んどけばいいんじゃね
0251デフォルトの名無しさん2008/07/12(土) 18:48:16
typedef struct STRUCT_IMAGE{
int width, height;
int depth;
void* pixels;
} ImageData;

という構造体の宣言があってこの後のプログラムで
ImageData が型の名前として使われているようなんですがどういうことですか?
型として使うなら STRUCT_IMAGE だと思うんですが。
0252デフォルトの名無しさん2008/07/12(土) 18:58:46
struct STRUCT_IMAGE img;

って書くのめんどくさいじゃん?
0253デフォルトの名無しさん2008/07/12(土) 18:58:48
>>251
typedefしてるじゃん。
0254デフォルトの名無しさん2008/07/12(土) 19:07:44
>>252
>>253
理解しました。
0255デフォルトの名無しさん2008/07/12(土) 20:01:40
>>235
volatileつけてみたら変わるかな?
0256デフォルトの名無しさん2008/07/12(土) 20:10:37
ちょっと稚拙な質問かもしれませんが行き詰まったのでお願いします。

void main(){
int i;
int a[10];

for(i=0;i<10;i++){
scanf("%d",&a[i]);
if(入力側で改行があったら) break;
}
}

scanfで、次の要素に移るときは基本的にスペース、もし改行があったらそこでループを抜けるプログラムを書きたいのですが、
breakの条件文がわかりません・・・。
もし、適当な条件文があるなら教えていただけないでしょうか。
0257デフォルトの名無しさん2008/07/12(土) 20:15:36
a[i] == '\n'
0258デフォルトの名無しさん2008/07/12(土) 20:20:30
%dで改行を拾えたっけ?
0259デフォルトの名無しさん2008/07/12(土) 20:39:28
素早い回答ありがとうございます。
ん〜今やってみましたが、改行してもscanfが終了しませんでした…
俺がscanfの仕様をよくわかってないのもあるかもしれません。
ちょっと>>256のだと語弊があることを懸念して、
「ループを利用して配列に数字を入力中、改行するとすぐさまそこで文字入力を終了する」
ということです。
…ひょっとするととんだ見当違いなプログラムを書いてしまったかも…

0260デフォルトの名無しさん2008/07/12(土) 21:22:21
何も入力せずにEnter押したら終了、みたいなのはscanfじゃ無理だと思うけど。
0261デフォルトの名無しさん2008/07/12(土) 21:35:57
終了するときは数値以外の入力をしてもらうって仕様にすれば、scanf()のリターン値をチェックすれば対応できるけど。
0262デフォルトの名無しさん2008/07/12(土) 21:40:30
なるほど、やはりエンターでは難しいですか。
わかりました。終わるときは何か他の文字を入力してもらうことにします。
ありがとうございました!
0263デフォルトの名無しさん2008/07/12(土) 22:48:11
c = fgetc(fp) でcに代入するのはfpのファイルのどこのバイトですか?
0264デフォルトの名無しさん2008/07/12(土) 22:50:46
>>263
オープンした直後なら最初のバイト。
二回目の実行なら二つ目のバイト。
0265デフォルトの名無しさん2008/07/12(土) 22:51:29
>>263
一回目は先頭
二回目は2バイト目
三回目は3バイト目
・・・
0266デフォルトの名無しさん2008/07/12(土) 22:58:25
現在地と言ったほうがいいのでは
0267デフォルトの名無しさん2008/07/12(土) 23:09:44
>>264
>>265
>>266

fgetc()に、1回呼び出されると現在地を1バイト移動するような機能があるんですか?
0268デフォルトの名無しさん2008/07/12(土) 23:12:14
1バイト取得して、1バイト進める
0269デフォルトの名無しさん2008/07/12(土) 23:20:53
>>268
分かりました。
ありがとうございました。
0270デフォルトの名無しさん2008/07/12(土) 23:50:05
すごく初歩的な内容ですがわからないことがあるんです

char initial[15];
char name[15];
printf("苗字を記入\n");
scanf("%s",&initial);
printf("名前を記入\n");
scanf("%s",&name);

で、苗字と名前を記入するプログラムの練習をしてるのですが
このプログラムだと苗字、名前15文字までしか入れることができません。
で、if else をつかって16文字以上入力した場合には
「名前が長すぎる」とprintfで持ってきたいのですが、どうしてもできません。
なにかヒントみたいなものでも良いのでどなたか助言いただけないでしょうか?
0271デフォルトの名無しさん2008/07/12(土) 23:51:30
strlen関数で文字数を取得するとか
0272デフォルトの名無しさん2008/07/12(土) 23:52:33
>>270
scanfのかわりにfgetsを使う
0273デフォルトの名無しさん2008/07/12(土) 23:55:10
char initial[100];
char name[100];
while(true)
{
printf("苗字を記入\n");
scanf("%s",&initial);
if(strlen(initial)>0 && strlen(initial)<15) break;
printf("入力が長すぎます\n");
}
while(true)
{
printf("名前を記入\n");
scanf("%s",&name);
if(strlen(name)>0 && strlen(name)<15) break;
printf("入力が長すぎます\n");
}
0274デフォルトの名無しさん2008/07/12(土) 23:59:09
>>271-273
ヒントありがとうです
さっそく違う方法でやってみるです。
0275デフォルトの名無しさん2008/07/13(日) 00:00:10
しょうもない質問ですみません。

while(0) {
  printf("*");
}

このプログラムを実行したとき*は幾つ表示されるかが分かりません
実行してみたんですがエラーが出てしまいます orz
0276デフォルトの名無しさん2008/07/13(日) 00:01:25
エラー????
何も表示されないだけかな
0277デフォルトの名無しさん2008/07/13(日) 00:09:32
>>276
ありがとうございますm(__)m
エラーが出ないように何回かいろんなところいじってみますorz
0278デフォルトの名無しさん2008/07/13(日) 00:15:31
ソース上げれば添削するよ
0279デフォルトの名無しさん2008/07/13(日) 00:16:37
×scanf("%s",&initial);
○scanf("%s",initial);
0280デフォルトの名無しさん2008/07/13(日) 00:18:39
>>279
それはどっちでもいいんじゃね?
0281デフォルトの名無しさん2008/07/13(日) 00:26:12
initialと&initialと&initial[0]は同じポインタになるな
0282デフォルトの名無しさん2008/07/13(日) 00:27:10
>>279-280
今、試行繰り返してますが
どちらでも動くみたいです。

>>273のおかげでなんとかエラーなしで動くようになったので
これからプログラムの流れの解読開始します
0283デフォルトの名無しさん2008/07/13(日) 00:29:40
けどscanf("%s",&initial);って書かれると
分かってるのか?って思う
0284デフォルトの名無しさん2008/07/13(日) 00:34:32
>>283
あんまりきれいではないよね
0285デフォルトの名無しさん2008/07/13(日) 00:50:12
>>280-281
ならない。
配列に&演算子を作用させたときに得られるポインタは配列へのポインタであって、
配列の先頭要素へのポインタではない。

memset() などでは、配列の先頭要素へのポインタを与えても、配列へのポインタを与えても、正当に動く。
なぜなら memset() の引数が void * と定義されているために、コンパイラが暗黙に適切な型変換を行うからである。

一方、可変個数の引数を取る printf() や scanf() では、そのような暗黙の変換は行われない。
scanf() で %s を指定した場合に与えるポインタは char へのポインタでなければならない。
ポインタのサイズや内部表現が同じ処理系においては、配列へのポインタを与えても
(渡される値が、型は異なっても実際には同じバイナリ列であるために)たまたま動く。
しかしそれは規格が保証した動作ではない。

0286デフォルトの名無しさん2008/07/13(日) 00:56:11
ついでに考えられることとして、文字列を指させているポインタを配列だと勘違いして
(あるいはつい同一視してしまって)&演算子をつけて printf() や scanf() に渡してしまうことがある。
これはどんなマシンであっても、たぶん動かない。
0287デフォルトの名無しさん2008/07/13(日) 01:05:39
>>285
printf("name=0x%x &name=0x%x\n", name, &name);
で、両方とも同じ値なのはなぜ?
0288デフォルトの名無しさん2008/07/13(日) 01:27:44
>>287
そのようにしたとき、&nameが配列の参照からポインタに成り下がるため、先頭アドレスが表示される
0289デフォルトの名無しさん2008/07/13(日) 01:28:54
>287
|ポインタのサイズや内部表現が同じ処理系においては、配列へのポインタを与えても
|(渡される値が、型は異なっても実際には同じバイナリ列であるために)たまたま動く。
0290デフォルトの名無しさん2008/07/13(日) 01:53:30
>>288
違うw
配列のアドレスと配列の先頭アドレスが一致するからだ。
0291デフォルトの名無しさん2008/07/13(日) 02:05:01
>>287
同じ値になるんだな
知らなかった
0292デフォルトの名無しさん2008/07/13(日) 02:05:54
どうでもいいことだが、%pじゃね?
0293デフォルトの名無しさん2008/07/13(日) 02:15:06
>>290
&nameと配列の参照を取得した時点で、それは先頭要素を指すポインタに変わると思ってたが、違うのかな
0294デフォルトの名無しさん2008/07/13(日) 02:23:44
nameは配列全体で、ただしすぐ先頭要素へのポインタになる
&nameは配列全体へのポインタになる
&name[0]はまずname[0]が結合し次に&だから先頭要素へのポインタから0番目の要素へのポインタ=先頭要素へのポインタ

たいてーの処理系では値としてはまったく同じものでコンパイラが型チェックすることがあるだけ
でももちろんそうでない処理系もあるかもしれないということになる(C規格の上では)

%pに渡すポインタも、void*にキャストする必要があるかどうかは処理系定義じゃなかったかな
0295デフォルトの名無しさん2008/07/13(日) 02:24:02
char a[] = "abc";
というのがあって、aは0x10000とする。

aは当然0x10000なのだが、&aは?

&をアドレスを求める演算子と考えれば、aはもともとアドレスなので&aはaの値をそのまま返す。
ということではないのかな?
0296デフォルトの名無しさん2008/07/13(日) 02:24:46
>>285
> ポインタのサイズや内部表現が同じ処理系においては、配列へのポインタを与えても
> (渡される値が、型は異なっても実際には同じバイナリ列であるために)たまたま動く。
> しかしそれは規格が保証した動作ではない。

規格上は指す型によってポインタのサイズや内部表現が違ってもよいのですね
指すのが構造体の場合も、指す構造体によって
やはりサイズや内部表現が異なる可能性がありますでしょうか・・・?

継承っぽい動作の実装で構造体へのポインタを異なる構造体へのポインタに
キャストしてるもので。
0297デフォルトの名無しさん2008/07/13(日) 02:26:11
char *p;
p が 0x10000とした場合、
&pはpがもともとアドレスにもかかわらず、pと&pは異なる値になるよ
0298デフォルトの名無しさん2008/07/13(日) 02:28:07
>>295
ちがいます。

aは&演算子のオペランドでない場合は&aになる。
0299デフォルトの名無しさん2008/07/13(日) 02:28:09
>>294
> すべてのCコンパイラで配列への(キャストのない)参照はポインターを産み出す。このポインターはTへのポインターで配列の最初の要素を指す
これについてはどう思いますかね
0300デフォルトの名無しさん2008/07/13(日) 02:28:51
>>295
逆じゃね?
&a は配列aのアドレスを返す
aは配列だが添え字とか&がなければ配列のアドレスを返す
0301デフォルトの名無しさん2008/07/13(日) 02:33:16
>>295
違うよ
aはもともとはアドレスじゃなくて識別子つまり配列そのもの
いくつかの例外(&aを含む)を除いてアドレスに変換されるけど

あとアドレス演算子とは呼ばれているけど、実際に&演算子が生み出すのはポインタ
Cのポインタは「アドレス」と「型」が一緒になった概念
ほとんどのコンパイラは前者だけを変数に保存してコンパイラだけが後者を管理するから
出力すれば同じものに見えるけどね
0302デフォルトの名無しさん2008/07/13(日) 02:34:33
>>296
構造体レベルだとたぶん変わらない
関数ポインタになると変わってくる
0303デフォルトの名無しさん2008/07/13(日) 02:37:05
>これについてはどう思いますかね
どう思いますかねって何もおかしくないでしょ
そこには書いてない例外の部分もちゃんと含めてだけど
0304デフォルトの名無しさん2008/07/13(日) 02:38:13
>>302
さんくす
そうだよな、構造体は仮宣言でもポインタで取り回せるし
(それも規格に合ってるのか知らんけど)
0305デフォルトの名無しさん2008/07/13(日) 02:40:58
>>304
キャストするぶんにはそのへんコンパイラがちゃんとやってくれることになっている
0306デフォルトの名無しさん2008/07/13(日) 12:25:41
>>301
じゃあ、

char str[10];
scanf("%s",&str);

って書いた方が本来の意味として正しいってこと?
0307デフォルトの名無しさん2008/07/13(日) 12:30:29
型が違う
0308デフォルトの名無しさん2008/07/13(日) 12:37:45
何がどう違うの
0309デフォルトの名無しさん2008/07/13(日) 12:39:10
int dm[10];
int *p = dm;
int (*p2)[10] = &dm;
0310デフォルトの名無しさん2008/07/13(日) 12:58:24
俺が無難な指針を出してやろう。

&配列名 は当面使わなくてOK、な。
0311デフォルトの名無しさん2008/07/13(日) 16:35:43
ウィンドウを表示してそこにボタンを表示したいんですけど、ボタンを表示する方法がわかりません。
だれかボタンを表示する方法を教えて下さい。
0312デフォルトの名無しさん2008/07/13(日) 16:37:08
>>311
TKでいいのか?
0313デフォルトの名無しさん2008/07/13(日) 16:37:21
>>311
↓
http://www.kumei.ne.jp/c_lang/sdk/sdk_15.htm
03143112008/07/13(日) 16:50:34
>>313
ありがとうございます。
0315デフォルトの名無しさん2008/07/14(月) 06:08:58
http://best100.jp/link.php?carrier_id=3&category_id=21&site_id=yatiju
0316デフォルトの名無しさん2008/07/14(月) 14:45:26
C言語でフローを作成する際こういう方法でやるのかな?
http://www.soi.wide.ad.jp/class/20020008/slides/04/index_23.html
0317デフォルトの名無しさん2008/07/14(月) 14:46:24
今どきチャートなんて作らんよ
03183162008/07/14(月) 14:47:43
オブジェクト指向の言語ならUMLだとかいろいろあるが
C言語のように単なる構造化の場合どうやるんだろ?

古典的なフローだとどうもGOTO使ってるぽくていやなんだが
0319デフォルトの名無しさん2008/07/14(月) 15:01:15
>>318
古典的フローチャートにもループ記述子が存在しているからそれを使えばOK。
つーか、そもそも構造をブロック化するだけじゃないかと思うが。
0320デフォルトの名無しさん2008/07/14(月) 16:30:35
>>318
右側の構造化チャートならgoto使うイメージ無いだろ。
0321デフォルトの名無しさん2008/07/14(月) 16:55:33
system("command");の出力結果を得たいのですがどうしたらよいでしょうか

自分としては一つの方法として「標準出力をフックする」というのは思いついたのですが
難しそうなので半ば諦めかけています。

何か方法はありますか
0322デフォルトの名無しさん2008/07/14(月) 16:58:43
>>321
popen はどう?
0323デフォルトの名無しさん2008/07/14(月) 17:06:51
>>322
凄い、出来ました。
ありがとうございます

#include <stdio.h>
int main()
{
FILE *fp;
char buf[256];
fp = popen("ls", "r");
while(!feof(fp))
printf("%s", fgets(buf, 256, fp));
return 0;
}
0324デフォルトの名無しさん2008/07/14(月) 17:09:14
>>321
大抵の環境でpopen()が使えると思う。
0325デフォルトの名無しさん2008/07/14(月) 17:10:32
>>324
そうなんですか
windowsでも出来るんですね
cygwinのdllでも同封してun*xコマンドを駆使しつつ
両方で活用できるソフトを作る事も出来そうですね…

ありがとうございます
0326デフォルトの名無しさん2008/07/14(月) 17:12:52
>>325
VisualStudioなら_popen()かな。
0327デフォルトの名無しさん2008/07/14(月) 17:17:04
>>326
そうなんですか
ありがたいですm(_ _)m
0328デフォルトの名無しさん2008/07/14(月) 17:35:17
>>323
pclose 推奨
0329デフォルトの名無しさん2008/07/14(月) 22:06:13
char buf[256]みたいな配列の
10〜100番の要素を5〜95のように同サイズで重なる領域にコピーしたいんですが
こういう場合は一旦どこかに変数を保存しないと実現できないんでしょうか?
0330デフォルトの名無しさん2008/07/14(月) 22:08:35
>>329
memmove
0331デフォルトの名無しさん2008/07/14(月) 22:09:10
コピーする順番がコントロールできるなら、そのままコピーすればいい
■ このスレッドは過去ログ倉庫に格納されています