
C言語では、文字や文字列を扱うためにchar型と文字配列を用いる。charは1バイトの整数型で、文字コード(ASCII)に対応する数値として文字を表現する。たとえば、Aは整数としては65に等しい。このように、文字は内部的には数値として処理されている。
C言語の文字・文字列処理とは?
文字列は、複数のcharを連続して並べ、末尾にヌル文字(\0)を追加することで表現する。このヌル文字は文字列の終端を示すため、処理の際に欠かせない。文字列を配列として扱う際には、十分な長さを確保し、ヌル文字分も含めて宣言する必要がある。
C言語には文字や文字列を操作するための標準ライブラリが豊富に用意されている。文字単体に対してはisalpha()やisdigit()などの関数、文字列全体にはstrcat()やputs()などが存在する。
これらの関数は、いずれも直感的な語源を持つ名前で、英語に慣れていれば意味を推測しやすい。
この記事では、C言語で頻繁に使用される文字・文字列処理関数の基本的な使い方と考え方を、具体例を交えて解説していく。
文字判定関数で入力チェックを簡単に
C言語でユーザー入力を検証する際には、文字がどの種類に属するかを判断する関数が便利である。標準ライブラリ には、用途別にさまざまな文字判定関数が用意されており、プログラムの分岐処理やエラーチェックに活用できる。
たとえば isalpha() は、「is alphabetic(アルファベットかどうか)」の略で、引数に渡された文字が英字(A〜Z、a〜z)であれば真(非ゼロ)を返す。
if (isalpha(inChar)) {
printf("英字が入力されました。\n");
}数字や記号などが入力された場合は偽(ゼロ)を返すため、名前の入力チェックなどに使える。以下はその具体例である。
#include <stdio.h>
#include <ctype.h>
int main() {
char inChar;
printf("1文字を入力してください:");
scanf(" %c", &inChar);
if (isalpha(inChar)) {
printf("英字が入力されました。\n");
} else {
printf("英字以外が入力されました。\n");
}
return 0;
}出力
1文字を入力してください:t
英字が入力されました。1文字を入力してください:0
英字以外が入力されました。このように、isalpha()はシンプルな条件分岐の条件式として非常に有効である。
if (isdigit(inChar)) {
printf("数字が入力されました。\n");
}同様に、isdigit()(is digit)は数字かどうかを判定し、数値のメニュー選択や数値限定の入力欄に活用できる。
#include <stdio.h>
#include <ctype.h>
int main() {
char inChar;
printf("1文字を入力してください:");
scanf(" %c", &inChar);
if (isdigit(inChar)) {
printf("数字が入力されました。\n");
} else {
printf("数字以外が入力されました。\n");
}
return 0;
}1文字を入力してください:9
数字が入力されました。1文字を入力してください:i
数字以外が入力されました。さらに、入力された文字が大文字か小文字かを調べたい場合には、isupper()(is upper case)およびislower()(is lower case)を使う。
if (isupper(inChar)) {
printf("大文字が入力されました。\n");
} else if (islower(inChar)) {
printf("小文字が入力されました。\n");
}大文字だけを許容したパスワード入力や、小文字への自動変換処理を組み込むことが可能になる。
#include <stdio.h>
#include <ctype.h>
int main() {
char inChar;
printf("1文字を入力してください:");
scanf(" %c", &inChar);
if (isupper(inChar)) {
printf("大文字が入力されました。\n");
} else if (islower(inChar)){
printf("小文字が入力されました。\n");
}
return 0;
}1文字を入力してください:A
大文字が入力されました。1文字を入力してください:b
小文字が入力されました。これらの関数は、どれも1文字ずつの検査に特化しており、シンプルな条件分岐において直感的に使える点が最大の強みである。特に、ユーザーからのキーボード入力を前提とするインタラクティブなプログラムでは、これらの関数を使うことで誤入力の早期検出や処理の安全性向上につながる。
開発初期から取り入れることで、入力系のロジックを堅牢に保てるため、習得の早い段階で活用しておくとよい。
文字列をつなぐstrcat()の基本と注意点
C言語で文字列を連結するには、strcat()関数(string concatenate)を使用する。これは、1つ目の引数に指定した文字列の末尾に、2つ目の引数の文字列を上書きで追加する関数である。使用にはのインクルードが必要だ。
#include <stdio.h>
#include <string.h>
int main() {
char greeting[20] = "Hello, ";
char name[] = "Alice";
strcat(greeting, name);
printf("%s\n", greeting); // 出力: Hello, Alice
return 0;
}Hello, Aliceこの例では、greeting配列の末尾にnameの内容が追加され、「Hello, Alice」という文字列が完成する。ここで重要なのは、連結先の配列に十分な空き容量が確保されていることである。strcat()はメモリの境界をチェックしないため、バッファオーバーフローの危険がある。これにより、プログラムが異常終了したり、意図しない動作を引き起こしたりする可能性がある。
安全性を高めるには、strncat()(string n-concatenate)を使うとよい。これは、最大で指定した文字数までしか追加しない関数で、連結による過剰な上書きを防ぐ。
strncat(greeting, name, sizeof(greeting) - strlen(greeting) - 1);このようにstrncat()では、現在の文字列長を考慮して、残りのバッファサイズを計算する必要がある。-1はヌル文字(\0)のためのスペースである。
文字列を結合する処理は、ユーザー名とメッセージの合成やファイル名の生成など、実用的な場面で頻繁に登場する。機能自体はシンプルだが、安全性への配慮を欠かすと、後のバグやセキュリティ事故につながるため、基本とともにリスクへの理解が欠かせない。
出力に便利なputs()とその使いどころ
文字列の出力に特化した関数として、C言語では**puts()(put string)**が用意されている。これは、指定された文字列を表示し、末尾に自動で改行を挿入するのが特徴である。使い方は非常にシンプルで、整形不要なメッセージを表示する際に便利である。
#include <stdio.h>
int main() {
puts("hello,world!");
return 0;
}hello,world!このコードは標準出力に「hello,world!」を表示し、その後に自動で改行が挿入される。printf()との違いは、書式指定ができない代わりに、常に改行付きで簡潔に出力できる点にある。たとえば、単に「完了しました」と表示するだけなら、puts(“完了しました”);のほうが直感的で読みやすい。
変数を含めた複雑なメッセージを出力する場合は、puts()では対応できない。そのため、「スコアは85点です」のようなメッセージを出すにはprintf()を用いる必要がある。誤ってputs()に改行付きの文字列(例:”Hello\n”)を渡すと、意図せず改行が2回行われるため注意が必要だ。
puts()は、簡潔なログ表示やエラーメッセージ出力に適した関数であり、標準出力の基本を理解する入口として有効である。学習初期には、余分な構文なしで動作確認できる点で重宝される。
なぜgets()が使われるのか?scanf()との違い
C言語でユーザーから文字列を入力する際、初心者が最初に学ぶのは通常scanf()関数である。しかし、scanf(“%s”, str);のように使用した場合、スペース(空白)で入力が途切れてしまうという制限がある。
たとえば「John Smith」と入力しても、変数strには「John」しか格納されず、残りは読み取られない。これに対し、gets()(get string)は改行文字までを1つの文字列として扱うため、スペースを含んだフルネームや文章の入力に適している。
char name[50];
gets(name); // "John Smith" などスペース入り文字列を正しく読み取る例
#include <stdio.h>
int main() {
char name[100];
printf("名前を入力してください(例: John Smith): ");
gets(name); // 改行まで読み取る(非推奨)
printf("入力された名前: %s\n", name);
return 0;
}このように、スペースを含む自由な文字列を1行まるごと受け取れる点が、gets()の最大の利点である。ユーザー名やコメント欄のように、単語単位ではなく1行分の入力を必要とする場面でよく使われてきた。
しかし、gets()には致命的なセキュリティ上の欠陥が存在する。入力の長さに制限がないため、配列のサイズを超えてデータが書き込まれる可能性がある。これがバッファオーバーフローであり、意図しないメモリへの書き込みを引き起こす。
悪用されると、コードの改ざんやシステムの乗っ取りといった深刻な攻撃につながる。最近のコンパイラでは gets() を使うと エラーや警告が出る。
このため、C言語の最新版(C11以降)では、gets()は標準から削除され、使用すべきでない関数とされている。代替として推奨されるのがfgets()だ。
fgets(name, sizeof(name), stdin);fgets()は安全性を考慮しており、読み取る最大文字数を明示的に指定できるため、バッファの範囲外にデータが書き込まれる心配がない。
#include <stdio.h>
int main() {
char name[100];
printf("名前を入力してください(例: John Smith): ");
fgets(name, sizeof(name), stdin); // 改行を含めて読み取る
printf("入力された名前: %s", name); // fgetsは末尾に改行が残る場合あり
return 0;
}このように、gets()は初心者にとって理解しやすい反面、実用においてはセキュリティ上の重大な欠点を持つ。理解の段階ではgets()を通じて文字列入力の仕組みを学び、実践では必ずfgets()に切り替えるという姿勢が求められる。これにより、学習と安全性を両立できる。
まとめ
本記事では、C言語における文字と文字列の処理について、初心者でも実践しやすい関数を中心に解説した。isalpha()やisdigit()による文字の判定、strcat()による文字列連結、puts()による出力、そしてgets()とfgets()の違いまでみてきた。理解することで、ユーザー入力や出力処理の幅が広がり、実用的なC言語プログラムを書けるようになるだろう。




