Presentation is loading. Please wait.

Presentation is loading. Please wait.

配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題

Similar presentations


Presentation on theme: "配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題"— Presentation transcript:

1 配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題
第9章 ポインタ 配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題

2 ポインタ変数(ex_9_3_5.c) #include <stdio.h>
#define PRINT(x,y,z) printf(#x"= %d, "#y"= %d, "#z"= %d\n",x,y,z); int main(void) { int x = 1, y = 100; int *p; PRINT(x,y,p); p = &x; PRINT(x,y,p); y = *p; PRINT(x,y,p); p = &y; PRINT(x,y,p); *p = 0; PRINT(x,y,p); PRINT(&x,&y,&p); return 0; } x=1, y=100, p= x=1, y=100, p= x=1, y=1, p= x=1, y=1, p= x=1, y=0, p= &x= , &y= , &p=

3 ポインタ変数(ex9_3_5.c) int x = 1, y = 100; int *p; p = &x; y = *p; p = &y;
100 1 p

4 9.4 配列変数とポインタ (再掲) 配列(array)とは int a[5]={11,12,13,14,15};
9.4 配列変数とポインタ (再掲) 配列(array)とは int a[5]={11,12,13,14,15}; ← プログラム例9.4.1 と宣言すると、メモリ上に右図のように並んだ int 型変数 5 個分の領域が確保され、その領域が a と名付けられる。 各々の配列要素には指定された値が入る。 配列要素 11 a[0] 12 a[1] 13 14 a[3] 15 a[2] a[4] 添字

5 9.4 配列変数とポインタ (再掲) int *a_p; a_p = &a[0]; C では、配列変数はポインタ変数
9.4 配列変数とポインタ (再掲) C では、配列変数はポインタ変数 を用いてアクセスすることが多い 11 1000 1004 1008 1012 1016 a[0] &a[0] は1000、 &a[1] は1004 12 a[1] 13 a[2] 14 int *a_p; a_p = &a[0]; a[3] 15 a[4] a_p は、整数型変数のアドレスが 入るポインタ型変数で(1行目)、 配列 a の先頭の要素の番地を 代入する(2行目) 1000 a_p

6 配列変数の正体 コンパイラは a[i] を *(a+i) と解釈 &a[i] = &(*(a+i)) = a+i 特に、 &a[0] = a
11 1000 1004 1008 1012 1016 a[0] 12 a[1] 13 配列 a の名前自体が配列の先頭要素の番地を表すポインタとみなせる a[2] 14 a[3] 15 ただし、a が a_p のようなポインタ変数として独立に存在するわけではない a[4] 実は、 a[i] = *(a+i) = *(i+a) = i[a] が成り立つ。→ ex9_4_1a.c

7 ポインタと配列変数の関係 ex9_4_1a.c #include <stdio.h> int main(void) {
int i, a[]={11,12,13,14,15}; printf(" a[i]= "); for (i=0; i<5; i++) printf("%d ",a[i]); putchar('\n'); printf("*(a+i)= "); for (i=0; i<5; i++) printf("%d ",*(a+i)); putchar('\n'); printf(" i[a]= "); for (i=0; i<5; i++) printf("%d ",i[a]); putchar('\n'); printf("\n &a=%u, a=%u, *a=%d\n",&a, a, *a); } ex9_4_1a.c

8 みなしポインタaの中身(スタック領域のアドレス)
実行結果(静的確保) Z:\nyumon2>ex9_4_1a a[i]= *(a+i)= i[a]= &a= , a= , *a=11 aが指し示す先のデータ = a[0] みなしポインタaのアドレス (スタック領域) みなしポインタaの中身(スタック領域のアドレス) a[0] a[1] 11 12 アドレスがループしており、配列名aはポインタ変数ではない

