ぼんさい塾

ぼんさいノートと補遺に関する素材や注釈です.ミスが多いので初稿から1週間を経た重要な修正のみ最終更新日を残しています.

ポインタ

2013-08-27 13:49:40 | 暮らし
progC.pdf
progC-s.pdf
記事一覧
 
                       仮引数での宣言

progC-s.pdf に「D8R%ポインタ」を追加しました.「ポインタは難しくない」と書いた資料もありますがやはり難しいと思います() --- 考えて分からなくても,コンパイラがあれば これ と同様にして自分で調べることができます.
(1) 「int x[3][4];」のとき "xはアドレスである" といっても sizeof(x) == 48. (2) 「int f(int y[100][5]){・・・}」の y はポインタで sizeof(y) == 4. (3) 「y[100][5]」は「y[ ][5]」と等価であるが「y[-100][5]」はエラー.(4) f の呼び出し「f(x)」はエラーにならないが「int z[6];」の「f(z)」はエラー. (5) 仮引数の宣言では *p == p[ ] であるが,(p[ ] == p[0] でもいいのに)実行文「p[ ] = 7;」はエラー --- (処理系がどこまで面倒を見ているか)考えても分かりませんね.調べるしかありません!

参考資料([n]は本文でも引用):
[1] ポインタ (プログラミング) - Wikipedia
  http://ja.wikipedia.org/wiki/%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)
逆に言えば、整数の様な自由な四則演算は制限されており、座標に対する演算と同じ演算しか出来ないという事である。
[2] BCC Developer - Hi-HO
  http://www.hi-ho.ne.jp/jun_miura/bccdev.htm
専らこれで確認しています.*.c であればCとしてコンパイルしますが「//」も使えます(C99で追認)
[3] プログラミング言語C―ANSI規格準拠― 第2版
  http://www.kyoritsu-pub.co.jp/bookdetail/9784320026926
全般に参照していますが,補足(7)の引用上明示.
[4] ポインタ虎の巻
  http://www.nurs.or.jp/~sug/soft/tora/index.htm
初級篇目次(1-9), 中級篇目次(1-7)
[5] ポインタ(pointer)
  http://www.cc.kyoto-su.ac.jp/~yamada/programming/pointer.html
メモリモデル,変数のメモリサイズとアドレス,変数とポインタ,ポインタ型変数,
配列とポインタ,ポインタへのポインタ
[6] C言語:ポインタ入門
  http://www.geocities.jp/debu0510/personal/c_pointa.html
基本,メモリの動的確保,関数へ参照渡しもどきをする,関数へのポインタ,
ポインタへのポインタ,voidへのポインタ,コールバック関数1,複雑な宣言,初期化
---------
[7] なぜポインタを使うのか? - Yahoo!知恵袋
  http://note.chiebukuro.yahoo.co.jp/detail/n3121
[8] C言語 ポインタ完全制覇
  http://kmaebashi.com/programmer/pointer.html
ポインタが難しいのではない。 C言語の、配列とポインタにかかわる文法が混乱しているだけだ。
[9] プログラム初心者にC言語のポインタを不本意ながら教える羽目になった ...
  http://d.hatena.ne.jp/kura-replace/20120611/1339376977
本稿は「ポインタの解説」ではなく「C 言語のポインタの教え方」です。
[10] C/C++は永久に不滅です! - Part4 誰もがつまずくポインタを完璧理解 ...
  http://itpro.nikkeibp.co.jp/article/COLUMN/20061206/256198/
考え方さえわかってしまえば、ポインタはそれほど難しいものではありません。
次ページ以降はITpro会員(無料)の方のみお読みいただけます。

