情報処理II

情報処理Ⅱ
第5回
2004年11月2日(火)
演算子のすべて(復習)
1. 関数呼び出し( ),配列の添字[ ],構造体のメンバ参照(., ->)
2. 単項演算子(!, 単項*, ++, 単項+, sizeof, キャストなど)
3. 乗除(2項*, /, %)
4. 加減算(2項+, 2項-)
5. シフト(<<, >>)
6. 関係(<, >, <=, >=)
7. 関係(==, !=)
8. ビット演算(&)
9. ビット演算(^)
10. ビット演算(|)
11. 論理演算(&&)
12. 論理演算(||)
13. 3項演算子(? :)
14. 代入演算子(=, +=など)
15. コンマ(,)
高い
優
先
順
位
低い
優先順位を変えたければ,( )で囲む.( )が何重にもなることがある.{ }や[ ]は,
この目的で使用できない.

2
3項演算子

オペランド1 ? オペランド2 : オペランド3



例: t = (a > b) ? a : b; ⇒
if (a > b) t = a; else t = b;
演算結果は左辺値ではない



まずオペランド1を評価する.それが真であればオペランド2を,
偽であればオペランド3を評価して,その値を演算結果とする.
× a > b ? a : b = 10;
○ *(a > b ? a : b) = 10;
a, bはポインタ変数
3項演算子の入れ子も可能だが,読みにくい
3
その他の演算子



関数呼び出し: ( )
配列の添字: [ ]
コンマ演算子: ,

例: for (i = 0, p = function(p[i], 1); i <
10; i++)
これらは構文の一部であり,演算子ではない.
4
代入の順序について

オペランドの評価順序は,特に明記したものを除いて,不定
(処理系依存)である.式の中で同一のオブジェクトに2つ以
上の代入をしないよう心がける.


例: x=2; printf("%d, %d", ++x, ++x); の出力は
「3 4」かもしれないし,「4 3」かもしれない.
例: x % 2 ? (x = x * 3 + 1) : (x /= 2); は意
図通りに動作する(が,if文で書くほうが自然).
5
まとめ




Cでは多彩な演算子が利用できる.いくつかは数学の記号に
近く,いくつかはC独特である.
各演算子には優先順位がある.
同じ優先順位の演算の評価順序を決めるのは,結合の方向
である(演算子により,「左から右」か「右から左」かが決まっ
ている).
評価されない式に注意.
6
本日学ぶこと

配列(array),文字列,多次元配列



次に学ぶこと:ポインタ(pointer)
配列とポインタは,Cではきわめて重要な要素.
ここでつまづくと,ろくにプログラムは作れない.
問題

配列を用いて,行列計算(和,積,逆行列,固有値などの計
算)ができるか?
7
配列とは?
配列は,同一の型のオブジェクトを1個以上連続して
記憶域(メモリ)に配置し利用するための機構である.



同一の型のオブジェクト: a[0]はint,a[1]はchar,とい
うのはNG.
1個以上: 1個でもいい.0個はNG.
連続して: 隙間がない.a[10]の次はa[11],その次は
a[12],…となる.
8
配列の宣言(1)

int a[3]; と宣言すると,3個のint型オブジェクトを確保
する.



a[0], a[1], a[2]が左辺値として使用できる.
宣言の形にも関わらず,a[3]は使用できない.代入したとき
の動作は不定.
「配列は0から始まる」と覚える.
a
a[0] a[1] a[2]
変数名:
参照可能だが
代入は不可.
オブジェクト:
代入と参照が
可能.
9
配列の宣言(2)

配列のサイズは?




× 整数以外,負の数,0
× 変数や関数呼び出しを含む値
○ 正の整数値に評価される定数式(定数のみからなる式)
一括の宣言

int a[3], b[5]; のように,一つの宣言文で複数の配列
を宣言できる.
10
ビットパターンのプログラムを配列で
0
0
1
0
1
0
0
0
y[7] y[6] y[5] y[4] y[3] y[2] y[1] y[0]
0
0
1
0
1
0
0
a
0
11
配列の初期化


int x = 0; と同様に,配列も初期化できる?
int a[3] = {100, 200, 300}; と書けばよい.


int a[3]; a[0] = 100; a[1] = 200; a[2] =
300; と同じ.
他の宣言例





○
○
○
?
×
int
int
int
int
int
a[3]
a[3]
a[3]
a[3]
a[3]
=
=
=
=
=
{100, 200, 300,};
初期値が明示されて
{100, 200};
いない要素には,0が
{0};
代入される.
{};
{100, 200, 300, 400};
12
要素数を明示しない宣言

