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