
C言語入門|11章の練習問題
11章では、C言語における 文字列の本質(C文字列文化) を学びました。
特に重要なのは、
- C の文字列は char 配列+終端文字¥0(ヌル文字) の組み合わせであること。
- 文字列操作関数はすべて ¥0 が現れるまで処理する こと。
- 文字列リテラルと char 配列では 書き換え可否が異なる。
- ヒープ上に必要なサイズぴったりの文字列バッファを確保する。
- ポインタをずらすと、違う場所から文字列として扱えること。
- calloc / malloc の違いと、free の扱い方。
これらは C言語の実務でも頻繁に登場し、理解できると一気に中級者へステップアップできます。
ここでは、文字列操作命令の挙動や、配列とヒープのメモリ構造を図表を使ってわかりやすく解説し、その後で「練習問題+解答例と解説」を4問出題します。

C文字列の特徴 — まずはイメージで理解しよう
char 配列のメモリイメージ(例:hello)
| インデックス | 値 | ASCII | アドレス(例) |
|---|---|---|---|
| a[0] | 'h' | 104 | 1000 |
| a[1] | 'e' | 101 | 1001 |
| a[2] | 'l' | 108 | 1002 |
| a[3] | 'l' | 108 | 1003 |
| a[4] | 'o' | 111 | 1004 |
| a[5] | 0 (終端) | 0 | 1005 |
ポイント
- 必ず最後に¥0 が付く
- 文字列の長さは「¥0を含まない文字数」
- 配列のサイズ=長さ+1文字分の¥0 が必要
文字列操作命令(標準関数)の概要
| 関数名 | 書式 | 何をする? | ¥0 の扱い |
|---|---|---|---|
| strlen | strlen(s) | 文字列 s の長さを返す | ¥0 はカウントしない |
| strcmp | strcmp(a, b) | 文字列 a と b を比較し、同じなら 0 | ¥0 が出るまで比較 |
| strcpy | strcpy(dst, src) | src を dst にコピー | ¥0 までコピー |
| strcat | strcat(dst, src) | dst の末尾に src を連結 | 連結後に新しい ¥0 を付加 |
11章の練習問題
【練習11-1】(標準文字列関数の理解)
次の空欄(ア)〜(エ)に入る語句を答えてください。
| 関数名 | 動作 | ¥0 の扱い |
|---|---|---|
| strlen | 文字列の長さを調べる | ¥0 は(ア) |
| strcmp | 2つの文字列を(イ)比較する | ¥0 まで比較 |
| strcpy | (ウ) | ¥0 までコピー |
| (エ) | 文字列を連結する | 末尾に ¥0 を付ける |
【解答例】
(ア)含めない
(イ)辞書順で
(ウ)文字列全体をコピーする
(エ)strcat
【練習11-2】(strlen・strcmp・動的メモリ・連結)
次の文字列があるとします。
char a[] = "C Lang ";
char b[] = "Practice";以下の動作を行うプログラムを作成してください。
- a と b の長さを表示する。
- a と b が同じ内容か比較する。
- 連結後の文字列を格納できるちょうどの領域をヒープに確保する。
- a のあとに b を連結してヒープ領域に格納する。
- メモリを解放する。
【解答例】(フルコード)
プロジェクト名:11-15-1 ソースファイル名: sample11-15-1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char a[] = "C Lang ";
char b[] = "Practice";
printf("len(a) = %lu\n", strlen(a));
printf("len(b) = %lu\n", strlen(b));
if (strcmp(a, b) == 0) {
printf("同じ内容です\n");
} else {
printf("内容は異なります\n");
}
size_t size = strlen(a) + strlen(b) + 1;
char* c = malloc(size);
strcpy(c, a);
strcat(c, b);
printf("連結結果:%s\n", c);
free(c);
return 0;
}【練習11-3】(ポインタをずらして部分文字列を書く)
次のプログラムについて設問に答えてください。
プロジェクト名:11-15-2 ソースファイル名: sample11-15-2.c
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char x[] = "ABCDEFG";
char y[] = {10, 11, 12, 13, 14, 15};
char* heap = calloc(20, sizeof(char));
char* p = heap + 6;
p[0] = 'X';
p[1] = 'Y';
free(heap);
return 0;
}【条件】
x の先頭アドレスは 4000、y は 5000、heap は 6000 とする。
(1)行番号 12 まで実行されたとき、x・y・p の「使用中領域/使用可能領域」を番地で示してください。
【解答】
配列・ポインタのメモリイメージ(表)
| 変数 | 使用中領域 | 使用可能領域 |
|---|---|---|
| x | 4000〜4007(ABCDEFG¥0) | 5000〜5005 |
| y | 5000〜5005(値 10〜15) | 5000〜5005 |
| p(= heap+6) | 使用中:6006〜6007('X','Y') | heap の確保範囲:6000〜6019 |
(2)9行目を char* p = y + 4; として文字列 p を表示した場合の動作を答えてください。
【解答】
y は文字列ではなく単なる数値配列なので、
p を文字列として printf("%s", p); のように扱うと、
¥0 が存在しないため暴走し、未定義動作になる。
【練習11-4】(strcpy と部分書き換えの注意点)
次のプログラムを読んで問に答えてください。
プロジェクト名:11-15-3 ソースファイル名: sample11-15-3.c
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[] = "computer";
char* t = s + 4;
strcpy(t, "BOX");
printf("%s\n", s);
return 0;
}(1)出力結果を答えてください。
(2)このコードの危険性を説明してください。
【解答例】
(1)出力結果
compBOX【理由】
t は s[4]('u' の位置)を指すため、そこから "BOX" を上書き。
(2)危険性
- strcpy は終端 ¥0 までコピーするため、
元の配列サイズを超えて書き込む可能性があり、バッファオーバーフローが起こる。 - 今回はたまたま収まったが、実務では非常に危険。
