※C言語初心者の為、内容に不備がある可能性があります。
C言語で配列を定義する。
実行結果
もちろん以下のようにも書ける。
int a[4] = { 1, 2, 100, 50 };
int a[] = { 1, 2, 100, 50 };
int a[4] = { 1, 2 };
↑こうやって書くとa[2], a[3]は「0」が勝手に代入される!
int b[2] = { 1, 2, 3 }; と書くと以下のように怒られる。
int c[] = { 1, 2, };
↑この書き方はなぜか怒られない。
配列の要素は原則として、順番にメモリ上に並んでいるはずなので実際に各
要素のアドレスを出してみる。
実行結果
確かに4バイトずつつながってる。
最後のaの出力結果からわかるとおり、配列の名前はその配列の先頭の要素の
アドレスをあらわしている!
ということは、int型の配列であればaで示されている先頭のアドレスより4バイト進めると
a[1]のアドレスになるということ?以下で試してみる。
結果
結果から、「int型へのポインタに1を加える」ということは「int型の大きさだけアドレスを1つ進める」
ということがわかる。これはどうも他の型についても同様みたい。
配列の名前aはポインタのように(a + 1)するとaより4番地進んだアドレスをあらわすらしい。
実行結果
a[n] は *(a+n) と同じ!
配列とポインタは似てる。でもポインタは変数だから書き換えができた。
でも配列名は先頭要素のアドレスを示すもので、変数ではない。だから書き換えは
できない。
ポインタpに対してはp++可能だけど配列名aに対してa++はできない。
さらに・・・。
a[n]は*(a + n)と同じで、
*(a + n) と*(n + a)は実は同じ。。
だから、、、
「a +n」と[n + a]も実は同じ。。
*(a + n)がa[n]と同じなので、*(n + a)はn[a]と同じ。
つまり、、
a[n]はn[a]と書いても同じ!!!
a[5]を5[a]と書いても同じ意味(気持ち悪い。)
配列とポインタはすっごい密接。
う?ん。なんとなくという感じ。次は多次元配列。
int a[5][2] の配列はメモリ上では以下のように並んでいる。
a[0][0]
a[0][1]
a[1][0]
a[1][1]
a[2][0]
a[2][1]
a[3][0]
a[3][1]
a[4][0]
a[4][1]
1次元の配列と同様に「a」はa[0][0]のアドレスを表している。
配列の初期化方法
int a[5][2] = {0,1,2,3,4,5,6,7,8,9};
もしくは
int a[][2] = {0,1,2,3,4,5,6,7,8,9};
最初の要素数のみ省略が可能。
メモリに並ぶ順番⇒「多次元配列は、一番外側(右)から回る」
a[2][0]
は式の中に2つの[]が存在している。
演算子の優先順位は等しいので結合規則 通りに→で評価される。
そのため(a[2])[0]と書いても同じ。
a[2]を仮に「A」と置き換えた場合A[0]となり、一次元の配列のように見える。
するとAが配列名で、A[0]のアドレスを表していることになる。
またA[0]は*(A + 0)とも書けた。
これを元に戻すと、、
*(a[2] + 0)
a[2]自体は*(a + 2)とかけたのでa[2][0]は・・・
*( *(a + 2) + 0 )
と書ける。
以上のことを確かめるプログラムを書いてみる。
実行結果
おんなじだ?。
少し実用的に使ってみる。
実行結果
配列はこんなところで。
猫の好きな私に向いた入門書
困ったもんだ
手前のレビュアー達の書く通り
猫でもわかるかな?
C言語で配列を定義する。
#include <stdio.h> int main() { int a[4]; a[0] = 1; a[1] = 2; a[2] = 100; a[3] = 50; printf( "a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3] ); return 0; }
実行結果
a[0] = 1, a[1] = 2, a[2] = 100, a[3] = 50
もちろん以下のようにも書ける。
int a[4] = { 1, 2, 100, 50 };
int a[] = { 1, 2, 100, 50 };
int a[4] = { 1, 2 };
↑こうやって書くとa[2], a[3]は「0」が勝手に代入される!
int b[2] = { 1, 2, 3 }; と書くと以下のように怒られる。
array01.c:13: 警告: 配列初期化子内の要素が多すぎます array01.c:13: 警告: (near initialization for 'b') array01.c:13: 警告: unused variable 'b'
int c[] = { 1, 2, };
↑この書き方はなぜか怒られない。
配列の要素は原則として、順番にメモリ上に並んでいるはずなので実際に各
要素のアドレスを出してみる。
#include <stdio.h> int main() { int a[4] = { 1,2,3,4 }, i; for( i = 0; i < 4; i++ ) { printf( "&a[%d] = %p\n", i, &a[i] ); } printf( "\na = %p\n", a ); return 0; }
実行結果
&a[0] = 0xbfa83570 &a[1] = 0xbfa83574 &a[2] = 0xbfa83578 &a[3] = 0xbfa8357c a = 0xbfa83570
確かに4バイトずつつながってる。
最後のaの出力結果からわかるとおり、配列の名前はその配列の先頭の要素の
アドレスをあらわしている!
ということは、int型の配列であればaで示されている先頭のアドレスより4バイト進めると
a[1]のアドレスになるということ?以下で試してみる。
#include <stdio.h> int main() { int a[] = {10, 20, 30, 40}, i, *p; p = a; /* pにa[0]のアドレスを代入 */ for ( i = 0; i < 4; i++ ) { printf( "&a[%d] = %p, a[%d] = %d, *(p + %d) = %d\n", i, &a[i], i, a[i], i, *(p+i) ); } return 0; }
結果
&a[0] = 0xbff2ade8, a[0] = 10, *(p + 0) = 10 &a[1] = 0xbff2adec, a[1] = 20, *(p + 1) = 20 &a[2] = 0xbff2adf0, a[2] = 30, *(p + 2) = 30 &a[3] = 0xbff2adf4, a[3] = 40, *(p + 3) = 40
結果から、「int型へのポインタに1を加える」ということは「int型の大きさだけアドレスを1つ進める」
ということがわかる。これはどうも他の型についても同様みたい。
配列の名前aはポインタのように(a + 1)するとaより4番地進んだアドレスをあらわすらしい。
#include <stdio.h> int main() { int *p, i, a[] = {20, 40, 80, 100}; p = a; for( i = 0; i < 4; i++ ) { printf( "&a[%d] = %p, (p + %d) = %p, (a + %d) = %p\n", i, &a[i], i, p + i, i, a + i); } return 0; }
実行結果
&a[0] = 0xbff0a8e8, (p + 0) = 0xbff0a8e8, (a + 0) = 0xbff0a8e8 &a[1] = 0xbff0a8ec, (p + 1) = 0xbff0a8ec, (a + 1) = 0xbff0a8ec &a[2] = 0xbff0a8f0, (p + 2) = 0xbff0a8f0, (a + 2) = 0xbff0a8f0 &a[3] = 0xbff0a8f4, (p + 3) = 0xbff0a8f4, (a + 3) = 0xbff0a8f4
a[n] は *(a+n) と同じ!
配列とポインタは似てる。でもポインタは変数だから書き換えができた。
でも配列名は先頭要素のアドレスを示すもので、変数ではない。だから書き換えは
できない。
ポインタpに対してはp++可能だけど配列名aに対してa++はできない。
さらに・・・。
a[n]は*(a + n)と同じで、
*(a + n) と*(n + a)は実は同じ。。
だから、、、
「a +n」と[n + a]も実は同じ。。
*(a + n)がa[n]と同じなので、*(n + a)はn[a]と同じ。
つまり、、
a[n]はn[a]と書いても同じ!!!
a[5]を5[a]と書いても同じ意味(気持ち悪い。)
配列とポインタはすっごい密接。
う?ん。なんとなくという感じ。次は多次元配列。
int a[5][2] の配列はメモリ上では以下のように並んでいる。
a[0][0]
a[0][1]
a[1][0]
a[1][1]
a[2][0]
a[2][1]
a[3][0]
a[3][1]
a[4][0]
a[4][1]
1次元の配列と同様に「a」はa[0][0]のアドレスを表している。
配列の初期化方法
int a[5][2] = {0,1,2,3,4,5,6,7,8,9};
もしくは
int a[][2] = {0,1,2,3,4,5,6,7,8,9};
最初の要素数のみ省略が可能。
メモリに並ぶ順番⇒「多次元配列は、一番外側(右)から回る」
a[2][0]
は式の中に2つの[]が存在している。
演算子の優先順位は等しいので結合規則 通りに→で評価される。
そのため(a[2])[0]と書いても同じ。
a[2]を仮に「A」と置き換えた場合A[0]となり、一次元の配列のように見える。
するとAが配列名で、A[0]のアドレスを表していることになる。
またA[0]は*(A + 0)とも書けた。
これを元に戻すと、、
*(a[2] + 0)
a[2]自体は*(a + 2)とかけたのでa[2][0]は・・・
*( *(a + 2) + 0 )
と書ける。
以上のことを確かめるプログラムを書いてみる。
#include <stdio.h> int main() { int a[3][2] = {10, 20, 30, 40, 50, 60}; int i, j; /* 各要素の値を確かめる */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 2; j++ ) { printf( "a[%d][%d] = %d\n", i, j, a[i][j] ); } } printf( "\n" ); /* 各要素のアドレスを確かめる */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 2; j++ ) { printf( "&a[%d][%d] = %p (a[%d] + %d) = %p\n", i, j, &a[i][j], i, j, ( a[i] + j ) ); } } printf( "\n" ); /* a[m][n]を*(*(a + m) + n)と書けるのか確かめる */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 2; j++ ) { printf( "*(*(a + %d) + %d) = %d\n", i, j, *(*(a + i) + j)); } } return 0; }
実行結果
a[0][0] = 10 a[0][1] = 20 a[1][0] = 30 a[1][1] = 40 a[2][0] = 50 a[2][1] = 60 &a[0][0] = 0xbf97b3e0 (a[0] + 0) = 0xbf97b3e0 &a[0][1] = 0xbf97b3e4 (a[0] + 1) = 0xbf97b3e4 &a[1][0] = 0xbf97b3e8 (a[1] + 0) = 0xbf97b3e8 &a[1][1] = 0xbf97b3ec (a[1] + 1) = 0xbf97b3ec &a[2][0] = 0xbf97b3f0 (a[2] + 0) = 0xbf97b3f0 &a[2][1] = 0xbf97b3f4 (a[2] + 1) = 0xbf97b3f4 *(*(a + 0) + 0) = 10 *(*(a + 0) + 1) = 20 *(*(a + 1) + 0) = 30 *(*(a + 1) + 1) = 40 *(*(a + 2) + 0) = 50 *(*(a + 2) + 1) = 60
おんなじだ?。
少し実用的に使ってみる。
#define NO 3 /* NOを3と定義 */ #include <stdio.h> int main() { int point[][2] = { 80, 80, /* 一人目の点数 英語、数学 */ 100, 98, /* 二人目の点数 英語、数学 */ 60, 80, /* 三人目の点数 英語、数学 */ }; int i, j, sum = 0, p_sum[NO]; double ave; /* 英語の平均点を求める */ for( i = 0; i < NO; i++ ) { sum += point[i][0]; } ave = (double)sum / NO; printf( "英語の平均点は%5.1f点です\n", ave ); /* 数学の平均点を求める */ for( i = 0; i < NO; i++ ) { sum += point[i][1]; } ave = (double)sum / NO; printf( "数学の平均点は%5.1f点です\n", ave ); /* 個人別の合計点数を求める */ for( i = 0; i < NO; i++ ) { p_sum[i] = 0; } for( i = 0; i < NO; i++ ) { for( j = 0; j < 2; j++ ) { p_sum[i] += point[i][j]; } printf( "出席番号%dの総得点 %d\n", i + 1, p_sum[i] ); } return 0; }
実行結果
英語の平均点は 80.0点です 数学の平均点は166.0点です 出席番号1の総得点 160 出席番号2の総得点 198 出席番号3の総得点 140
配列はこんなところで。
猫でもわかるC言語プログラミング (猫でもわかるプログラミングシリーズ)
posted with amazlet at 10.03.22
粂井 康孝
ソフトバンククリエイティブ
売り上げランキング: 141668
ソフトバンククリエイティブ
売り上げランキング: 141668
おすすめ度の平均:
悪いわけではありませんが猫の好きな私に向いた入門書
困ったもんだ
手前のレビュアー達の書く通り
猫でもわかるかな?