
【6日でできるC言語入門】文字列の比較関数
C言語で配列やデータ構造をソートする際、文字列の並べ替えには「比較関数」が不可欠です。
特に標準ライブラリの qsort 関数では、比較関数(コールバック)を自作して渡すことで、数値だけでなく文字列や構造体の任意のフィールド順に並び替えることができます。
ここでは、文字列用の比較関数の書き方、strcmp 関数の正しい利用方法、qsort との組み合わせ、そして応用例まで詳しく解説します。

1.文字列の比較関数の基本
1.1. 文字列を比較する関数―strcmp
C言語の標準ライブラリには、文字列を辞書順で比較するための strcmp 関数が用意されています。
| 関数名 | 書式 | 戻り値 |
|---|---|---|
| strcmp | int strcmp(const char* s1, const char* s2); | s1とs2の大小関係(下表参照) |
strcmpの戻り値
| 戻り値 | 意味 |
|---|---|
| 0 | s1とs2が完全一致 |
| 負の値 | s1がs2よりも辞書順で前にある。 |
| 正の値 | s1がs2よりも辞書順で後ろにある。 |
1.2. 比較関数として利用する理由
標準ソート関数qsortに「配列要素の比較ルール」を伝えるため、比較関数を自分で用意します。
特に文字列配列や構造体のメンバ(例:名前)でソートしたい場合、この関数が必要です。
2.文字列比較関数のサンプル実装
2.1. qsort用・文字列比較関数の典型例
int cmp_str(const void* a, const void* b) {
// a, bはそれぞれchar*型(配列要素)のアドレス(=char**型)
return strcmp(*(const char**)a, *(const char**)b);
}なぜconst void*なのか?
qsortの仕様で、比較関数の引数はconst void*型。- 文字列配列(
char* array[])の場合、qsortから受け取るa, bは「要素(char*)のアドレス」→型はconst char**。 - したがって、
*(const char**)aで実際の文字列(char*)を取り出す。
図解
| 実際の要素 | 配列の型 | qsortから渡る型 | 比較関数内の処理 |
|---|---|---|---|
| "apple" | char* | const void* | (const char*)a → char* |
| "lemon" | char* | const void* | (const char*)b → char* |
2.2. サンプルプログラム:文字列配列のソート
プロジェクト/ファイル名: Lesson72_1/main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 5
int cmp_str(const void* a, const void* b) {
return strcmp(*(const char**)a, *(const char**)b);
}
void show(char* array[], int size) {
for (int i = 0; i < size; i++) {
printf("%s ", array[i]);
}
printf("\n");
}
int main(void) {
char* fruits[SIZE] = {"みかん", "りんご", "バナナ", "ぶどう", "すいか"};
printf("初期配列: ");
show(fruits, SIZE);
qsort(fruits, SIZE, sizeof(char*), cmp_str);
printf("ソート後: ");
show(fruits, SIZE);
return 0;
}実行結果
初期配列: みかん りんご バナナ ぶどう すいか
ソート後: すいか ぶどう みかん りんご バナナ※ 文字コードによる並び順になるため、結果はロケール・環境により異なる場合があります
3.応用:構造体配列の比較関数
3.1. 構造体の特定メンバ(例:名前)でソート
構造体配列をqsortでソートしたい場合、比較関数内で必要なフィールドをstrcmpで比較します。
プロジェクト/ファイル名: Lesson72_2/main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char name[16];
} Student;
int cmp_by_name(const void* a, const void* b) {
// a, bはStudent型のアドレス
const Student* sa = (const Student*)a;
const Student* sb = (const Student*)b;
return strcmp(sa->name, sb->name);
}
void show(Student* arr, int size) {
for (int i = 0; i < size; i++) {
printf("ID:%d 名前:%s\n", arr[i].id, arr[i].name);
}
}
int main(void) {
Student students[] = {
{3, "佐藤"}, {1, "田中"}, {2, "山田"}, {5, "加藤"}, {4, "鈴木"}
};
int size = sizeof(students) / sizeof(students[0]);
printf("ソート前:\n");
show(students, size);
qsort(students, size, sizeof(Student), cmp_by_name);
printf("ソート後:\n");
show(students, size);
return 0;
}実行結果
ソート前:
ID:3 名前:佐藤
ID:1 名前:田中
ID:2 名前:山田
ID:5 名前:加藤
ID:4 名前:鈴木
ソート後:
ID:5 名前:加藤
ID:3 名前:佐藤
ID:2 名前:山田
ID:1 名前:田中
ID:4 名前:鈴木まとめ
- 文字列の比較関数は、
strcmpを使ってqsortの比較関数として実装する。 - 配列の型や目的に合わせて、ポインタのキャストやアクセス方法に注意する。
- 応用すれば、構造体配列の特定メンバでのソートや、独自の並び替え基準も柔軟に実装できる。
