1 C言語入門 第13週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) 2 関数定義の引数と配列 3 講義資料 第3週p.53. 配列のサイズ • sizeof で得られるバイト数 : : a = &a[ -1] 0x?? a = &a[ 0] 0x?? a + 1 = &a[ 1] 0x?? a + 2 = &a[ 2] 0x?? : 0x?? : 0x?? a+N-1 = &a[N-1] 0x?? a+N = &a[N ] 0x?? a+N+1 = &a[N+1] 0x?? : オレンジ色は 未割当のメモリ int a[N]; sizeof(a[0]) = sizeof(int) sizeof(a) = sizeof(int) * N arraysizetest.c int a[10]; // 要素数10のint型の配列変数 printf("%d\n", printf("%d\n", printf("%d\n", printf("%d\n", sizeof(int)); sizeof(a)); sizeof(a[0])); sizeof(a)/sizeof(a[0])); //int型の割り当てバイト数 //配列変数aの割り当てバイト数 //変数a[0]の割り当てバイト数 //配列変数aの要素数 mintty + bash + GNU C : sizeof(int) $ gcc -g arraysizetest.c && ./a 4 40 4 10 4 [1] pp.121-122. 関数定義の引数と配列 • 引数名直後の1次元はポインタ扱いになる 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 pointertest7.c mintty + bash + GNU C int main() { // 0 1 2 3 4 5 6 7 8 9 int a[10] = { 2, 3, 5, 7,11,13,17,19,23,29}; int b[2][5] = { 2, 3, 5, 7,11,13,17,19,23,29}; $ gcc pointertest7.c && ./a pointertest7.c: 関数 ‘main’ 内: pointertest7.c:36:3: 警告: 互換性のないポインタ型から 1 番目の ‘func_with_pointer’ の引数に渡しています [デフォルトで有効] func_with_pointer(b); ^ pointertest7.c:20:6: 備考: expected ‘int *’ but argument is of type ‘int (*)[5]’ void func_with_pointer(int *p) ^ sizeof(a) = 40 sizeof(x) = 8 sizeof(x[0]) = 4 sizeof(p) = 8 sizeof(y) = 8 sizeof(y[0]) = 20 sizeof(y[0][0]) = 4 sizeof(p) = 8 printf("sizeof(a) = %d\n", sizeof(a)); func_with_array1d(a); func_with_pointer(a); func_with_array2d(b); func_with_pointer(b); //a += 1; // It's impossible. Because a is an array. //b += 1; // It's impossible. Because b is an array. return EXIT_SUCCESS; } pointertest7.c 20 21 22 23 void func_with_pointer(int *p) { printf("sizeof(p) = %d\n", sizeof(p)); } 関数引数に与えた int b[2][5] が int (*)[5] 扱い されていることが分かる 5 [1] pp.121-122. 関数定義の引数と配列 • ポインタ扱いなので配列サイズは取れない 4 5 6 7 8 9 pointertest7.c mintty + bash + GNU C void func_with_array1d(int x[10]) { printf("sizeof(x) = %d\n", sizeof(x)); printf("sizeof(x[0]) = %d\n", sizeof(x[0])); x += 1; // x はポインタなので変更出来る } $ gcc pointertest7.c && ./a pointertest7.c: 関数 ‘main’ 内: pointertest7.c:36:3: 警告: 互換性のないポインタ型から 1 番目の ‘func_with_pointer’ の引数に渡しています [デフォルトで有効] func_with_pointer(b); ^ pointertest7.c:20:6: 備考: expected ‘int *’ but argument is of type ‘int (*)[5]’ void func_with_pointer(int *p) ^ sizeof(a) = 40 sizeof(x) = 8 sizeof(x[0]) = 4 sizeof(p) = 8 sizeof(y) = 8 sizeof(y[0]) = 20 sizeof(y[0][0]) = 4 sizeof(p) = 8 pointertest7.c 11 12 13 14 15 16 17 18 void func_with_array2d(int y[2][5]) { printf("sizeof(y) = %d\n", sizeof(y)); printf("sizeof(y[0]) = %d\n", sizeof(y[0])); printf("sizeof(y[0][0]) = %d\n", sizeof(y[0][0])); y += 1; // y はポインタなので変更出来る //y[0] += 1; // y[0] は配列なので変更来ない } sizeof(y[0])は sizeof(int[5])になっている sizeof(int[10]) ではなく sizeof(int*) sizeof(int[2][5]) ではなく sizeof(int(*)[5]) 6 [1] pp.121-122. 関数定義の引数と配列 • ポインタ扱いなのでアドレスが変更出来る 4 5 6 7 8 9 pointertest7.c mintty + bash + GNU C void func_with_array1d(int x[10]) { printf("sizeof(x) = %d\n", sizeof(x)); printf("sizeof(x[0]) = %d\n", sizeof(x[0])); x += 1; // x はポインタなので変更出来る } $ gcc pointertest7.c && ./a pointertest7.c: 関数 ‘main’ 内: pointertest7.c:36:3: 警告: 互換性のないポインタ型から 1 番目の ‘func_with_pointer’ の引数に渡しています [デフォルトで有効] func_with_pointer(b); ^ pointertest7.c:20:6: 備考: expected ‘int *’ but argument is of type ‘int (*)[5]’ void func_with_pointer(int *p) ^ sizeof(a) = 40 sizeof(x) = 8 sizeof(x[0]) = 4 sizeof(p) = 8 sizeof(y) = 8 sizeof(y[0]) = 20 sizeof(y[0][0]) = 4 sizeof(p) = 8 pointertest7.c 11 12 13 14 15 16 17 18 void func_with_array2d(int y[2][5]) { printf("sizeof(y) = %d\n", sizeof(y)); printf("sizeof(y[0]) = %d\n", sizeof(y[0])); printf("sizeof(y[0][0]) = %d\n", sizeof(y[0][0])); y += 1; // y はポインタなので変更出来る //y[0] += 1; // y[0] は配列なので変更来ない } 定義は配列に見えるが実はポインタなので アドレスが変更出来る 最終次元はポインタだが、 y[0] は int[5] 配列だから アドレスの変更が出来ない アンコメントして コンパイル出来ない事を 確認しましょう 7 [1] pp.121-122. 確認: 関数定義の引数と配列 • 以下の個所を変えてコンパイルし確認せよ pointertest7.c 4 5 6 7 8 9 void func_with_array1d(int x[10]) { printf("sizeof(x) = %d\n", sizeof(x)); printf("sizeof(x[0]) = %d\n", sizeof(x[0])); x += 1; // It's possible. Because x is pointer. } int x[10] ではなく int x[20] や int x[] にしても 問題なくコンパイル出来る事を確認せよ pointertest7.c 11 12 13 14 15 16 17 18 int y[2][5] ではなく void func_with_array2d(int y[2][5]) int y[20][5], int y[][5]にしても { printf("sizeof(y) = %d\n", sizeof(y)); 問題なくコンパイル出来る事を確認せよ printf("sizeof(y[0]) = %d\n", sizeof(y[0])); printf("sizeof(y[0][0]) = %d\n", sizeof(y[0][0])); int y[2][10] だと y += 1; // It's possible. Because y is a pointer to an array. コンパイル出来ないことを確認せよ //y[0] += 1; // It's impossible. Because y is an array. } 変数名に一番近い次元はポインタ扱いされるので 要素数が意味を持たなくなっていることを確認せよ 8 [1] pp.121-122. 関数定義の引数と配列 • 引数名直後の1次元は要素数を省略すべき pointertest7.c 4 5 6 7 8 9 void func_with_array1d(int x[10]) { printf("sizeof(x) = %d\n", sizeof(x)); printf("sizeof(x[0]) = %d\n", sizeof(x[0])); x += 1; // It's possible. Because x is pointer. } pointertest7.c 11 12 13 14 15 16 17 18 int x[10] という 引数の宣言は int *x と同じ意味 int y[2][5] という 引数の宣言は int (*y)[5] と同じ意味 無意味な数値は void func_with_array2d(int y[2][5]) { printf("sizeof(y) = %d\n", sizeof(y)); printf("sizeof(y[0]) = %d\n", sizeof(y[0])); printf("sizeof(y[0][0]) = %d\n", sizeof(y[0][0])); y += 1; // It's possible. Because y is a pointer to an array. //y[0] += 1; // It's impossible. Because y is an array. } int *x int (*y)[5] と書くのが最も正確 簡易表記? なるべく 書くべきでない int x[10] より int x[] int y[2][5] より int y[][5] と書く方が実態に合っている 9 [1] pp.121-122. 関数定義の引数と配列 • 関数定義の仮引数では以下の定義は同義 1次元配列 2次元配列 3次元配列 int sub(char s[N]) { // ... } int sub(char s[M][N]) { // ... } int sub(char s[L][M][N]) { // ... } = = = int sub(char s[]) { // ... } int sub(char s[][N]) { // ... } int sub(char s[][M][N]) { // ... } = = = int sub(char *s) { // ... } int sub(char (*s)[N]) { // ... } int sub(char (*s)[M][N]) { // ... } ... ... ... 10 [1] pp.121-122. 関数の引数では 配列の最初の次元は 無視されてポインタ扱いになる 関数定義の引数と配列 • 関数定義の仮引数では以下の定義は同義 1次元配列 2次元配列 3次元配列 int sub(char s[N]) { // ... } int sub(char s[M][N]) { // ... } int sub(char s[L][M][N]) { // ... } = = = int sub(char s[]) { // ... } int sub(char s[][N]) { // ... } int sub(char s[][M][N]) { // ... } = = = int sub(char *s) { // ... } int sub(char (*s)[N]) { // ... } int sub(char (*s)[M][N]) { // ... } ... ... ... 11 並べ替え(SORT) 12 教科書pp.180-183 演習: miniv.c • 要素数n個のint型のデータから最小値を検索する関数 miniv を作成せよ • ただし最小値はn個のデータのうちi番目以降から検索す るものとする • miniv_test.c と共にコンパイルして動作を確認せよ • 引数は以下の順とする • int *v: 最小値を検索するデータへのポインタ • int n: 最小値を検索するデータ(v[])の要素数 • int i: 最小値を検索し始める要素番号(v[i]以降のデー タから最小値を検索する) 訂正2014-07-11 • 戻り値: • 見つけた最小値の要素番号をint型で返す • 要素番号とはv[i]に対するiの数値 「int型で」を追記 13 教科書 pp.85-108. 演習: miniv.c • ヒント n個 ? ? ? ? v[0] v[1] v[2] v[3] ? ... v[n-1] i 番目から n-1 番目までの中から探せばよい ループの基本 無限ループ for (i = 0; i < n; i++) { // i増やしながら0~n-1の範囲でループさせる } for (;;) { // for文()内の式は省略可能 } 教科書pp.184-187 演習: selection_sorti.c • 要素数n個のint型のデータを選択ソートにより小さい 順に並べ替える関数 sorti を作成せよ • sorti_test.c と共にコンパイルして動作を確認せ よ • 引数は以下の順とする • int *v: ソートするデータへのポインタ • int n: ソートするデータ(v[])の要素数 • 戻り値: • なし • ヒント: • 最小値の検索に miniv.c を、値の交換に swapi.c を用いるとループ内は少なくとも2行あれば書ける 14 15 教科書pp.184-187 選択ソート 1. 残りのデータから最小値を検索し、 残りのデータの先頭と最小値を交換 2. 残りのデータがなくなるまで1.から繰り返す 残りデータ ? ? ? ? v[0] v[1] v[2] v[3] ? ... 値の交換 残りデータの先頭 残りデータの最小値 v[n-1] 16 教科書pp.184-187 選択ソート 1. 残りのデータから最小値を検索し、 残りのデータの先頭と最小値を交換 2. 残りのデータがなくなるまで1.から繰り返す ソート済みデータ 残りデータ ? ? ? ? v[0] v[1] v[2] v[3] ? ... v[n-1] 値の交換 残りデータの先頭 残りデータの最小値 17 代表的なソートのアルゴリズム • • • • • 選択ソート、ヒープソート マージソート バブルソート、クイックソート バケットソート etc,,, 18 [1] pp.144-148, 319. 標準ライブラリの qsort 関数 • void qsort(void *base, size_t n, size_t size, int (*cmp)(const void *, const void *)); • 要素サイズsize,要素数nのデータbaseを比較関数 cmpの結果に従い並べ替える • 引数 • • • • base: データへのポインタ n: データの要素数 size: 1要素当りのバイト数 cmp: 比較に用いる関数へのポインタ • 戻り値 • なし 並べ替えの順序 昇順、降順 データ型 int, double, 文字列 void * 型は 任意の方へのポインタ 関数へのポインタ 並べ替えの際、 比較を可換にすることで 汎用性を持たせている。 19 qsort 利用の例 • 比較関数を用意すれば任意データに使える qsort_test1.c 28 29 30 31 int compi(const int *a, const int *b) { return *a - *b; } int 型のデータの並べ替えの例 int 型のデータの比較関数 qsort_test1.c 47 48 49 printiv(v, n); qsort(v, n, sizeof(int), (int (*)(const void *, const void *)) compi); printiv(v, n); mintty + bash + GNU C $ gcc n = ? v[] = v[] = qsort_test1.c && ./a 10 197 22 155 489 71 47 137 364 486 70 22 47 70 71 137 155 197 364 486 489 const void * を 引数とする関数として キャストする必要がある 20 qsort 利用の例 • 比較関数を用意すれば任意データに使える qsort_test2.c 47 48 49 50 配列へのポインタ並べ替えの例 int strcmp_wrapper(const char **a, const char **b) { return strcmp(*a, *b); } 標準ライブラリ関数 strcmp のラッパー関数 qsort_test2.c 67 68 69 printsv(v, n); qsort(v, n, sizeof(char*), (int (*)(const void*,const void*))strcmp_wrapper); printsv(v, n); mintty + bash + GNU C $ gcc qsort_test2.c && ./a n = ? 2 v[0] = "yocchzcmwhmufrdvde" v[1] = "iipfziuhu" v[0] = "iipfziuhu" v[1] = "yocchzcmwhmufrdvde" const void * を 引数とする関数として キャストする必要がある 21 関数へのポインタ • 作り方 • • • • 関数のプロトタイプ宣言を書き写す 関数名を変数名に書き変える 変数名を ( ) で囲む 変数名の前に * を付ける • 例: • 格納したい関数のプロトタイプ宣言 引数名は省略可能 fnc という変数を宣言 戻り値が int int *型の引数を2つ取る 関数のアドレスを 格納出来る • int compi(const int *a, const int *b); • 関数へのポインタの宣言 • int (*fnc)(const int *, const int *); • 関数へのポインタによる関数の呼び出し • (*fnc)(&a, &b); fnc という変数に 格納されたアドレスにある 関数に引数を渡して実行 22 関数へのポインタ • 関数へのポインタの例 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 pointertest8.c mintty + bash + GNU C int compi(const int *a, const int *b) { return *a - *b; } $ gcc pointertest8.c && ./a a = ? 10 b = ? 20 (*fnc)(&a, &b) = -10 int main() { int a, b; int (*fnc)(const int *a, const int *b) = compi; fprintf(stderr, "a = ? "); scanf("%d", &a); fprintf(stderr, "b = ? "); scanf("%d", &b); printf("(*fnc)(&a, &b) = %d\n", (*fnc)(&a, &b)); return EXIT_SUCCESS; } 23 データ構造 24 教科書pp.177-179. スタック構造 • 積み木式のデータ構造 • • • • LIFO(Last-In-First-Out) FILO(First-In-Last-Out) 後入れ先出し 先入れ後出し • push(一番上に格納) • *p に格納 • p--; • pop(一番上から取り出し) • p++; • *p から取出し サブルーチン呼び出し時の ローカル変数作成等で利用されている push 9 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 8 8 p p p 9 9 10 10 10 11 11 11 pop 9 9 Wikipedia / スタック 25 教科書pp.177-179. スタック構造 • 積み木式のデータ構造 • • • • LIFO(Last-In-First-Out) FILO(First-In-Last-Out) 後入れ先出し 先入れ後出し • push(一番上に格納) • *p に格納 • p++; • pop(一番上から取り出し) • p--; • *p から取出し サブルーチン呼び出し時の ローカル変数作成等で利用されている p 0 0 1 1 2 2 push p 0 p 1 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 8 8 9 9 9 10 10 10 11 11 11 2 pop Wikipedia / スタック 26 キュー構造 • 待ち行列構造 • FIFO(First-In-First-Out) • 先入れ先出し • enqueue(先頭に格納) p1 • p2++ • *p2 に格納 • dequeue(末尾から取り出し) • *p1 から取出し • p1++; • リングバッファ • キューの先頭と末尾を繋げ、 輪のようにして使う p2 9 0 0 0 1 1 1 dequeue 2 2 2 3 3 3 p1 p1 4 4 5 5 5 6 6 6 7 7 7 8 8 8 9 p2 9 p2 3 4 9 10 10 10 11 enqueue 11 11 Wikipedia / キュー 27 enqueue 時に はみ出したら 反対側に繋げる キュー構造 • リングバッファ 0 1 0 11 2 1 enqueue dequeue 10 p1 4 2 9 5 3 p2 9 3 3 6 p1 7 8 8 4 p2 9 10 7 5 6 YouTube 等、ストリーミングの先読みバッファ等で利用 11 Wikipedia / リングバッファ 28 二分ヒープ構造 • 要素 i について • 親: (n-1)/2 • 左の子:2n+1 • 右の子:2n+2 • 格納値: 常に親<=子とする 0 0 1 1 2 2 3 3 4 4 5 5 6 • 例: i = 1 7 • 親: 0 • 左の子:3 • 右の子:4 8 9 10 11 ヒープソート等で利用 6 7 8 9 10 11 Wikipedia / 二分ヒープ 29 第10,11,12週の演習の消化 演習 講義資料 第10週 p.62. N進整数文字列の数値化 • 文字列による整数の表現は以下のようになるはず • [符号][N進数ヘッダ]N進数表現の整数 • ここで • 符号: • +, - の何れかで省略可能 • N進数ヘッダ: • 基数が与えられていな場合(基数=0の場合)に利用 • 2,8,16進に対して0b,0,0xの何れかで省略時は10進数扱い • N進数表現の数値: • Nを2~36とすると1桁の数値は0~9,a~z,A~Zの何れか • 例: • 2進数: 0b11(=3), 8進数: 077(=63), 10進数: 99, 16進数: 0xff(=255), 36進数: zz(=1295) • 符号の有無: +0x123, -0x123, 0x123 30 31 講義資料 第10週 p.62. N進整数文字列の数値化 • N進整数の文字列sに対して 基数の 指示が ある? *s は? '-' '+' その他 s++ 符号は-1 Y N *s は? '0' *s は? s++ 'x' s++ 符号は+1 符号の処理 'b' その他 10進 その他 2進 16進 8進 s++ N進数ヘッダの処理 N進整数数値化処理 本体へ 32 講義資料 第10週 p.62. N進整数文字列の数値化 • N進整数の文字列sに対して *s は N進文字 か? N Y *s を数値化 変換済み数値に 符号を付加 N倍した変換済み 数値に加算 s++ 変換済み数値を 返して終了 N進整数数値化処理本体 *sがN進整数1桁として 数値化出来ない場合 エラー処理が必要 講義資料 第10週 p.62. N進整数文字列の数値化 • 以下の関数がそれぞれの機能に該当 • • • • 第12週 p.21.: strtosign.c (符号の処理) 第12週 p.22.: strtobase.c (N進数ヘッダの処理) 第11週 p.30.: base36toint.c (36進整数1桁の数値化) 第11週 p.31.: basetoint.c (N進整数1桁の数値化) • 上記4つの関数を利用すると以下の関数が完成 出来るはず • 第10週 p.62.: strtoi.c 33 講義資料 第12週 p.21.から移動 演習: strtosign.c • 文字列sの先頭1文字を確認し、符号の識別子('-'または'+') の有無に応じて-1,+1の何れかを返す関数 strtosign を作成 せよ • 関数のプロトタイプ宣言はmyfunc_week12.hに作成せよ • strtosign_test.c と共にコンパイルして動作を確認せよ • 引数 • const char *s: 確認する文字列 • char **endp: 未処理の文字列へのポインタを返すために用いる • 戻り値 • 符号の識別子がある場合'-'なら-1、'+'なら+1、それ以外なら+1を int型で返す • endp が NULL 以外の時は以下の値を*endpに返す • 符号の識別子がなかった場合先頭文字(つまりs[0])へのポインタ • 符号の識別子があった場合符号識別子の次の文字(つまりs[1])へのポイ ンタ 34 35 講義資料 第12週 p.21.から移動 演習: strtosign.c • ヒント: • *endp には s[0] または s[1] へのポインタ が入る • s[0] へのポインタは s, s[1] へのポインタ は、s++ した後の s でも良い mintty + bash + GNU C $ gcc strtosign_test.c strtosign.c && ./a s = -5 s = "-5"(0x22a6c0) strtosign(s, &endp) = -1 endp = "5"(0x22a6c1) 講義資料 第12週 p.22.から移動 演習: strtobase.c • 文字列sの先頭2文字を確認し、0b,0,0xなら2,8,16進数、それ 以外なら10進数と判別する関数 strtobase を作成せよ • 関数のプロトタイプ宣言はmyfunc_week12.hに作成せよ • strtobase_test.c と共にコンパイルして動作を確認せよ • 引数 • const char *s : 確認する文字列 • char **endp : 未処理の文字列へのポインタを返すために用いる • 戻り値 • 文字列sの先頭2文字に応じて、2,8,10,16の何れかをint型で返す • endp が NULL 以外の時は以下の値を*endpに返す • 基数識別子(N進数ヘッダ: 0, 0b, 0x)がない場合、先頭文字(つまり s[0])へのポインタ • 基数識別子がある場合、基数識別子の次の文字(つまりs[1]またはs[2]) へのポインタ 36 37 講義資料 第12週 p.22.から移動 演習: strtobase.c • ヒント: • 本資料p.31.のフローチャートを見てみよう mintty + bash + GNU C $ gcc strtobase_test.c strtobase.c && ./a s = 0x123 s = "0x123"(0x22a6c0) strtobase(s, &endp) = 16 endp = "123"(0x22a6c2) 38 講義資料 第11週 p.30.から移動 演習: base36toint.c • 36進数で用いられる「0~9,A~Z,a~z(文字コード: 0x30~0x39, 0x41~0x5a, 0x61~0x7a)」までの文字をint型の数値0~35に変換 する関数 base36toint を作成せよ • 関数のプロトタイプ宣言はmyfunc_week11.hに作成せよ • エラーの際、DEBUGマクロが定義されていたら、標準エラー出力に警告 メッセージを表示せよ • base36toint_test.cと共にコンパイルして動作を確認する事 • 引数 • int c : 数値に変換する文字コード • 戻り値 • cで与えられた文字コードに対応する数値0~35をint型で返す • cが0~9を0~9,A~Zとa~zは共に10~35に変換しそのいずれでもない場 合はエラーとなる • エラーの場合は-1を返す mintty + bash + GNU C $ gcc base36toint_test.c base36toint.c && ./a c = ? z 35 39 講義資料 第11週 p.30.から移動 演習: base36toint.c • ヒント: • cが'0'~'9'である場合、c-'0'とすると、0~9 の数値に変換出来る • cが'a'~'z'の場合、 c-'a'はいくらだろう? • a~z と A~Z は tolower関数または toupper 関数 で大文字か小文字に変換してし まうと大文字小文字の場合分けが必要なくなる mintty + bash + GNU C $ gcc base36toint_test.c base36toint.c && ./a c = ? z 35 講義資料 第11週 p.31.から移動 演習: basetoint.c • 「0~9,A~Z,a~z」の文字をN進数表現の1桁としてint型の数値に変 換する関数 basetointを 作成せよ • 関数のプロトタイプ宣言はmyfunc_week11.hに作成せよ • エラーの際、DEBUGマクロが定義されていたら、標準エラー出力に警告 メッセージを表示せよ • basetoint_test.cと共にコンパイルして動作を確認する事 • 引数 • int c : 数値に変換する文字コード • int base : N進数表現の基数(つまりN=base)、2~36 • 戻り値 • cで与えられた文字コードに対応する数値0~base-1をint型で返す • 変換結果やbaseの値が範囲外の場合はエラーとなる • エラーの場合は-1を返す ヒント: base36toint.c を 用いると簡単に 作成出来る mintty + bash + GNU C $ gcc basetoint_test.c basetoint.c base36toint.c && ./a c = ? z base = ? 10 -1 40 41 講義資料 第10週 p.62.から移動 演習: strtoi.c 訂正2014-07-25 誤: strtoint 正: strtoi • N進整数を表現した文字列をint型の値に変換する関数 strtoint を 作成せよ • 関数のプロトタイプ宣言はmyfunc_week10.hに作成せよ 訂正2014-07-25 • strtoi_test.cと共にコンパイルして動作を確認する事 標準ライブラリと 齟齬があったので • 引数 直しました • const char *s : 変換する文字列 • char **endp : 未処理の文字列へのポインタを返すために用いる • int base : N進数表現の基数(つまりN=base)、2~36 • 戻り値 • 文字列sを基数baseとして数値に変換した結果をint型で返す • 文字列先頭に符号識別子('-','+')がある場合、変換結果の±に反映さ れる • baseに0が与えられた場合、文字列先頭に0b,0,0xがあれば、2,8,16進 数、それ以外なら10進数として扱う。 • endp が NULL 以外の時は以下の値を*endpに返す • 変換出来た最後の文字の次の文字へのポインタ 講義資料 第10週 p.62.から移動 演習: strtoi.c ヒント: strtosign.c, strtobase.c, basetoint.c を利用すると比較的簡単に作 成できる mintty + bash + GNU C $ gcc strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c && ./a s = -0xff base = 0 s = "-0xff"(0x22a6c0) str(s, &endp, base) = -255 endp = ""(0x22a6c5) 42 43 参考文献 • [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準 拠、共立出版(1989)
© Copyright 2025 ExpyDoc