C言語 strcmpとmemcmp【使い方と比較の違い:サンプル付き】

C言語
この記事は約10分で読めます。

こんにちは、ナナです。

C言語では、次のように「変数」に比較演算子を使うことで、「定数」や「他の変数」と値を比較することができます。

#include <stdio.h>

int main(void)
{
	int num1 = 100;
	int num2 = 200; 

	//	変数と定数の比較
	if (num1 == 100)
	{
		printf("一致\n");
	}

	//	変数と変数の比較
	if (num1 != num2)
	{
		printf("不一致\n");
	}

	return 0;
}

しかし、C言語ではこのような変数同士の比較は簡単にできても、文字列のような連続したデータを比較演算子では比較できません。次のプログラムの条件式は「真」とはならないのです。

#include <stdio.h>

int main(void)
{
	char moji[] = "Hello";
	char num1[] = { 100, 200 };
	char num2[] = { 100, 200 };

	//	文字列と文字列の比較は比較演算子ではできない
	if (moji == "Hello")
	{
		printf("一致\n");
	}

	//	配列と配列の比較は比較演算子ではできない
	if (num1 == num2)
	{
		printf("一致\n");
	}

	return 0;
}

このような、複数の情報から構成される文字列や配列の比較を可能とするのが、strcmp関数とmemcmp関数です。

本記事では次の悩みを解消する内容となっています。

本記事の悩み解決リスト
  • strcmp関数の使い方とサンプルプログラム
  • strncmp関数の使い方とサンプルプログラム
  • memcmp関数の使い方と仕様とは?
  • memcmp関数を使ったサンプルプログラム
  • strcmp関数とmemcmp関数の使い分け方とは?

では、「strcmp」と「memcmp」の使い方と扱い方の違いを学んでいきましょう。

スポンサー

strcmp系の標準ライブラリ関数を紹介

まずは、strcmp系の標準ライブラリ関数を紹介しましょう。

#include <string.h>

int strcmp(const char * str1, const char * str1);
int strncmp(const char * str1, const char * str1, size_t n);

strcmpとは「string:文字列」を「compare:比較」するための標準ライブラリ関数です。

strcmp関数の仕様について

strcmp関数は、第1引数と第2引数は比較したい文字列へのポインタを指定します。

includeファイルstring.h
関数仕様int strcmp(const char * str1, const char * str1);
引数1比較対象の文字列へのポインタ
引数2比較対象の文字列へのポインタ
戻り値比較結果
0:文字列内容が一致
正の値:違いがあり、str1の文字コードが大きい
負の値:違いがあり、str2の文字コードが大きい
特記事項指定文字列からヌル文字までの完全一致を判定する

strncmp関数の仕様について

strncmp関数は、第3引数で比較するサイズを指定できるバージョンです。

includeファイルstring.h
関数仕様int strncmp(const char * str1, const char * str1, size_t n);
引数1比較対象の文字列へのポインタ
引数2比較対象の文字列へのポインタ
引数3比較するサイズを指定
戻り値比較結果
0:文字列内容が一致
正の値:違いがあり、str1の文字コードが大きい
負の値:違いがあり、str2の文字コードが大きい
特記事項指定文字列からヌル文字、もしくは指定サイズn分だけ文字列を比較する
ナナ

文字列の比較結果は戻り値で取得できます。一致したときに「0」の値が返却されることに注意しましょう!

strcmp関数を使ったサンプルプログラム

strcmp関数を使ったプログラムを紹介しましょう。

#include <stdio.h>
#include <string.h>

int main(void)
{
	char moji[] = "Hello";

	if (strcmp(moji, "Hello") == 0)
	{
		printf("一致\n");
	}
	else
	{
		printf("不一致\n");
	}

	return 0;
}

戻り値に関しては、文字の大小関係を知りたいことはあまりないため、一般的に「0」か「0以外」かをチェックします。

strcmp関数を使った比較例のサンプルプログラム

strcmp関数において、どのような文字列の比較なら一致とされるかは必ず知っておきましょう。

#include <stdio.h>
#include <string.h>

int main(void)
{
	printf("%d\n", strcmp("Hello", "Hello"));		//	〇
	printf("%d\n", strcmp("HELLO", "hello"));		//	×
	printf("%d\n", strcmp("Hello", "HelloWorld"));	//	×
	printf("%d\n", strcmp("ハロー", "ハロー"));		//	〇

	return 0;
}
No第1引数第2引数比較結果説明
“Hello”“Hello”一致完全一致のため
“HELLO”hello”不一致英大文字・小文字は別文字と判断する
“Hello”“HelloWorld”不一致前方一致のみでは不一致と判断する
“ハロー”“ハロー”一致全角文字でも一致と判断する

まず、大事なのは②のケースとして英大文字と小文字は区別されることです。そして、③の前方一致のケースは不一致と判断されます。

ナナ

strcmp関数による一致判定とは、ヌル文字も含めて完全一致する必要があります。