int a[ ] = {100, 200, 300}; は
int a[3] = {100, 200, 300}; と同じ.



要素数をコンパイラが決めてくれる.
要素数を決め打ちする必要がなく,将来変更する可能性のあ
るとき,この書法が積極的に用いられる.
× int a[ ];
13
配列の要素数の求め方

aを配列変数とすると,sizeof(a) / sizeof(a[0])
でその要素数が求められる.


算術型に限らず,どんな型でも成立する.
aがポインタ変数の場合や,mallocライブラリルーチンなどで
動的に確保した配列領域には,利用できない.
14
文字列

文字列は,末尾に '\0' のつくchar配列である.



'\0' は 0 と同一.文字を意識するときに使用する.
'a' の書式を文字定数という.ただし,int型の値である.
"a" の書式を文字列リテラルという.

文字列リテラルを直接書き換えることはできないが,配列変数
の初期化で代入し,そこを書き換えることは可能.
文字:
'a'
文字列:
"a"
'a'
'\0'
15
文字列と配列変数

char a[ ] = "wakayama"; は,
char a[9] = {'w', 'a', 'k', 'a', 'y', 'a',
'm', 'a', '\0'}; と同じ.



sizeof(a)/sizeof(a[0]) は8ではなく9.
char a[9] = "wakayama"; も同じ.
char a[8] = "wakayama"; は,
char a[8] = {'w', 'a', 'k', 'a', 'y', 'a',
'm', 'a'}; と同じ.

文字列ではない.
16
文字列を書き換える例
i
i
i
i
i
i
i
i
i
= 1
= 2
=
3
=
4
=
5
=
6
=
7
=
8
=
9
と出力できる?

printf("i = %9d", i); の「9」を書き換える.
17
多次元配列の宣言


多次元配列: 配列の配列
int a[2][2]; と宣言すると,
sizeof(int)が4のとき,
sizeof(a)は16
sizeof(a[0])は8
sizeof(a[0][0])は4
a
参照可能だが
代入は不可.
a[0]
a[1]
a[0][0] a[0][1] a[1][0] a[1][1]
オブジェクト:
代入と参照が
可能.
18
多次元配列の初期化

例






int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8,
9}};
int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int a[3][3] = {1, 2, 3, 4};
int a[3][3] = {{1, 2}, {3, 4}};
int a[2][2][2] = {{1, 2}, {3, 4}};
int a[ ][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8,
9}};
最も左だけ
省略可能
初期値が明示されて
いない要素には,0が
代入される.
19
行列の積を求めるプログラム(1)

2×2の行列は int a[2][2]; で宣言.


float,double,unsigned intのほうがいい場合も
a と b の積を c に格納するとき:
b[0][0]
b[1][0]
b[0][1]
b[1][1]
a[0][0] a[0][1]
c[0][0] = a[0][0] * b[0][0] c[0][1] = a[0][0] * b[0][1]
+ a[0][1] * b[1][0]
+ a[0][1] * b[1][1]
a[1][0] a[1][1]
c[1][0] = a[1][0] * b[0][0] c[1][1] = a[1][0] * b[0][1]
+ a[1][1] * b[1][0]
+ a[1][1] * b[1][1]
20
行列の積を求めるプログラム(2)

一般に,


n×mとm×pの行列の積を求めることができ,結果は
n×pの行列になる.
c[i][j] = ∑0≦k≦m-1(a[i][k] * b[k][j])
これを 0≦i≦n-1,0≦j≦p-1 に対して計算すればよい.
p
3つの変数i, j, k
による3重ループ
m
n
n
p
21
まとめ




「型 変数名[要素数];」と宣言すると,「変数名[0]」 ~
「変数名[要素数-1]」が利用できる.
配列宣言と同時に,{ … } を用いて初期化も可能.
文字列は,末尾に '\0' のつく文字配列である.文字列を
配列に格納すれば,書き換えられる.
多次元配列を用いると,2次元,3次元,…に自然に情報を格
納できる.
22
次に学ぶこと


ポインタ(Pointer)
問題


文字列が回文("noon", "トマト" など)かどうか判定でき
る?
float型の値のビットパターンを出力できる?
23
ポインタ

ポインタとは?


指し示すもの
配列とはまた別の,実用的かつ多様な型を作る一つの方式
(派生型)
y
*y
24