第6章 配列

第13章 文字の取り扱い方
13.1
13.2
13.3
13.4
13.5
文字と文字型変数
文字列
文字型配列への文字列の代入
キーボードからの文字列の入力
文字型配列と関数
13.1 文字と文字型変数

これまでに扱ったのは数値型変数
整数型
int : -2147483648 〜 2147483647
 浮動小数点型
これらの他に、short int, long int,
long double, また、unsigned がつ
float : 10-38 〜 1038
くものなどがある。
詳細はプログラミング演習Ⅰの資料を参照
double : 10-308 〜 10308


プログラミングでは文字も扱う場合が多い

文字型 char を用いる
http://www.ced.is.utsunomiya-u.ac.jp/lecture/2008/prog/p1/kadai1/variable.html
文字型変数に文字を代入
プログラム例 13.1.1 より抜粋
int main(void)
文字型変数 x を宣言
{
char x;
1文字はシングル
代入文でOK
x = 'H';
クォート(')でくくる
printf("%c¥n", x);
return 0;
}
1文字用の書式指定子
1文字 = 1バイトの数値
8ビット(0~255)
p.180, 表A.3
ASCIIコード
文字型変数に文字を代入
プログラム例 13.1.1 の改変
#include <stdio.h>
int main(void)
{
char x, y, z, u, v, w;
character
decimal
x = 'H'; y = 'a'; z = 'p';
%c 文字
%d 10進数
u = 'p'; v = 'y'; w = '!';
printf("%c%c%c%c%c%c¥n", x, y, z, u, v, w);
printf("%d %d %d %d %d %d¥n", x, y, z, u, v, w);
printf("%x %x %x %x %x %x¥n", x, y, z, u, v, w);
return 0;
%x 16進数
}
hexadecimal
13.2 文字列
複数個の文字(文字列、string という)は、各要素が char 型
の配列として扱う。文字列はダブルクォート(")でくくること。
文字列の最終文字の次に、文字列の最後を示す \0 が入る。
プログラム例 13.2.2 より抜粋
文字列 William Shakespeare を配列変数 x に代入
int main(void)
{
char x[20] = {"William Shakespeare"};
19字だが、
printf("%s¥n", &x[0]);
20字分用意
return 0;
}
文字列用の書式指定子
ここで、配列変数 x の先頭番地を指定すると、
x のすべてを表示する。
ただし最後の ¥O は表示しない
文字列は配列に格納される
1000
1001
1002
・
・
・
x[0]
x[1]
x[2]
x[3]
x[4]
x[18]
x[19]
W
i
l
l
i
e
\0
int main(void)
{
char x[]={"William
Shakespeare"};
printf("%s¥n", x);
return 0;
}
&x[0] は 単に x でよい
文字列の終わり
正体は1バイトの数字の0
13.2 文字列
配列の長さ < 文字列の長さ の場合にどうなるか、試してみよう
プログラム例 13.2.2 の改変
#include <stdio.h>
ここの値を変えて、配列の
長さを1つずつ減らしていく
int main(void)
{
char x[??] = {"William Shakespeare"};
printf("%s¥n", x);
return 0;
}
文字列の正体
プログラム例 13.2.2 の改変
#include <stdio.h>
int main(void)
{
int i;
char x[20] = {"William Shakespeare"};
printf("%s¥n", x);
for (i = 0; i < 20; i++)
printf(" %d", x[i]);
printf("\n");
return 0;
}
この出力結果を
p.180、表A.3
のASCIIコード
と比べてみよう
13.2 文字列
複数の文字列を扱う場合 → 2次元配列を使う
プログラム例 13.2.4
#include <stdio.h>
int main(void)
{
char name[3][20] = {"William Shakespeare",
"William Clinton",
"William Henry"};
int i;
for (i = 0; i < 3; i++)
printf("%s¥n", name[i]);
printf("\n");
return 0;
}
13.3 文字列の代入


配列(文字列)に代入文は使えない
文字列処理関数 (string.h を include)

strcpy(char *dst, char *src)
string copy (ストリング・コピー)の略
引数の順序は代入文 dst ← src に対応

引数はポインタ(文字型配列の名前)


13.3 文字列の代入
プログラム例 13.3.2
#include <stdio.h>
#include <string.h>
int main(void)
入れ物は2つ用意
{
a ← "William Shakespeare"
char a[31], b[31];
strcpy(a, "William Shakespeare");
printf("%s\n", a);
strcpy(b, a);
文字列の代入
b ← a
printf("%s¥n", b);
return 0;
}
a
William Shakespeare
b
William Shakespeare
実際にコピー
13.3 文字列の代入(もどき)
プログラム例 13.3.2 の改変
#include <stdio.h>
int main(void)
入れ物は1つ
a ← "William Shakespeare"
{
char a[] = "William Shakespeare", *b;
文字型ポインタを用意
printf("%s\n", a);
b = a;
b ← a
アドレスデータの代入
printf("%s¥n", b);
データは共用
return 0;
}
a
b
William Shakespeare
13.4 キーボードからの文字列の入力
プログラム例 13.4.2
101 は文章を読み込むのに
十分と考えられる適当な数。
特別な意味はない
#include <stdio.h>
int main(void)
{
char sentence[101];
printf("文章を入力して下さい");
gets(sentence);
キーボードから文字列を受け取り、
puts(sentence);
の配列変数 sentence に代入する
return 0;
}
ディスプレイに表示
gets は get string、puts は put string と覚えれば良い
ゲットエス
プットエス
参考: C言語の読み方サイト http://bubuzuke.s7.xrea.com/ISO10646/c_reading.html
失敗例
プログラム例 13.4.1 と 13.4.2 の混合
#include <stdio.h>
int main(void)
{
char surname[51], sentence[101];
printf("姓を入力してください :");
scanf("%s", surname);
printf("姓は %s です.\n", surname);
printf("文章を入力してください ");
gets(sentence);
puts(sentence);
return 0;
}
gets, getc, getchar
があるときは
scanf は使わない
製品開発には挙動不審な scanf は使われない
解決例
プログラム例 13.4.1 と 13.4.2 の混合
#include <stdio.h>
int main(void)
{
char s[101], surname[51], sentence[101];
printf("姓を入力してください :");
gets(s); sscanf(s, "%s", surname);
printf("姓は %s です.\n", surname);
printf("文章を入力してください ");
gets(sentence);
puts(sentence);
return 0;
}
gets + sscanf なら OK
13.5 文字型配列と関数
関数に文字列を渡す → ポインタ変数(配列名)を引数に
プログラム例 13.5.2
2次元配列のまま渡す場合
#include <stdio.h>
1行あたり40文字で3行分
#define NSIZE 40
の2次元配列を宣言
#define N_Mem 3
void input_name(int n, char name[][NSIZE]);
ポインタ(その配列
void print_name(int n, char name[][NSIZE]); の先頭番地を指す)
を引数とする
int main(void)
{
char f_and_g[N_Mem][NSIZE];
input_name(N_Mem, f_and_g);
print_name(N_Mem, f_and_g);
return 0;
}
文字列を
読込む関数
文字列を
表示する関数
13.5 文字型配列と関数
プログラム例 13.5.2 (つづき)
void input_name(int n, char name[][NSIZE])
{
int i;
for (i = 0; i < n; i++) {
printf("苗字と名前を入力してください :");
gets(name[i]);
}
}
void print_name(int n, char name[][NSIZE])
{
int i;
for (i = 0; i < n; i++)
printf("あなたの苗字と名前は %s です.\n", name[i]);
}
13.5 文字型配列と関数
プログラム例 13.5.3
ポインタ配列として渡す場合
#include <stdio.h>
NSIZEが不要に
#define NSIZE 40
#define N_Mem 3
void input_name(int n, char *name[]);
void print_name(int n, char *name[]);
int main(void)
文字列ポインタ配列を用意
{
int i;
char f_and_g[N_Mem][NSIZE], *name[N_Mem];
for (i = 0; i < N_Mem; i++)
行ごとに2次元配列を
name[i] = f_and_g[i];
文字列ポインタ配列に
input_name(N_Mem, name);
すり替え
print_name(N_Mem, name);
return 0;
}
13.5 文字型配列と関数
プログラム例 13.5.3 (つづき)
void input_name(int n, char *name[])
{
int i;
for (i = 0; i < n; i++) {
printf("苗字と名前を入力してください :");
gets(name[i]);
}
}
NSIZEが不要に
void print_name(int n, char *name[])
{
int i;
for (i = 0; i < n; i++)
printf("あなたの苗字と名前は %s です.\n", name[i]);
}
スキルアップタイム 1
以下の動作をするプログラムを作成してみよう。
1. ディスプレイに「文章を入力して下さい」と表示する。
2. キーボードから入力された適当な英語の文章
(例えば Boys be ambitious! など)を読み取る。
3. その文章をディスプレイに表示する。
4. これを3回繰り返す。
(1、2、3回目は各々違う文章を入力してみる)
プログラム例 13.4.2 を参照
スキルアップタイム 1
のプログラムの流れ
ヘッダファイル、関数、記号定数の宣言部
main
変数宣言(必要な変数と
そのデータ構造を決める)
3
回
繰
り
返
し
printf で「文章を入力して下さい」
gets で文章を読み取り、変数に入れる
puts で文章を表示
終了
3つの文章を記憶せず、
読み込んで表示するだ
けなら1つの文章用1
次元配列で OK
スキルアップタイム 2
作ったプログラムを以下のように変更してみよう。
1. 最初にディスプレイに「3つの文章を入力して下さ
い」 と表示する。
2. ディスプレイに「文章 i:」(iは1、2、3と変化する)
と表示し、キーボードから入力される英語の文章
を読み取る。これを3回繰り返す(この時点では表
示はしない)。
3. 3個の文章をまとめてディスプレイに表示する。
3個の文章を記憶する必要有り → 文字列の2次元配列が必要
スキルアップタイム 2
のプログラムの流れ (その1)
ヘッダファイル、関数、記号定数の宣言部
main
変数宣言(必要な変数と
そのデータ構造を決める)
繰
返
し
繰
返
し
printf で「文章を入力して下さい」
gets で文章を読み取り、配列変数に入れる
puts or printf で配列変数に入った文章を表示
終 了
main で全て
の作業を行う
タイプ(この程
度の課題なら
これでも十分)
スキルアップタイム 2 の
プログラムの流れ (その2)
プログラム例 13.5.2 を参照
関数名、変数名は自分の
好きなように決めてください
ヘッダファイル、関数、などの宣言部
これは一例
文章を読み取る関数 input_sentence
main
変数宣言(必要な変数と
そのデータ構造を決める)
繰
返
し
文章を読み取る関数
文章を表示する関数
printf で「文章を入力して下さい」
gets で文章を読み取る
文章を表示する関数 print_sentence
繰
返
し
printf or puts で文章を表示
終了
文章用の2次元配列(その先頭へのポインタ)
を引数としてデータをやりとりする
スキルアップタイム3
すべてできた人は、演習問題の問題13.3、
問題13.5 をやってみる。
問題13.3 用のデータを考えるのが面倒な人は下記のデータを
使ってください。
学籍番号
氏名
科目Aの得点
1001
Akanishi Hideo
55
1005
Ishihara Satoshi
64
1013
Kitano Keiko
71
1024
Sakaguchi Erika
85
1030
Tanaka Kazuya
68