Download : sample-001.c ( utf8 版 )
/* * 2016/11/18 sample-001.c * * ポインター型変数の利用 * */ #include <stdio.h> #include <malloc.h> /* * 利用方法 * コンパイル * cc -o sample-001.exe sample-001.c * 実行 * ./sample-001.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int v; /* 整数型の変数を確保 */ int *p = &v; /* ポインター型変数 p に v のポインター値を代入する */ /* *p は、変数 v と全く同じに振る舞う */ *p = 1; printf ( "*p = %d\n", *p ); printf ( "v = %d\n", v ); *p = *p + 10; printf ( "*p = %d\n", *p ); printf ( "v = %d\n", v ); return 0; }
$ ./sample-001.exe *p = 1 v = 1 *p = 11 v = 11 $
Download : sample-002.c ( utf8 版 )
/* * 2016/11/18 sample-002.c * * 動的領域の確保 (単純変数) * */ #include <stdio.h> #include <malloc.h> /* calloc/free を利用する場合に必要 */ /* * 利用方法 * コンパイル * cc -o sample-002.exe sample-002.c * 実行 * ./sample-002.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int *p; /* 整数型変数の領域を 1 つ分確保 */ p = (int *)calloc ( 1, sizeof(int) ); if ( p == NULL ) { /* メモリの確保に失敗した場合は NULL が返る */ printf ( "整数領域のメモリ確保に失敗しました。\n" ); } else { /* 以下は、*p を普通の整数型変数と同じ様に利用できる */ *p = 1; printf ( "*p = %d\n", *p ); *p = *p + 10; printf ( "*p = %d\n", *p ); /* 動的に確保したメモリは最後に必ず、free で解放する */ free ( p ); } return 0; }
$ ./sample-002.exe *p = 1 *p = 11 $
Download : sample-003.c ( utf8 版 )
/* * 2016/11/18 sample-003.c * * ポインター型変数の利用(2) * */ #include <stdio.h> /* * 利用方法 * コンパイル * cc -o sample-003.exe sample-003.c * 実行 * ./sample-003.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int a[10]; /* 整数型の配列を確保 */ int *p = a; /* ポインター型変数 p に a の先頭の要素のポインター値を代入する */ /* p は、配列名 a と全く同じに振る舞う */ p[2] = 1; printf ( "p[2] = %d\n", p[2] ); printf ( "a[2] = %d\n", a[2] ); p[4] = p[2] + 10; printf ( "p[4] = %d\n", p[4] ); printf ( "a[4] = %d\n", a[4] ); return 0; }
$ ./sample-003.exe p[2] = 1 a[2] = 1 p[4] = 11 a[4] = 11 $
Download : sample-004.c ( utf8 版 )
/* * 2016/11/18 sample-004.c * * 動的領域の確保 (配列) * */ #include <stdio.h> #include <malloc.h> /* * 利用方法 * コンパイル * cc -o sample-004.exe sample-004.c * 実行 * ./sample-004.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int *p; /* 整数型変数の領域を 10 つ分確保 */ p = (int *)calloc ( 10, sizeof(int) ); if ( p == NULL ) { /* メモリの確保に失敗した場合は NULL が返る */ printf ( "整数領域のメモリ確保に失敗しました。\n" ); } else { /* 以下は、p を普通の整数型配列名と同じ様に利用できる */ p[2] = 1; printf ( "p[2] = %d\n", p[2] ); p[4] = p[2] + 10; printf ( "p[4] = %d\n", p[4] ); /* 動的に確保したメモリは最後に必ず、free で解放する */ free ( p ); } return 0; }
$ ./sample-004.exe p[2] = 1 p[4] = 11 $
Download : sample-005.c ( utf8 版 )
/* * 2016/11/18 sample-005.c * * 不定長の入力 (最大値が存在) * */ #include <stdio.h> /* * 利用方法 * コンパイル * cc -o sample-005.exe sample-005.c * 実行 * ./sample-005.exe */ #define MAX_OF_INPUT_SIZE 10 /* 入力できるデータ数 */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int array[MAX_OF_INPUT_SIZE]; /* 整数型の配列を確保 */ int n; /* 入力される整数値の個数 */ int i; printf ( "データ数を入力してください : " ); scanf ( "%d", &n ); if ( ( 0 <= n ) && ( n < MAX_OF_INPUT_SIZE ) ) { for ( i = 0; i < n; i++ ) { printf ( "%d 番目の数値を入力してください : ", i + 1 ); scanf ( "%d", &array[i] ); } printf ( "入力された内容は以下の通りです。\n" ); for ( i = 0; i < n; i++ ) { printf ( "%d 番目の数値は %d です。\n", i + 1, array[i] ); } } else { printf ( "データ数(%d)が異常です。\n", n ); } return 0; }
5 453 32 -239 0 294
$ ./sample-005.exe < sample-005.in データ数を入力してください : 5 1 番目の数値を入力してください : 453 2 番目の数値を入力してください : 32 3 番目の数値を入力してください : -239 4 番目の数値を入力してください : 0 5 番目の数値を入力してください : 294 入力された内容は以下の通りです。 1 番目の数値は 453 です。 2 番目の数値は 32 です。 3 番目の数値は -239 です。 4 番目の数値は 0 です。 5 番目の数値は 294 です。 $
Download : sample-006.c ( utf8 版 )
/* * 2016/11/18 sample-006.c * * 不定長の入力 (動的に領域を確保) * */ #include <stdio.h> #include <malloc.h> /* * 利用方法 * コンパイル * cc -o sample-006.exe sample-006.c * 実行 * ./sample-006.exe */ /* * main 関数 */ int main ( int argc, char *argv[] ) { int *parray; /* 整数型の配列の先頭 */ int n; /* 入力される整数値の個数 */ int i; printf ( "データ数を入力してください : " ); scanf ( "%d", &n ); if ( 0 <= n ) { if ( ( parray = (int *)calloc( n, sizeof(int) ) ) != NULL ) { for ( i = 0; i < n; i++ ) { printf ( "%d 番目の数値を入力してください : ", i + 1 ); scanf ( "%d", &parray[i] ); } printf ( "入力された内容は以下の通りです。\n" ); for ( i = 0; i < n; i++ ) { printf ( "%d 番目の数値は %d です。\n", i + 1, parray[i] ); } free ( parray ); } else { printf ( "整数領域のメモリ確保に失敗しました。\n" ); } } else { printf ( "データ数(%d)が異常です。\n", n ); } return 0; }
15 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
$ ./sample-006.exe < sample-006.in データ数を入力してください : 15 1 番目の数値を入力してください : 1 2 番目の数値を入力してください : 2 3 番目の数値を入力してください : 3 4 番目の数値を入力してください : 4 5 番目の数値を入力してください : 5 6 番目の数値を入力してください : 6 7 番目の数値を入力してください : 7 8 番目の数値を入力してください : 8 9 番目の数値を入力してください : 9 10 番目の数値を入力してください : 0 11 番目の数値を入力してください : 1 12 番目の数値を入力してください : 2 13 番目の数値を入力してください : 3 14 番目の数値を入力してください : 4 15 番目の数値を入力してください : 5 入力された内容は以下の通りです。 1 番目の数値は 1 です。 2 番目の数値は 2 です。 3 番目の数値は 3 です。 4 番目の数値は 4 です。 5 番目の数値は 5 です。 6 番目の数値は 6 です。 7 番目の数値は 7 です。 8 番目の数値は 8 です。 9 番目の数値は 9 です。 10 番目の数値は 0 です。 11 番目の数値は 1 です。 12 番目の数値は 2 です。 13 番目の数値は 3 です。 14 番目の数値は 4 です。 15 番目の数値は 5 です。 $
#include <stdio.h> void subfunc( int a[] ) { /* 関数の仮引数を、配列として宣言できる(サイズは不要[無意味]) */ /* 渡された「位置情報(ポインター)」を利用して、 配列の要素を「間接的に」参照 */ /* 添え字を利用して、配列の要素の値が読み出せる */ printf ( "a[0] = %d\n", a[0] ); printf ( "a[1] = %d\n", a[1] ); a[2] = a[0] + a[1]; /* 配列の要素の値を変更可能 */ /* これは、関数の呼び出し元の配列の要素の 値を変更している */ /* 呼び出す側の関数が、呼び出される関数の引数に配列名を 指定することにより、この二つの関数(呼び出す側と呼び出される側) で、配列を「共有」できる */ } int main(int argc, char *argv[]) { int array[10]; array[0] = 10; array[1] = 20; /* 値を設定する */ subfunc ( array ); /* 配列名を関数の引数として渡す */ /* 配列の先頭の要素の「位置情報(ポインター値)」がコピーされて 渡される */ /* 配列(の要素)のコピーが渡されるわけではない */ printf ( "array[2]=%d\n", array[2] ); /* subfunc の中で、設定した値が反映されている */ return 0; }
/* メモリモデル */ #include <stdio.h> #include "s_memory.h" int main(int argc, char *argv[]) { /* 変数名 番地 int a; -> 100 int b; -> 101 int c; -> 102 */ set_memory_value_at ( 100, 10 ); /* 100 番地に、10 を設定 */ /* a = 10 */ set_memory_value_at ( 101, 20 ); /* 101 番地に、20 を設定 */ /* b = 20 */ set_memory_value_at ( 102, get_memory_value_at ( 100 ) + get_memory_value_at ( 101 ) ); /* 102 番地に、100 番地と 101 番地の内容の和をいれる */ /* c = a + b */ printf ( "memory[102]=%d\n", get_memory_value_at ( 102 ) ); /* 102 番地の内容を表示 */ /* printf ( "%d\n", c ) */ }
/* メモリモデル */ #include <stdio.h> #include "s_memory.h" void addnum ( int addr3, int addr1, int addr2 ) { set_memory_value_at ( addr3, get_memory_value_at ( addr1 ) + get_memory_value_at ( addr2 ) ); /* addr3 番地に、addr1 番地と addr2 番地の内容の和をいれる */ /* c = a + b */ } int main(int argc, char *argv[]) { /* 変数名 番地 int a; -> 100 int b; -> 101 int c; -> 102 */ set_memory_value_at ( 100, 10 ); /* 100 番地に、10 を設定 */ /* a = 10 */ set_memory_value_at ( 101, 20 ); /* 101 番地に、20 を設定 */ /* b = 20 */ addnum ( 102, 100, 101 ); /* 番地を引数に渡すことによって、 その番地の内容を参照したり、 その番地の内容を変更したりできる => 配列名を関数の引数に渡すのとよくにている */ printf ( "memory[102]=%d\n", get_memory_value_at ( 102 ) ); /* 102 番地の内容を表示 */ /* printf ( "%d\n", c ) */ }
/* メモリモデル 番地を指定して、値を取り出したり、設定できる それしかできないプリミティブ(原子的)な操作 これの組み合わせで、C 言語の代入などの操作が実現できる */ #include <stdio.h> #include "s_memory.h" void addnumarray ( int addr3, int addr1, int addr2 ) { set_memory_value_at ( addr3, get_memory_value_at ( addr1 ) + get_memory_value_at ( addr2 ) ); /* addr3 番地に、addr1 番地と addr2 番地の内容の和をいれる */ /* c[0] = a[0] + b[0] */ set_memory_value_at ( addr3 + 1, /* 先頭の番地がわかれば、次の番地も判る */ get_memory_value_at ( addr1 + 1 ) + get_memory_value_at ( addr2 + 1 ) ); /* addr3 + 1 番地に、addr1 + 1 番地と addr2 +1 番地の内容の和をいれる */ /* c[1] = a[1] + b[1] */ } int main(int argc, char *argv[]) { /* 変数名 番地 int a[2]; -> 100, 101 int b[2]; -> 102, 103 int c[2]; -> 104, 105 */ set_memory_value_at ( 100, 10 ); /* 100 番地に、10 を設定 */ /* a = 10 */ set_memory_value_at ( 101, 20 ); /* 101 番地に、20 を設定 */ /* b = 20 */ set_memory_value_at ( 102, 30 ); /* 102 番地に、30 を設定 */ /* a = 10 */ set_memory_value_at ( 103, 40 ); /* 101 番地に、20 を設定 */ /* b = 20 */ addnumarray ( 104, 100, 102 ); /* 番地を引数に渡すことによって、 その番地の内容を参照したり、 その番地の内容を変更したりできる => 配列名を関数の引数に渡すのとよくにている */ printf ( "memory[104]=%d\n", get_memory_value_at ( 104 ) ); /* 104 番地の内容を表示 */ /* printf ( "%d\n", c[0] ) */ printf ( "memory[105]=%d\n", get_memory_value_at ( 105 ) ); /* 105 番地の内容を表示 */ /* printf ( "%d\n", c[1] ) */ }
#include <stdio.h> int main(int argc, char *argv[]) { int array[10]; char str[10]; array[0] = 10; /* 配列 array の先頭要素に 10 を代入 */ printf ( "array[0] = %d\n", array[0] ); /* 先頭の要素の内容(値)が表示される */ printf ( "*array = %d\n", *array ); /* 先頭の要素の内容(値)が表示される */ *array = 20; /* array[0] と *array はどこでも、交換可能 */ printf ( "*array = %d\n", *array ); printf ( "array[0] = %d\n", array[0] ); /* 一般に、 array[n] と *(array + n) も交換可能 */ array[3] = 100; printf ( "*(array+3) = %d\n", *(array + 3) ); /* *(array+3) <-> array[3] array+3 <-> array[3] の場所同じ >1 byte< array +-------+ 0x7fffbf29f860 array[0] | | sizeof(int)=4 +-------+ | | +-------+ | | +-------+ | | +-------+ 0x7fffbf29f860+4=0x7fffbf29f864 array[1] | | +-------+ | | +-------+ | | +-------+ | | +-------+ 0x7fffbf29f860+8=0x7fffbf29f868 array[2] | | +-------+ | | +-------+ | | +-------+ | | +-------+ 0x7fffbf29f860+c=0x7fffbf29f86c array[3] | | +-------+ | | +-------+ | | +-------+ | | +-------+ */ printf ( "array = %p\n", array ); printf ( "array + 3 = %p\n", array + 3 ); printf ( "str = %p\n", str ); printf ( "str + 3 = %p\n", str + 3 ); return 0; }
#include <stdio.h> void sub ( int a[] ) { *a = *a * 2; /* 配列 a の先頭の要素を二倍する */ } int main(int argc, char *argv[]) { int array[10]; /* array[0] ? array[9] までの 10 個の変数の宣言 array は、 array[0] のポインター値を表す */ int svar; /* svar のポインター値は ? -> &svar によって、単純変数 svar のポインター値が取り出せる 単純変数 サイズ 1 の配列 宣言 svar onearray[1] 操作 svar onearray[0] / *onearray ポインター値 &svar onearray *&svar <-> svar *onearray */ int onearray[1]; /* 1 つの変数 onearray[0] を宣言 -> onearray は、onearray[0] のポインター値 */ array[0] = 10; sub ( array ); printf ( "array[0] = %d\n", array[0] ); onearray[0] = 10; sub ( onearray ); printf ( "onearray[0] = %d\n", onearray[0] ); svar = 10; sub ( &svar ); printf ( "svar = %d\n", svar ); /* scanf の時に、変数に & を付ける 今まで : 「ルール」としてきた 今回 : & をつけたのは、ポインター値を渡すため scanf は、引数で与えられた、ポインター値から 「*」を付けて、間接参照する事により、 変数の値を書き換えていた */ return 0; }
Download : 20161125-01.c ( utf8 版 )
/* * 課題 CNAME-01 * * 2016/11/25 FILENAME * * 動的なメモリの確保 * キーボードより正の整数を幾つか入力して、その要素が入った配列を返す * 0 以下の整数が入力されたら、終了とする * 配列のサイズは、正の整数の個数 + 1 とし、最後の要素には 0 を入れる */ /* * 利用方法 * コンパイル * cc -I ~/c/include -o BASENAME.exe FILENAME * 実行 * ./BASENAME.exe */ #include <stdio.h> #include <malloc.h> /* calloc/free を利用するので必要 */ /* * read_n_integers */ int *read_n_integers( int size ) { int num; /* キーボードから入力された数値を保存する */ int *value; /* 確保された配列の先頭要素へのポインター */ printf ( "正の整数値を入力してください(0 以下だと入力を終了します):" ); scanf ( "%d", &num ); if ( num <= 0 ) { /* 入力が全部終ったので、配列を作成する */ /* 配列のサイズは、引数で指定された個数 + 1 となる */ if ( ( value = (int *)calloc ( size + 1, sizeof ( int ) ) ) != NULL ) { /* 動的メモリは取り出せるとは限らないので、結果をチェック */ value[ size ] = 0; /* 最後の要素として 0 を代入 */ } /* else {} */ /* NULL が帰った場合は、そのまま、値として返す */ } else { /* 入力が終っていないので、更に、値を読むために再帰呼び出し */ if ( ( value = read_n_integers( size + 1 ) ) != NULL ) { /* 結果が NULL でなければ、配列が作られている */ /* size 番目の要素を配列に記録 */ /* ** この部分を完成させなさい */ } /* else {} */ /* NULL が帰った場合は、そのまま、値として返す */ } /* いずれの場合でも value を返す */ /* ** この部分を完成させなさい */ } /* * main */ int main ( int argc, char *argv[] ) { int *array; /* n 個数の要素をもつ配列の先頭をもつ */ int i; /* read_n_integers を呼び出して、n 個の整数値を入力する */ /* 引数には、入力済のデータ数を指定するので、最初は 0 を指定する */ if ( ( array = read_n_integers( 0 ) ) != NULL ) { /* read_n_integers は、NULL を返す可能性がある */ /* 入力された要素を画面に出力 */ for ( i = 0; array[i] > 0; i++ ) { printf ( "%d th data = %d\n", i, array[i] ); } /* malloc/calloc で確保したメモリは、必ず free で解放する */ /* ** この部分を完成させなさい */ } /* else {} */ /* NULL の場合はエラーなので、何もしない */ return 0; }
12 34 5 6 90 -1
$ ./20161125-01-QQQQ.exe 正の整数値を入力してください(0 以下だと入力を終了します):12 正の整数値を入力してください(0 以下だと入力を終了します):34 正の整数値を入力してください(0 以下だと入力を終了します):5 正の整数値を入力してください(0 以下だと入力を終了します):6 正の整数値を入力してください(0 以下だと入力を終了します):90 正の整数値を入力してください(0 以下だと入力を終了します):-1 0 th data = 12 1 th data = 34 2 th data = 5 3 th data = 6 4 th data = 90 $