9 動的確保の場合のポインタと配列 ex9_4_1b.c #include <stdio.h> #define N 5
int main(int argc, char *argv[]) { int i, n=N, *a; if (argc > 1) sscanf(argv[1], "%d", &n); if ((a = (int *)calloc(n, sizeof(int))) == NULL) { perror("I can't allocate a[]."); abort(); } for (i=0; i<n; i++) a[i]=11+i; printf(" a[i]= "); for (i=0; i<n; i++) printf("%d ", a[i]); putchar('\n'); printf("\n &a=%u, a=%u, *a=%d\n",&a, a, *a); ex9_4_1b.c

10 ポインタ変数aの中身(ヒープ領域のアドレス)
実行結果(動的確保) Z:\nyumon2>ex9_4_1b a[i]= &a= , a= , *a=11 aが指し示す先のデータ = a[0] ポインタ変数a のアドレス (スタック領域) ポインタ変数aの中身(ヒープ領域のアドレス) a a[0] a[1] 11 動的確保した配列a[]の実体は ヒープ領域に確保 12

11 ポインタ配列 ポインタを要素に持つ配列 文字列配列や2次元配列で用いる int *a[N]; char *argv[]
int *a[0],*a[1],...,*a[N-1]; char *argv[] コマンドラインの文字列配列 Z:\nyumon2>ex_9_4_1b 10 argv[0] = "ex_9_4_1b" argv[1] = "10"

12 2次元配列の静的確保(自動変数) ex6_7_2c.c スタック領域に確保 #include <stdio.h>
#define N 4 int main(void) { int i, j, k=0; int a[N][N]; for (i = 0; i < N; i++) for (j = 0; j < N; j++) a[i][j] = ++k; printf("&a=%u, a=%u, *a=%u, **a=%d\n", &a, a, *a, **a); return 0; } ex6_7_2c.c スタック領域に確保

13 2次元配列の静的確保(静的変数) ex6_7_2d.c データ領域に確保 #include <stdio.h>
#define N 4 int main(void) { int i, j, k=0; static int a[N][N]; for (i = 0; i < N; i++) for (j = 0; j < N; j++) a[i][j] = ++k; printf("&a=%u, a=%u, *a=%u, **a=%d\n", &a, a, *a, **a); return 0; } ex6_7_2d.c データ領域に確保

14 2次元配列の静的確保(大域変数) ex6_7_2e.c データ領域に確保 #include <stdio.h>
#define N 4 int a[N][N]; int main(void) { int i, j, k=0; for (i = 0; i < N; i++) for (j = 0; j < N; j++) a[i][j] = ++k; printf("&a=%u, a=%u, *a=%u, **a=%d\n", &a, a, *a, **a); return 0; } ex6_7_2e.c データ領域に確保

15 実行結果(静的確保) Z:\nyumon2>ex6_7_2c &a= , a= , *a= , **a=1 Z:\nyumon2>ex6_7_2d &a= , a= , *a= , **a=1 Z:\nyumon2>ex6_7_2e &a= , a= , *a= , **a=1 スタック領域 データ領域 (静的領域) データ領域 1 1 1 2 2 2

16 2次元配列の動的確保(1) ex6_7_2f.c #include <stdio.h>
#include <stdlib.h> #define N 4 int main(void) { int i, j, k=0; int *a[N]; for (i = 0; i < N; i++) { a[i] = (int *)calloc(N, sizeof(int)); for (j = 0; j < N; j++) a[i][j] = ++k; } printf("&a=%u, a=%u, *a=%u, **a=%d\n", &a, a, *a, **a); return 0; ex6_7_2f.c スタック領域にポインタ配列 ヒープ領域に確保

17 2次元配列の動的確保(2) ex6_7_2g.c #include <stdio.h>
#include <stdlib.h> #define N 4 int main(void) { int i, j, k=0; int **a; a = (int **)calloc(N, sizeof(int *)); for (i = 0; i < N; i++) { a[i] = (int *)calloc(N, sizeof(int)); for (j = 0; j < N; j++) a[i][j] = ++k; } printf("&a=%u, a=%u, *a=%u, **a=%d\n", &a, a, *a, **a); return 0; ex6_7_2g.c スタック領域にポインタのポインタ ヒープ領域に ポインタ配列 ヒープ領域に確保

18 2次元配列の動的確保(3) ex6_7_2h.c #include <stdio.h>
#include <stdlib.h> #define N 4 #define IDX(i,j) (i)*N+(j) int main(void) { int i, k=0; int *a; a = (int *)calloc(N*N, sizeof(int)); for (i = 0; i < N*N; i++) a[i] = ++k; printf("&a=%u, a=%u, *a=%u, **a=%d\n", &a, a, *a, **a); printf("%d, %d, %d\n",a[IDX(1,1)],a[IDX(2,2)],a[IDX(3,3)]); return 0; } ex6_7_2h.c スタック領域にポインタ ヒープ領域に確保

19 実行結果(動的確保) スタック a[0] a[1] Z:\nyumon2>ex6_7_2f &a= , a= , *a= , **a=1 Z:\nyumon2>ex6_7_2g &a= , a= , *a= , **a=1 Z:\nyumon2>ex6_7_2h &a= , a= , *a=1 6, 11, 16 ヒープ **a 1 2 ヒープ スタック **a 1 a スタック 2 ヒープ a *a 1 *a 2

20 時間計測:ミリ秒単位(time2.c) 再掲 #include <stdio.h>
#include <stdlib.h> #include <windows.h> #pragma comment(lib,"winmm.lib") int main(void) { int i, N=100000; int t1, t2; t1 = timeGetTime(); for (i=0; i<N; i++) printf(" %d", rand()%6 + 1); printf("\n"); t2 = timeGetTime(); printf("経過時間: %d msec\n", t2-t1); return 0; } ← 乱数用ヘッダファイル ← Windows用ヘッダファイル ← 音楽用Windowsライブラリ 計測開始 計測終了 実行時間

21 「エラトステネスの篩」改良版(prime2.c)
配列 a をデータ領域または動的に確保する(char 型にすると上限が4倍になる) 動的確保の場合、コマンドラインオプションで素数の上限 n を入力できるようにする (n-1000)から上の素数を(整数10桁で)表示 素数の個数を数えあげて表示 経過時間を計測して表示 n のデフォルト値は1億または10億とする 5

22 エラトステネスの篩(ふるい)改良版 t1 100,000,000 or 500,000,000 コマンドラインから n の入力
エラー処理つき配列 a[ ] 確保&初期化 ←callocで動的確保 j ← i+i i の倍数 を除く a[j] ← 1 !a[i] i=2,...,N/2  j≦N j ← j+i prime2 k ← 0 k ← k+1 !a[i] i=2,...,N  i の10桁出力 i > n-1000 後ろの素数を出力 素数の数 k の出力 t2 経過時間(t2-t1)の出力

23 第1回 レポート(必須) 課題:「エラトステネスの篩」改良版(prime2.c) 提出期限:2010年10月29日(金) 12:50
(コマンドライン入力&動的確保) 提出期限:2010年10月29日(金) 12:50 提出場所:ネットワーク実験室(1)の入口近くの箱 今回のレポートでは以下の項目をいれること。 学籍番号、氏名 課題名 ソースリスト 実行結果 感 想(5行以上) レポートのファイルは 保存しておくこと レポートサンプルを参照のこと

24 本日のパズル 次のプログラムは何が出力されるか?
#define PRINT3(x,y,z) printf("%d\t%d\t%d\n",x,y,z) main() { int x, y, z; x = y = z = 1; ++x || ++y && ++z; PRINT3(x,y,z); ++x && ++y || ++z; PRINT3(x,y,z); ++x && ++y && ++z; PRINT3(x,y,z); } 1 2 3


Download ppt "配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題"

Similar presentations


Ads by Google