補足:(1) 多数の資料がありますが,とりあえず上記資料だけ掲げておきます.
(2) [%4] の表現は ここ で紹介した資料と少し変えています.
---------
(3) [%1] の記号《p》は一般には通用しません.
(4) [%11] の「処理系に依存」は“ビッグエンディアン/リトルエンディアン”.
(5) [%2] の x[3][4] の初期値は {{5, 6, 0, 0}, {7, 8, 9, 0}, {0, 0, 0, 0}}なので,p[6] (== p[4+2]) の値は x[1][2] (== 9).「int (*q)[2] = x+1;」なら q[0][0] == 7,q[0][1] == 8,q[1][0] == 9.
(6) 局所変数の宣言でも「int q[ ][4] ={{α, β};」は「int q[2][4] ={{α, β};」と同じなのでエラーにはなりませんが,このときの q は配列の先頭アドレスでポインタではありません(e.g. 代入不能).
(7) 「char (*(*x[3])())[5];」は K&R-2,5.12 からの引用です.
(8) 関数の(プロトタイプ)宣言については次回述べます.
------------------------------------------------------------------
#include < stdio.h>//HTMLタグに化けないようSPを挿入
int main(void){
  int x[3][4]={{5,6},{7,8,9}}, i, k;
  printf("sizeof(x) is %d\n", sizeof(x));
  for(i = 0; i < 3; i++){
    for(k = 0; k < 4; k++){
      printf("%d, ", *(&x[0][0] + i*4 + k));
    }
    printf("\n");
  }
  printf("%d:f(x)\n", f(x));
  return 0;
}
int f(int p[100][5]){int i, k;
  printf("sizeof(p) is %d\n", sizeof(p));
  for(i = 0; i< 3; i++){
    for(k = 0; k < 4; k++){printf("%d, ", p[i][k]);}
    printf("\n");
  }
  return p[0][1];
}


論理演算

2013-08-23 19:22:00 | 暮らし
progC.pdf
progC-s.pdf
記事一覧

                            集合算

progC-s.pdf に「D8N%論理演算」を追加しました.

参考資料([n]は本文でも引用):
[1] ビット演算 - Wikipedia
  http://ja.wikipedia.org/wiki/%E3%83%93%E3%83%83%E3%83%88%E6%BC%94%E7%AE%97
ビットシフトに対して第2引数の値が負である場合、あるいは第1引数の型のビット数を超える場合の規定は言語によって異なる ・・・ C, C++ の標準では、このような場合の結果は未定義となっている。
[2] ビットフィールド - Wikipedia
  http://ja.wikipedia.org/wiki/%E3%83%93%E3%83%83%E3%83%88%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89
ビット演算の論理積・論理和・否定の組み合わせが、フラグのセット・リセットとテストを行うために使われる。
[3] へ、変態っ!!読めないからやめてっ!bit使ったデータ構造 ...
  http://d.hatena.ne.jp/jetbead/20121202/1354406422
Darseinさんが20日目の記事で、ビット演算についての詳しい説明を紹介してくださっています!必読ですね!!!!:)
[4] Tech Tips: ビット演算魔術、部分集合を高速に出すの巻
  http://techtipshoge.blogspot.jp/2011/05/blog-post_28.html
--y & x は、集合xの部分集合をすべて列挙することができます。
[番外] C++ ビット集合(std::bitset) - Cppll
  http://www.cppll.jp/cppreference/cppbitset_details.html
[5] シフト
  http://wisdom.sakura.ne.jp/programming/asm/assembly19.html
アセンブリ言語のシフトは、高水準言語のそれよりももっと細かい操作ができます
[6] ステータスレジスタ - Wikipedia
  http://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF
キャリーフラグを持つプロセッサでは、あふれた桁をキャリーフラグに格納する。 また、加算命令にはキャリーフラグの内容も同時に加算するという命令を持っている。「算術オーバーフロー」も参照

補足:(1) ビット演算は制御用のソフトではビットフィールドのマスクやオン/オフに頻繁に使われます.
(2) 10進-16進変換,16進-10進変換の解答例はブログの「記事一覧」から参照できます.
 


goto文

2013-08-21 19:06:45 | 暮らし
progC.pdf
progC-s.pdf
記事一覧

                   構造化とgoto文

progC-s.pdf に「D8L%goto文」を追加しました.

参考資料([n]は本文でも引用):
[1] 構造化プログラミング - Wikipedia
http://ja.wikipedia.org/wiki/%E6%A7%8B%E9%80%A0%E5%8C%96%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0
ダイクストラは“Go To Statement Considered Harmful”[8]および“Structured Programming”[4]において、好ましい構造として手続き呼び出しの他に、順次・反復・分岐の3つを挙げた。ヴィルトはこれらを構造化文(structured statement)と呼んだ[28]。goto文を避けて構造化文を用いるようプログラマーに教えることが、構造化プログラミングの伝統的な知恵である[29]。
[2] go to文は 有害である - みねこあ
  http://d.hatena.ne.jp/minekoa/20090712/1247398356
・使ってはならないのは「goto」ではない | 株式会社きじねこ
・Go To Statement Considered Harmful(ダイクストラ)
[3] Super Technique 講座~goto 文が有用な場合
  http://www.nurs.or.jp/~sug/soft/super/goto.htm
goto 文の利用とは、神学論争ではなくて、「リソースバランス」の問題である。この視点によって goto 文という議論の多いC言語機能を検討するのが、この論の目的である。goto 文の利用は「常に不可である」とする教条主義者はこんな論は読まずに、信仰の道を歩まれるのが良かろう。
[4] アセンブリ言語 - Wikipedia
  http://ja.wikipedia.org/wiki/%E3%82%A2%E3%82%BB%E3%83%B3%E3%83%96%E3%83%AA%E8%A8%80%E8%AA%9E
例えば、次の命令はx86/IA-32プロセッサのもので、8ビット即値をレジスタに入れる命令である。この命令のバイナリコードは 10110 で、その後に3ビットのレジスタを指定する識別子が続く。AL レジスタの識別子は 000 なので、次に示す機械語は AL レジスタに 01100001 というデータをロードする[8]。
インテルのオペコード 10110000 (B0) は8ビットの値を AL レジスタにコピーするが、10110001 (B1) は CL レジスタにコピーし、10110010 (B2) は DL レジスタにコピーする。これらをアセンブリ言語で表現すると次のようになる[8]。
[5] x86アセンブリ言語入門 - nifty
  http://homepage1.nifty.com/herumi/prog/prog.html
なおこのページではごく簡単なコードを書けるようになること, デバッグ時に知っておけばよいこともあるだろう程度の知識の取得を目指します. 高速化手法自体については触れません.
[6] 試験で使用する情報技術に関する用語・プログラム言語など
  http://www.jitec.ipa.go.jp/1_13download/shiken_yougo_ver2_1.pdf
[7] フローチャート - Wikipedia
  http://ja.wikipedia.org/wiki/%E3%83%95%E3%83%AD%E3%83%BC%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88
[8] 構造化チャート の画像検索結果
  http://www.google.co.jp/search?q=%E6%A7%8B%E9%80%A0%E5%8C%96%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88&hl=ja&rlz=1T4GZEZ_jaJP332JP332&tbm=isch&tbo=u&source=univ&sa=X&ei=jLAUUqbMIIjZkAWa0IC4Cg&ved=0CCsQsAQ&biw=1201&bih=700
[9] フローチャートから構造化チャートへ - Acroquest Technology 株式会社
  http://www.acroquest.co.jp/webworkshop/programing_course/index7.html
[10] PAD (Problem Analysis Diagram) によるプログラムの設計および作成
  http://ci.nii.ac.jp/naid/110002723539
[11] PAD について
  http://www2.ee.knct.ac.jp/el/E2/L210/algorism/pad1.html

補足:(1) コンピュータの動作原理を理解するにはアセンブリ言語でプログラムを書くことが最良の方法だと思います.アセンブリ言語を知らず,単に「Cのプログラミングでgoto文を使うな」と教わった人も,if 文や while 文を goto 文で表現したプログラムを見ると,少しはハードウェアの動作を想像できると思います --- アセンブラを使ったかどうかで switch 文の見方も変ってきます.
(2) Cでプログラムを作るときには goto 文を使わないほうが無難です --- フローチャートでなく構造化チャート(広義)を用いて設計すれば自動的に goto 文は現れなくなります.自分が作るときは使いませんが講義ではここに示 したような PAD もどきを使っていました.


書式付入出力

2013-08-20 20:56:39 | 暮らし
progC.pdf
progC-s.pdf
記事一覧
 
                                      scanf( ) の問題点 [2]

progC-s.pdf に「D8K%書式付入出力」を追加しました.

参考資料([n]は本文でも引用):
[1] printf - ウィキペディア - Wikipedia
  http://ja.wikipedia.org/wiki/Printf
%[引数順][フラグ][最小フィールド幅][.精度][長さ修飾子]変換指定子
引数順..これはCの規格ではなくPOSIXで規定されている。
[2] scanf - ウィキペディア - Wikipedia
http://ja.wikipedia.org/wiki/Scanf
ユーザからの入力を受ける機能を持つにもかかわらず、後述するようにエラーに対する考慮を何もしていないため、テストプログラムを除いてはあまり使われない。
[3] C言語-書式付入出力関数(printf文・scanf文)の書式 - 碧色工房
http://www.mm2d.net/c/c-01.shtml
前置きが長くなりましたが,このフォーマットの表を作ってみました.
[4] 標準入出力関数(1)
http://www9.plala.or.jp/sgwr-t/c/sec05.html
5-4.scanf()の注意事項
[5] scanfにはご注意を!
  http://kaiya.cs.shinshu-u.ac.jp/pub/c/scanf/
scanfがちゃんとデータを読んだか否かの確認,そしてライブラリ関数を使う時の一般則としては, 関数の返り値を利用する ことが有効です.
以下のOSとコンパイラの組み合わせでは,後述のようなエラーが発生します.
ターミナル(コンソール)入出力をはっきりと理解してなさそうな人は使うのをやめたほうが良いでしょう.
[6] C: scanf( )関数の連続使用は注意
http://www.aa.alpha-net.ne.jp/freeh/minimini/develop/cscanf.html
上記の例でバッファに溜められるのは'a''b''c''\n'という4文字分がバッファに溜まっています。すると、1つ目のscanf("%s")では"abc"という文字列が変数*strに代入されます。が、まだ改行'\n'がバッファに残っているのです。上記の問題を解消するには、以下のような方法があります。
[7] scanf( )関数
http://wisdom.sakura.ne.jp/programming/c/c58.html
しかし、scanf( )関数の中で特別変わったフォーマットがあります。それがスキャン集合指定子です。

補足:(1)キー入力はバックスペースによる修正があるので,とりあえずバッファに入力文字を格納し,改行文字を受け取ってから処理を始めるのが一般的です.このためプログラミングがややこしくなっています --- お勧めは progC.pdf (@16) の単純な方法.
(2) MS-DOS の頃,<stdio.h> の getchar( ) でなく<conio.h> の getch( ) や kbhit( ) をよく使いました. <stdio.h>には読まなかったことにしてバッファに戻す ungetchar( ) という関数もあったはずですが
  http://ja.wikipedia.org/wiki/%E6%A8%99%E6%BA%96C%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA#.E5.85.A5.E5.87.BA.E5.8A.9B_.3Cstdio.h.3E
のリストには見当たりませんでした.

 

 


データの型

2013-08-19 19:47:51 | 暮らし
progC.pdf
progC-s.pdf
記事一覧

                        IEEE 754

progC-s.pdf に「D8J%データの型」を追加しました.

参考資料([n]は本文でも引用):
[1] データ型 - Wikipedia
  http://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B
詳細は「プリミティブ型」および「複合データ型」を参照; 詳細は「型システム」を参照
[2] (再掲) 整数型 - Wikipedia
http://ja.wikipedia.org/wiki/%E6%95%B4%E6%95%B0%E5%9E%8B
[3] データ型 (C# と Java の比較) - MSDN - Microsoft
  http://msdn.microsoft.com/ja-jp/library/ms228360(v=vs.90).aspx
.NET Framework データ型間の暗黙の型変換の一覧を次に示します。
[4] IEEE 754 - ウィキペディア - Wikipedia
http://ja.wikipedia.org/wiki/IEEE_754
・これを単に2の補数で表すと、全体の符号 sign とは別に exponent も符号を持つことになり、単純な大小比較ができなくなってしまう。そのため、指数部はバイアスされて常に正の値となるような・・・
・非正規化数の場合q = -126で、cが 0.fraction とする。(qは-127 ではない。仮数の小数点以上の部分が0になっている関係で、指数を-126としてバランスをとっている。)
[5] 型変換 - Wikipedia
http://ja.wikipedia.org/wiki/%E5%9E%8B%E5%A4%89%E6%8F%9B
[6] Cの型変換と式 - @IT
http://www.atmarkit.co.jp/fcoding/articles/c/05/c05a.html

補遺:(1) 指数部のバイアス表現の意図については[4]を見てください.
(2) 配列については progC-e.pdf(演習)で詳しく調べます.BccDev.exe
    int x[4] = {10, 11, 12, 13};
    printf("%d, %d, %d, %d\n", x+1, (&x[0])+1, x+2, (x+2)-(x+1));
を実行したときの出力は「1245056, 1245056, 1245060, 1」でした.(x+x), (2*x)は「無効なポインタの加算」「ポインタの不正な使用」になりました.
(3) ポインタについては別途説明しますが,1ページに纏めるので http://pulsar.blog.ocn.ne.jp/topics/B2010-03.pdf より詳しくなることはありません.
(4) キャストの代わりに所望の変数に代入したときの処理を
    int x0, x1, x2; double y = 0x123456789;
    char c0; unsigned char c1; float z;
    x0 = y; x1 = y * 16; x2 = y * 256; c0 = c1 = y; z = y*1000;
    printf("x0=%x, x1=%x, x2=%x, y=%f\n", x0, x1, x2, y);
    printf("c0=%x, c1=%x, z=%f\n", c0, c1, z);
で調べた結果は次のようになりました.
    x0=23456789, x1=34567890, x2=45678900, y=4886718345.000000
    c0=ffffff89, c1=89, z=4886718578688.000000 (整数は整数)
(5) 静的変数は指定がなければ 0 や NULL になるが自動変数では何故そうとは言えないのかは,プログラムがどのようにコンパイルされるかを知れば極めて自然であることが分かります --- スタック・記憶クラスの話で言及します.
※ main( ) の外で「int *p;」と宣言して「printf("%d\n", p);」を実行すると「0」が表示されます(大域変数は無指定なら静的 --- これも自然).