C言語では, 単語や文章などの複数の文字(文字列)は文字の配列として扱う. この章では, 文字列の扱いを学ぶが, それ以上にコンピュータのメモリ上にどのように文字というデータが配置されているかを理解することに重点を置いて欲しい.
%s (教科書p.212),
文字を出力するときは %cを書式に指定する.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char c = 'a';
char str[] = "ABCDEFG";
printf("c=%c\n", c);
printf("str=%s\n", str);
return EXIT_SUCCESS;
}
const char c; のように const で修飾して宣言されたcは定数であるが, このままでは, 値は不明でリテラルではない.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char c = 'a'; // 'a' は文字リテラル. c は変数.
char strA[] = "ABC"; // "ABC" は文字列リテラル. strA は変数.
const char strB[] = "ABC"; // "ABC" は文字列リテラル. strB は定数.
int a; // a は変数.
int b = 1; // 1 は整数リテラル. bは変数.
double x; // x は変数.
double y = 5.0e3; // 5.0e3 は倍精度浮動小数点数リテラル. y は変数.
const double z = 1.0e2; // 1.0e2 は倍精度浮動小数点数リテラル. z は定数.
a = 3; // 3 は整数リテラル. a は変数.
y = 8.0e-4; // 8.0e-4 は倍精度浮動小数点数リテラル.
printf("a=%d, y=%f\n", a, y); // "a=%d, y=%f\n" は文字列リテラル.
return EXIT_SUCCESS;
}
| 型 | 宣言 | printfの書式 | scanfの書式 |
| 文字 | char c; | printf("c = %c", c); | scanf("%c", &c); |
| 文字列 | char str[10]; | printf("str = %s", str); | scanf("%s", str); |
| 整数 | int n; | printf("n = %d", n); | scanf("%d", &n); |
| 実数 | double x; | printf("x = %f", x); | scanf("%lf", &x); |
| アドレス | double x; | printf("xのアドレス = %p", &x); | |
| アドレス | char str[10]; | printf("strの先頭のアドレス = %p", str); |
// 文字の復習
#include <stdio.h>
int main(void)
{
// 文字の宣言
char a;
// 文字の代入
a = 'A'; // 特殊な文字の例 '\t' '\n' '\a' '\0'
a = 0x62; // 16進数で表記した文字
// printf の書式
printf("c=%c\n", a); // 文字の出力は %c で指定する.
// scanf の書式
scanf("%c", &a); // 文字の出力は %c で指定する. 引数には & をつける.
printf("c=%c\n", a);
return 0;
}
// 文字列
#include <stdio.h>
int main(void)
{
// 文字列の宣言 と初期化
char a[8] = "ABC";
// printf の書式
printf("a=%s\n", a); // 文字の出力は %s で指定する.
return 0;
}
program 3
// 文字列
#include <stdio.h>
int main(void)
{
// 文字列の宣言
char a[8];
// scanf の書式
scanf("%s", a); // 文字の入力は %s で指定する.
// 引数には配列名を与える.
// 配列でない変数 -> & をつけて 渡す.
// 配列 -> &a[0] を渡す. 毎回 &a[0] と書くのは面倒.
// 配列名 a が &a[0] の意味で使えるようになっている.
// 入力した文字の確認.
printf("a=%s\n", a);
return 0;
}
program 4
// 初期化
#include <stdio.h>
int main(void)
{
// 文字列の初期化
char a[8] = {'A', 'B', 'C', '\0'};
char b[8] = "pqr";
// ここでは, "pqr" は {'p', 'q', 'r', '\0'} の意味
// 初期化された内容の確認.
printf("a=%s\n", a);
printf("b=%s\n", b);
return 0;
}
program 5
// 注意 !!! 結果を予想できるようになりましょう.
#include <stdio.h>
int main(void)
{
char a[8];
char b[8];
char c[8];
printf("a = ");
scanf("%s", a);
printf("b = ");
scanf("%s", b);
printf("b = ");
scanf("%s", c);
printf("a=%s\n", a);
printf("b=%s\n", b);
printf("b=%s\n", c);
return 0;
}
program 6
// 代入
#include <stdio.h>
int main(void)
{
// 文字列の宣言
char a[8];
// 文字列への代入
a[0] = 'A';
a[1] = 'B';
a[2] = 'C';
a[3] = 0x62; // 16進数で表記した文字
a[4] = '\0'; // 最後は 0 で終端する.
// 入力した文字列の確認.
printf("a=%s\n", a);
return 0;
}
program 7
// 代入
#include <stdio.h>
int main(void)
{
// 文字列の宣言
char a[8] = "ABC";
char x[8];
// 文字列 a から 文字列 x へのコピー(代入)
x[0] = a[0];
x[1] = a[1];
x[2] = a[2];
x[3] = a[3]; // a[3] には '\0' が代入されていることに注意.
// コピーした文字列の確認.
printf("x=%s\n", x);
return 0;
}
program 8
// 代入
#include <stdio.h>
int main(void)
{
int i;
// 文字列の宣言
char a[8] = "ABC";
char x[8];
// 文字列 a から 文字列 x へのコピー(代入)
// 繰り返しを使うと
for(i=0; i<8; i++){
x[i] = a[i];
if(x[i] == '\0')
break;
}
// コピーした文字列の確認.
printf("x=%s\n", x);
return 0;
}
program 9
// 代入 のための関数 string_copy を作ってみましょう.
#include <stdio.h>
// 文字列 x を文字列 y にコピーする関数.
void string_copy(char y[8], char x[8])
{
int i;
for(i=0; i<8; i++){
y[i] = x[i];
if(x[i] == '\0')
break;
}
}
int main(void)
{
// 文字列の宣言
char a[8] = "ABC";
char b[8];
string_copy(b, a);
// コピーした文字列の確認.
printf("b=%s\n", b);
return 0;
}
program 10
#include <stdio.h>
#include <string.h> // 文字列に関係した関数を使うときは string.h をインクルードする.
int main(void)
{
char str[100];
strcpy(str, "ABC"); // 本当は, 文字列のコピーのための関数は標準で備わっている.
printf("str=%s\n", str);
return 0;
}
program 11
// 文字列の長さを調べるプログラム.
// str[10] に代入されている文字を前から1つずつ調べ,
// '\0' でない文字の数を length により数える.
#include <stdio.h>
#include <strings.h>
int main(void)
{
char str[10] = "ABC";
int i;
int length;
length = 0;
for(i=0; i<10; i++){
if(str[i] != '\0'){
printf("%d: %c\n", i, str[i]);
length++;
}else{ // str[i] == '\0' のとき
break; // for のループの繰り返しを終了する.
}
}
printf("length = %d\n", length);
return 0;
}
program 12
// 文字列の長さを調べる関数
#include <stdio.h>
#include <strings.h>
// 配列を受けとる関数. [] 内の要素数は省略できる.
int string_length(char s[])
{
int len = 0;
while ( s[len] != '\0' )
len++;
return len;
}
int main(void)
{
char str[10] = "ABC";
int length;
length = string_length(str); // 配列名を渡す
printf("length = %d\n", length);
return 0;
}
program 13
// 文字列の長さを調べる.
#include <stdio.h>
#include <string.h> // 文字列に関係する関数を使用するときインクルードする.
int main(void)
{
char str[10] = "ABC";
int length;
length = strlen(str); // 文字列の長さを調べる関数は標準で用意されている.
printf("length = %d\n", length);
return 0;
}
program 14
// 文字列の長さとサイズ
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[10] = "ABC";
printf("length = %d\n", strlen(str));
printf("sizeof(str) = %d\n", sizeof(str));
return 0;
}
program 15
// 配列に対する sizeof 演算の復習
#include <stdio.h>
#include <string.h>
int main(void)
{
double x[10];
printf("sizeof(x) = %d\n", sizeof(x)); // 配列のための領域の大きさ (単位はバイト)
printf("sizeof(x[0]) = %d\n", sizeof(x[0])); // 各要素の大きさ (単位はバイト)
printf("sizeof(x) / sizeof(x[0]) = %d\n", sizeof(x)/sizeof(x[0])); // 要素の数
return 0;
}
program 16
// 文字列の配列
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[3][8]; // 3つの文字列の領域を確保. 各文字列は最大7文字まで.
strcpy(a[0], "abc"); // a[0] に "abc" をコピーする.
strcpy(a[1], "pqr");
strcpy(a[2], "uvw");
// 値の確認.
printf("a[0] = %s\n", a[0]);
printf("a[1] = %s\n", a[1]);
printf("a[2] = %s\n", a[2]);
return 0;
}
program 17
// 文字列の配列の初期化
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[3][8] = {"abc", "pqr", "uvw"};
// 値の確認.
printf("a[0] = %s\n", a[0]);
printf("a[1] = %s\n", a[1]);
printf("a[2] = %s\n", a[2]);
return 0;
}
program 18
// 文字列の配列を関数に渡す.
#include <stdio.h>
#include <string.h>
// 各文字列に定められた文字列をコピーする関数
// 各要素の大きさ (ここでは8) は省略できない.
void strings_copy(char destination[3][8])
{
int i;
char source[3][8] = {"00", "111", "222"};
for(i=0; i<3; i++)
strcpy( destination[i], source[i] );
}
int main(void)
{
int i;
char a[3][8];
strings_copy(a);
// 値の確認
for(i=0; i<3; i++)
printf("%d: %s\n", i, a[i]);
return 0;
}
program 19
// 文字列の配列を関数に渡す.
#include <stdio.h>
#include <string.h>
// 各文字列の内容を出力する関数
// 各要素の大きさ (ここでは8) は省略できない.
void print_strings(char str[3][8])
{
int i;
for(i=0; i<3; i++)
printf("%d: %s\n", i, str[i]);
}
int main(void)
{
char a[3][8] = {"abc", "pqr", "uvw"};
print_strings(a);
return 0;
}
program 20
// 文字列の配列を関数に渡す.
#include <stdio.h>
#include <string.h>
// 各文字列の長さを出力する関数
// 各要素の大きさ (ここでは8) は省略できない.
void print_lengths(char str[3][8])
{
int i;
for(i=0; i<3; i++)
printf("%d: %d\n", i, strlen(str[i]));
}
int main(void)
{
char a[3][8] = {"123", "12345", "1234567"};
print_lengths(a); // 配列名を渡す.
return 0;
}
自由課題1
/*
(a) 教科書p.208の「文字列リテラルの大きさ」およびp.211「文字列配列の初期化」を
理解し, 以下のプログラム中の 配列 string の要素数を答えよ.
これは, 文字列 "12345" の長さ5とは異なることに注意せよ.
(b) また, その理由を答えよ.
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char string[] = "12345";
printf("string = %s\n", string);
printf("sizeof(char)=%d, sizeof(string)=%d\n", sizeof(char), sizeof(string));
return EXIT_SUCCESS;
}
自由課題2
/*
以下のプログラムについて
(a) 文字の配列 strA, strB, strC のサイズを答えよ.
(b) (*)で行っていることを説明せよ.
(c) (**)で行っている代入は誤りである. 理由を答えよ.
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
// 初期化
char strA[5] = "acem";
char strB[5] = "nors";
char strC[5] = "tuvw";
printf("strA = %s\nstrB = %s\nstrC = %s\n\n", strA, strB, strC);
strB[2] = 'X'; // (*) 正
printf("strA = %s\nstrB = %s\nstrC = %s\n\n", strA, strB, strC);
strB[7] = 'Y'; // (**) 誤
printf("strA = %s\nstrB = %s\nstrC = %s\n\n", strA, strB, strC);
return EXIT_SUCCESS;
}
自由課題3
/*
次のプログラムでは, 文字列 string の長さ length を求めている.
これを実現するためには, 文字列は '\0' で終端することになっているので,
配列中から 文字 '\0' を探せばよい.
とくに, 配列の大きさとは異なることに注意すること.
このプログラムでは, while を用いて長さを求めているが,
for を用いたプログラムに変更せよ.
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char string[20] = "ABCD";
int length;
length = 0;
while(string[length] != '\0')
length++;
printf("length = %d\n", length);
return EXIT_SUCCESS;
}
自由課題4
/*
以下のプログラムでは, まず文字列 string の長さ length を求め,
その値を用いて, 指定した文字 c が, 文字列 string の中で
最初に現れる場所 position を求めている.
position を求めている部分は for を用いて記述されているが,
これを while を用いて表せ.
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char c, string[20] = "ABCD";
int length, position;
// 文字列の長さを求める.
length = 0;
while(string[length] != '\0')
length++;
printf("length = %d\n", length);
// string の中で最初に文字 c が現れる場所 position を求める.
c = 'B';
for(position=0; position < length; position++){
if(string[position] == c){
printf("'%c' is found at %d\n", c, position);
break;
}
}
return EXIT_SUCCESS;
}
自由課題5
/*
以下のプログラムでは, 文字列 strAに 別の文字列 strB の内容を
コピーしている. 代入を行っている部分を for を用いて書き直せ.
C言語では, strA = strB のような代入を行うことはできない.
また, 初期化以外の場所では, strA = "abce"; のような代入ができない.
内容をコピーするときは, 下に示すように各要素の代入を行う.
または,
strA[0] = 'P';
strA[1] = 'Q';
strA[2] = 'R';
strA[3] = '\0';
のようなに代入を行う.
文字列を対象とした コピー, 結合, 長さ, 検索などの
頻繁に用いる操作については, 標準関数として用意されているので,
実用上はこれらの標準関数を用いた方がよい.
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char strA[100];
char strB[100] = {'P', 'Q', 'R', '\0'};
strA[0] = strB[0];
strA[1] = strB[1];
strA[2] = strB[2];
strA[3] = '\0';
printf("s = %s\n", strA);
return EXIT_SUCCESS;
}
自由課題6
/*
文字列自体が文字の配列であるので,
文字列の1次元配列は文字の2次元配列で実現される.
以下のプログラムでは, まず各文字列を表示し,
次に各文字列の長さを求めて出力するプログラムである.
(*)の部分に各文字列 array[i] の長さを length に代入するよう
プログラムを加筆せよ.
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i, length=0;
char array[4][100] = {"abcdefg", "1234", "UVWXYZ", "---"};
for(i=0; i<4; i++)
printf("array[%d] = %s\n", i, array[i]);
for(i=0; i<4; i++){
/*
array[i] の長さ length を求める. (*)
*/
printf("[%d] %d\n", i, length);
}
return EXIT_SUCCESS;
}
List 9-11, List 9-12 の constの使い方は, C言語の規格上は誤りである.
これらは gcc でコンパイルすると, 以下ようなメッセージが表示される.
List9_11.c: In function ‘main’: List9_11.c:14: warning: passing argument 1 of ‘put_strary’ from incompatible pointer type
const を削除して次のように宣言すればよい.
void put_strary(char st[][6], int n)詳細は, ポインタの知識が必要となるので, ポインタを学んだ後に第6.4節を参照のこと.
これに対し, 仮引数に1次元配列を渡す場合は正しい. 例えば List 9-8 では,
unsigned str_length(const char str[])のように関数宣言を行っているが, これは正しい.
(c)1999-2013 Tetsuya Makimura