C言語入門

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)