strncmp関数を使うと前方一致判定も可能

strncmp関数は比較範囲を限定的にすることができるため、前方一致の判定が可能になります。

#include <stdio.h>
#include <string.h>

int main(void)
{
	char moji[] = "Hello";

	printf("%d\n", strncmp(moji, "Hello",		strlen(moji)));	//	〇
	printf("%d\n", strncmp(moji, "HelloWorld",	strlen(moji)));	//	〇

	return 0;
}

strlen関数はヌル文字を含まない文字サイズを返却するため、このプログラムでは前方一致の場合も一致判定がなされます。

ナナ

関数の性質を知ることで、使いどころを知ることができます。

スポンサー

memcmp系の標準ライブラリ関数を紹介

続いて、memcmp関数を紹介しましょう。

#include <string.h>

int memcmp(const void * buf1, const void * buf1, size_t n);

memcmp関数は「memory:メモリ」を「compare:比較」するための標準ライブラリ関数です。

strcmp関数では、文字列がヌル文字で終わる性質を利用するため、引数にサイズ指定がありません。しかし、memcmp関数では、データの終端という概念がないため、引数によってサイズを指定することになります。

memcmp関数の仕様について

memcmp関数は、第1引数と第2引数は比較したいメモリへのポインタを指定します。

includeファイルstring.h
関数仕様int memcmp(const void * buf1, const void * buf1, size_t n);
引数1比較対象のメモリへのポインタ
引数2比較対象のメモリへのポインタ
引数3比較サイズを指定
戻り値比較結果
0:メモリ内容が一致
正の値:違いがあり、buf1の数値が大きい
負の値:違いがあり、buf2の数値が大きい
特記事項2つのメモリ内容をサイズ分まで完全一致かを判定する

特徴的なのは引数がvoid型ポインタになっていることです。

memcmp関数を使ったサンプルプログラム

memcmp関数の引数はvoid型ポインタのため、次のようにあらゆる型へのポインタを指定することが可能です。変数同士、文字列同士、配列同士いずれも指定が可能なのです。

#include <stdio.h>
#include <string.h>

int main(void)
{
	long	buf1 = 100;
	long	buf2 = 100;

	short	num1[] = { 10, 20, 30 };
	short	num2[] = { 10, 20, 30 };

	char	moji1[] = "Hello";
	char	moji2[] = "Hello";

	//	変数の比較
	printf("%d\n", memcmp(&buf1, &buf2,	sizeof(buf1)));

	//	文字列の比較
	printf("%d\n", memcmp(moji1, moji2, sizeof(moji1)));

	//	配列の比較
	printf("%d\n", memcmp(num1, num2, sizeof(num1)));

	return 0;
}
ナナ

memcmp関数は、あらゆる情報をメモリ単位で比較できるのが特徴です。

memcmp関数で構造体を比較するときと使う時の注意点

memcmp関数には構造体データへのポインタも指定することが可能です。

#include <stdio.h>
#include <string.h>

typedef struct
{
	short	num1;
	short	num2;
} S_TEST;

int main(void)
{
	S_TEST	buf1 = { 0x1234, 0x5678 };
	S_TEST	buf2 = { 0x1234, 0x5678 };

	printf("%d\n", memcmp(&buf1, &buf2, sizeof(buf1)));

	return 0;
}

注意点としては、構造体は構造体メンバのデータ型によって、パディング領域が発生する可能性があります。

そのため、パディング領域が不定値の状態ではメンバの値は一致していても、一致判定ができないことがあることに注意です

次のプログラムはパディングが発生する構造体定義と変数定義です。

#include <stdio.h>
#include <string.h>

typedef struct
{
	char	num1;
	short	num2;
} S_TEST;

//	グローバル変数
S_TEST	buf1 = { 0x12, 0x5678 };

int main(void)
{
	S_TEST	buf2 = { 0x12, 0x5678 };

	printf("%d\n", memcmp(&buf1, &buf2, sizeof(buf1)));

	return 0;
}
-1

このように不一致の判定となります。これはパディング領域の不定値によって不一致判定がされたということです。

構造体について詳しく知りたい方は『C言語 構造体 struct【情報のパッケージ化とそのメリット】』の記事を見ておくとよいでしょう。

ナナ

構造体をmemcmp関数で比較したければ、memset関数で事前に領域全てを0クリアするといった工夫が必要となります。

スポンサー

strcmp関数とmemcmp関数の使い分け

それぞれの比較関数ですが、次のシーンに応じて使い分けしましょう。

strcmp関数を使うシーン
  • 文字列同士の完全一致を判定したいとき
strncmp関数を使うシーン
  • 文字列の一部を一致判定したいとき
memcmp関数を使うシーン
  • 配列を比較したいとき
  • 構造体を比較したいとき。ただし、パディングに注意。
ナナ

目的のシーンに合わせて関数を使い分けましょう!