「C言語の基礎 - 配列・メモリ領域」の版間の差分
(ページの作成:「== メモリ領域を動的に確保する == C言語で、メモリ領域を動的に確保するには、stdlib.hのmalloc関数を使用する。<br> <source lang="c"…」) |
細 (文字列「<source lang」を「<syntaxhighlight lang」に置換) |
||
(同じ利用者による、間の2版が非表示) | |||
1行目: | 1行目: | ||
== メモリ領域を動的に確保する == | == メモリ領域を動的に確保する == | ||
C言語で、メモリ領域を動的に確保するには、stdlib.hのmalloc関数を使用する。<br> | C言語で、メモリ領域を動的に確保するには、stdlib.hのmalloc関数を使用する。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
void *malloc(size_t size); | void *malloc(size_t size); | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
malloc関数はsizeバイト分のメモリ領域を確保して、そのメモリ領域へのポインタを返す関数である。<br> | malloc関数はsizeバイト分のメモリ領域を確保して、そのメモリ領域へのポインタを返す関数である。<br> | ||
13行目: | 13行目: | ||
malloc関数を使用したメモリの動的確保は、多くの場合、以下のように実装する。<br> | malloc関数を使用したメモリの動的確保は、多くの場合、以下のように実装する。<br> | ||
以下の例として、int型のデータが10個入るサイズのメモリ領域を確保している。<br> | 以下の例として、int型のデータが10個入るサイズのメモリ領域を確保している。<br> | ||
< | <syntaxhighlight lang="c"> | ||
int *ptr = nullptr; | int *ptr = nullptr; | ||
26行目: | 26行目: | ||
/* メモリ領域の解放 */ | /* メモリ領域の解放 */ | ||
free(ptr); | free(ptr); | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
以下の例では、malloc関数を使用して、メモリ領域を動的に確保している。<br> | 以下の例では、malloc関数を使用して、メモリ領域を動的に確保している。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
57行目: | 57行目: | ||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
== メモリ領域を確保して、その領域を0で初期化する == | == メモリ領域を確保して、その領域を0で初期化する == | ||
C言語で、メモリ領域を動的に確保して、その領域を0で初期化するには、stdlib.hのcalloc関数を使用する。<br> | C言語で、メモリ領域を動的に確保して、その領域を0で初期化するには、stdlib.hのcalloc関数を使用する。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
void *calloc(size_t nmemb, size_t size); | void *calloc(size_t nmemb, size_t size); | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
calloc関数は、sizeバイトの大きさを持つオブジェクトがnmemb個分入るメモリ領域を確保して、その領域のすべてのビットを0で初期化する関数である。<br> | calloc関数は、sizeバイトの大きさを持つオブジェクトがnmemb個分入るメモリ領域を確保して、その領域のすべてのビットを0で初期化する関数である。<br> | ||
73行目: | 73行目: | ||
<br> | <br> | ||
以下の例では、calloc関数を使用してメモリ領域を動的に確保している。<br> | 以下の例では、calloc関数を使用してメモリ領域を動的に確保している。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
104行目: | 104行目: | ||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
== 確保したメモリ領域のサイズを変更する == | == 確保したメモリ領域のサイズを変更する == | ||
malloc関数やcalloc関数等で確保したメモリ領域のサイズを変更するには、stdlib.hのrealloc関数を使用する。<br> | malloc関数やcalloc関数等で確保したメモリ領域のサイズを変更するには、stdlib.hのrealloc関数を使用する。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
void *realloc(void *ptr, size_t size); | void *realloc(void *ptr, size_t size); | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
realloc関数は、まず、ptrが指すメモリ領域を解放した後、大きさがsizeである新しいメモリ領域を確保する関数である。<br> | realloc関数は、まず、ptrが指すメモリ領域を解放した後、大きさがsizeである新しいメモリ領域を確保する関数である。<br> | ||
120行目: | 120行目: | ||
<br> | <br> | ||
以下の例では、realloc関数を使用して、確保したメモリ領域のサイズを変更している。<br> | 以下の例では、realloc関数を使用して、確保したメモリ領域のサイズを変更している。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
164行目: | 164行目: | ||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
170行目: | 170行目: | ||
malloc関数やcalloc関数、realloc関数で確保したメモリ領域を解放するには、stdlib.hのfree関数を使用する。<br> | malloc関数やcalloc関数、realloc関数で確保したメモリ領域を解放するには、stdlib.hのfree関数を使用する。<br> | ||
free関数は、ptrが指すメモリ領域を解放する関数である。<br> | free関数は、ptrが指すメモリ領域を解放する関数である。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
void free (void *ptr); | void free (void *ptr); | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
以下の例として、free関数を使用してメモリ領域を開放している。<br> | 以下の例として、free関数を使用してメモリ領域を開放している。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
198行目: | 198行目: | ||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
== 配列やメモリ領域の内容を初期化する == | == 配列やメモリ領域の内容を初期化する == | ||
配列を初期化する場合は、以下のように配列の宣言時に初期化子を使用する。<br> | 配列を初期化する場合は、以下のように配列の宣言時に初期化子を使用する。<br> | ||
< | <syntaxhighlight lang="c"> | ||
int a1[] = {1, 2, 3}; /* それぞれ異なる値で初期化 */ | int a1[] = {1, 2, 3}; /* それぞれ異なる値で初期化 */ | ||
int a2[256] = {0}; /* 同一の値で初期化 */ | int a2[256] = {0}; /* 同一の値で初期化 */ | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
また、malloc関数等を使用して動的に確保したメモリ領域を初期化する場合や、配列を宣言時以外に初期化する場合は、<br> | また、malloc関数等を使用して動的に確保したメモリ領域を初期化する場合や、配列を宣言時以外に初期化する場合は、<br> | ||
221行目: | 221行目: | ||
<br> | <br> | ||
memmove関数は、memcpy関数と似ているが、領域の重なり合うオブジェクト間でコピーを行う場合でも正しく動作する。<br> | memmove関数は、memcpy関数と似ているが、領域の重なり合うオブジェクト間でコピーを行う場合でも正しく動作する。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <string.h> | #include <string.h> | ||
227行目: | 227行目: | ||
void *memmove(void *s1, const void *s2, size_t n); | void *memmove(void *s1, const void *s2, size_t n); | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
以下の例では、memcpy関数を使用して、int型の配列をコピーしている。<br> | 以下の例では、memcpy関数を使用して、int型の配列をコピーしている。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
253行目: | 253行目: | ||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
261行目: | 261行目: | ||
memcmp関数は、s1が指すオブジェクトの始めのn文字と、s2が指すオブジェクトの始めのn文字を比較する関数である。<br> | memcmp関数は、s1が指すオブジェクトの始めのn文字と、s2が指すオブジェクトの始めのn文字を比較する関数である。<br> | ||
memcmp関数は、比較するオブジェクトが同じなら0、s1 > s2なら正の整数、s1 < s2なら負の整数を返す。<br> | memcmp関数は、比較するオブジェクトが同じなら0、s1 > s2なら正の整数、s1 < s2なら負の整数を返す。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <string.h> | #include <string.h> | ||
int memcmp (const void *s1, const void *s2, size_t n); | int memcmp (const void *s1, const void *s2, size_t n); | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
以下の例では、memcmp関数を使用して、int型の配列を比較している。<br> | 以下の例では、memcmp関数を使用して、int型の配列を比較している。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
314行目: | 314行目: | ||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
322行目: | 322行目: | ||
qsort関数は、baseが指すオブジェクトの配列(要素数がnmemb個、各要素の大きさがsizeである配列)を、compareが指す比較関数にしたがって整列する関数である。<br> | qsort関数は、baseが指すオブジェクトの配列(要素数がnmemb個、各要素の大きさがsizeである配列)を、compareが指す比較関数にしたがって整列する関数である。<br> | ||
ちなみに、qsort関数の名前はクイックソートに由来するが、内部でクイックソートアルゴリズムを使用してる保障はない。(処理系定義)<br> | ちなみに、qsort関数の名前はクイックソートに由来するが、内部でクイックソートアルゴリズムを使用してる保障はない。(処理系定義)<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
void qsort (void *base, size_t nmemb, size_t size, int (*compare\)(const void *, const void *)); | void qsort (void *base, size_t nmemb, size_t size, int (*compare\)(const void *, const void *)); | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
qsort関数の引数は以下の通りである。<br> | qsort関数の引数は以下の通りである。<br> | ||
340行目: | 340行目: | ||
<br> | <br> | ||
以下の例では、qsort関数を使用して、int型の配列を昇順に整列している。<br> | 以下の例では、qsort関数を使用して、int型の配列を昇順に整列している。<br> | ||
< | <syntaxhighlight lang="c"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
388行目: | 388行目: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br><br> | |||
== 配列やメモリ領域の内容から文字を探索する == | |||
C言語で、配列やメモリ領域の内容から文字を探索するには、string.hのmemchr関数を使用する。<br> | |||
<br> | |||
memchr関数は、sが指すオブジェクトの先頭からn文字分検索して、文字cが最初に現れる位置を探索する関数である。<br> | |||
なお、探索中はsが指すオブジェクトとcはunsigned char型として解釈される。<br> | |||
memchr関数は、strchr関数と似ているが、'\0'があっても探索を続ける。<br> | |||
<br> | |||
memchr関数は、文字が見つかった場合は探し出した文字へのポインタを返し、文字が見つからなかった場合はNULLを返す。<br> | |||
memchr関数を利用すると、メモリ領域の中で指定した文字が現れる位置を探すことができる。<br> | |||
<syntaxhighlight lang="c"> | |||
#include <string.h> | |||
void *memchr (const void *s, int c, size_t n); | |||
</syntaxhighlight> | |||
<br> | |||
以下の例では、memchr関数を使用して、char型の配列を探索している。<br> | |||
<syntaxhighlight lang="c"> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#define N 256 | |||
int main(void) | |||
{ | |||
char s[] = {'S', 'n', 'o', 'o', 'p', 'y', '\0', 'z'}; | |||
char *ret; | |||
int c; | |||
/* 入力 */ | |||
puts("文字を入力してください."); | |||
c = getchar(); | |||
/* s が指す配列中に c があるか? */ | |||
if ((ret = (char *)memchr(s, c, sizeof(char) * N)) != NULL) | |||
{ | |||
printf("%cは%d番目にありました.\n", c, ret - s); | |||
} | |||
else | |||
{ | |||
printf("%cはありませんでした.\n", c); | |||
} | |||
return EXIT_SUCCESS; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== 配列やメモリ領域の内容から任意の値を探索する == | |||
C言語で、配列やメモリ領域の内容から任意の値を探索するには、stdlib.hのbsearch関数を使用する。<br> | |||
<br> | |||
bsearch関数は、baseが指すオブジェクトの配列(要素数がnmemb個、各要素の大きさがsizeである配列)から、<br> | |||
keyが指すオブジェクトに一致する要素を探索する関数である。<br> | |||
なお、baseが指す配列は昇順に整列(ソート)されている必要がある。<br> | |||
<syntaxhighlight lang="c"> | |||
#include <stdlib.h> | |||
void *bsearch (const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); | |||
</syntaxhighlight> | |||
<br> | |||
bsearch関数の引数は、以下の通りとなる。<br> | |||
* key: 探索キー | |||
* base: 探索する配列 | |||
* nmemb: 配列の要素数 | |||
* size: 配列の個々の要素のサイズ | |||
* compar: 比較関数 | |||
<br> | |||
bsearch関数を使用するには、事前にプログラマが比較関数を実装する必要がある。また、比較関数は以下のルールに基づいて実装する。<br> | |||
比較関数は、keyへのポインタを第1引数とし、配列要素へのポインタを第2引数として呼び出される。<br> | |||
* 第1引数が第2引数より小さい場合 : 0より小さい値を返す | |||
* 第1引数が第2引数と一致する場合 : 0を返す | |||
* 第1引数が第2引数よりも大きい場合 : 0より大きい値を返す | |||
<br> | |||
以下の例では、bsearch関数を使用して、int型の配列を探索している。<br> | |||
<syntaxhighlight lang="c"> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
int compare(const int *val1, const int *val2); | |||
int main(void) | |||
{ | |||
int ary[] = {1, 2, 3, 4, 5, 6, 7, 8}; | |||
int key, *result; | |||
int n = sizeof(ary) / sizeof(ary[0]); | |||
/* keyを入力 */ | |||
scanf("%d", &key); | |||
/* 探索 */ | |||
result = bsearch(&key, ary, n, sizeof(int), (int (*)(const void *, const void *))compare); | |||
if ( result == NULL ) | |||
{ | |||
fprintf(stderr, "%dは見つかりませんでした.\n", key); | |||
} | |||
else | |||
{ | |||
printf("%dは配列の%d番目の要素です.\n", key, (int)(result - &ary[0])); | |||
} | |||
return EXIT_SUCCESS; | |||
} | |||
/* 比較関数 */ | |||
int compare(const int *val1, const int *val2) | |||
{ | |||
if ( *val1 < *val2 ) | |||
{ | |||
return -1; | |||
} | |||
else if ( *val1 == * val2 ) | |||
{ | |||
return 0; | |||
} | |||
else | |||
{ | |||
return 1; | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br><br> | <br><br> | ||
__FORCETOC__ | __FORCETOC__ | ||
[[カテゴリ:C]] | [[カテゴリ:C]] |
2021年11月15日 (月) 01:56時点における最新版
メモリ領域を動的に確保する
C言語で、メモリ領域を動的に確保するには、stdlib.hのmalloc関数を使用する。
#include <stdlib.h>
void *malloc(size_t size);
malloc関数はsizeバイト分のメモリ領域を確保して、そのメモリ領域へのポインタを返す関数である。
なお、メモリ領域の確保に失敗した場合は、NULLを返す。
malloc関数で確保したメモリ領域は、free関数で解放する。
malloc関数を使用したメモリの動的確保は、多くの場合、以下のように実装する。
以下の例として、int型のデータが10個入るサイズのメモリ領域を確保している。
int *ptr = nullptr;
/* int型のデータが1 個入るサイズのメモリ領域を確保 */
if ((ptr = (int *)malloc(sizeof(int) * 10)) == NULL)
{
/* エラー処理 */
}
/* 何らかの処理 */
/* メモリ領域の解放 */
free(ptr);
以下の例では、malloc関数を使用して、メモリ領域を動的に確保している。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *ptr = nullptr, *work = nullptr;
/* int 型のデータが 10 個入るサイズのメモリ領域を確保 */
if ((ptr = (int *)malloc(sizeof(int) * 10)) == NULL)
{
fprintf(stderr, "メモリ領域を確保に失敗しました.\n");
exit(EXIT_FAILURE);
}
work = ptr;
for ( int i = 0; i < 10; i++)
{
work[i] = i;
printf("%d ", work[i]);
}
printf("\n");
/* メモリ領域の解放 */
free(ptr);
return EXIT_SUCCESS;
}
メモリ領域を確保して、その領域を0で初期化する
C言語で、メモリ領域を動的に確保して、その領域を0で初期化するには、stdlib.hのcalloc関数を使用する。
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
calloc関数は、sizeバイトの大きさを持つオブジェクトがnmemb個分入るメモリ領域を確保して、その領域のすべてのビットを0で初期化する関数である。
メモリ領域の確保に成功した場合は、そのメモリ領域へのポインタを返し、失敗した場合はNULLを返す。
また、calloc関数で確保したメモリ領域は、free関数で解放する。
以下の例では、calloc関数を使用してメモリ領域を動的に確保している。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
double *ptr = nullptr;
int nmemb = 3;
/* double サイズ 3 個分の領域を確保 */
if ((ptr = (double *)calloc(nmemb, sizeof(double))) == NULL)
{
fprintf(stderr, "メモリ領域を確保に失敗しました.\n");
return EXIT_FAILURE;
}
/* 適当に値を入力 */
ptr[0] = 1950;
/* メモリ領域の内容を表示する */
for ( int i = 0; i < nmemb; i++ )
{
printf(" %.1f", ptr[i]);
}
printf("\n");
/* メモリ領域の解放 */
free(ptr);
return EXIT_SUCCESS;
}
確保したメモリ領域のサイズを変更する
malloc関数やcalloc関数等で確保したメモリ領域のサイズを変更するには、stdlib.hのrealloc関数を使用する。
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
realloc関数は、まず、ptrが指すメモリ領域を解放した後、大きさがsizeである新しいメモリ領域を確保する関数である。
新しいメモリ領域は、可能な限り開放する前の古いメモリ領域の内容を引き継ぐが、古いメモリ領域の大きさを超えた部分の値は不定となる。
また、realloc関数は、メモリ領域の確保に成功した場合は、そのメモリ領域へのポインタを返し、失敗した場合はNULLを返す。
以下の例では、realloc関数を使用して、確保したメモリ領域のサイズを変更している。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *ptr = nullptr;
/* intサイズ10個分のメモリ領域を確保 */
if ((ptr = (int *)malloc(sizeof(int) * 10)) == NULL )
{
fprintf(stderr, "メモリ領域が確保できません.\n");
return EXIT_FAILURE;
}
/* 確保したメモリ領域に値を格納して表示 */
printf("realloc 関数使用前.\n");
for ( int i = 0; i < 10; i++ )
{
ptr[i] = i;
printf(" %d", ptr[i]);
}
printf("\n");
/* intサイズ10個分から15個分のメモリ領域に拡張する */
if ((ptr = (int *)realloc(ptr, sizeof(int) * 15)) == NULL)
{
fprintf(stderr, "メモリが確保できません。\n");
return EXIT_FAILURE;
}
/* 確保したメモリ領域に値を格納して表示 */
printf("\nrealloc関数使用後.\n");
for ( int i = 0; i < 15; i++ )
{
ptr[i] = i;
printf(" %d", ptr[i]);
}
printf("\n");
/* メモリ領域の解放 */
free(ptr);
return EXIT_SUCCESS;
}
メモリ領域を解放する
malloc関数やcalloc関数、realloc関数で確保したメモリ領域を解放するには、stdlib.hのfree関数を使用する。
free関数は、ptrが指すメモリ領域を解放する関数である。
#include <stdlib.h>
void free (void *ptr);
以下の例として、free関数を使用してメモリ領域を開放している。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *ptr = nullptr;
/* int サイズのメモリ領域を確保 */
if ((ptr = (int *)malloc(sizeof(int))) == NULL)
{
fprintf(stderr, "メモリ領域の確保に失敗しました.\n");
exit(EXIT_FAILURE);
}
/* メモリ領域の解放 */
free(ptr);
printf("メモリ領域を解放しました.\n");
return EXIT_SUCCESS;
}
配列やメモリ領域の内容を初期化する
配列を初期化する場合は、以下のように配列の宣言時に初期化子を使用する。
int a1[] = {1, 2, 3}; /* それぞれ異なる値で初期化 */
int a2[256] = {0}; /* 同一の値で初期化 */
また、malloc関数等を使用して動的に確保したメモリ領域を初期化する場合や、配列を宣言時以外に初期化する場合は、
反復処理等を使用して、個々の要素に対して個別に値を格納していく必要がある。
文字配列(文字列)を初期化する場合は、memset関数を使用する。これについては、ページの"文字列を初期化する"を参照する。
配列やメモリ領域の内容をコピーする
C言語で、配列やメモリ領域の内容をコピーするには、string.hのmemcpy関数またはmemmove関数を使用する。
memcpy関数は、s2が指すオブジェクトからs1が指すオブジェクトにn文字コピーする関数である。
なお、領域の重なり合うオブジェクト間でコピーが行われるときの動作は未定義である。
memmove関数は、memcpy関数と似ているが、領域の重なり合うオブジェクト間でコピーを行う場合でも正しく動作する。
#include <string.h>
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
以下の例では、memcpy関数を使用して、int型の配列をコピーしている。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 8
int main(void)
{
int x1[] = {1, 2, 3, 4, 5, 6, 7, 8};
int x2[N] = {0};
/* メモリ領域内の内容をコピー */
memcpy(x2, x1, sizeof(int) * N);
/* x1 と x2 の各要素を表示 */
for ( int i = 0; i < N; i++ )
{
printf("x1[%d] : %d, x2[%d] : %d\n", i, x1[i], i, x2[i]);
}
return EXIT_SUCCESS;
}
配列やメモリ領域の内容を比較する
C言語で、配列やメモリ領域の内容を比較するには、string.hのmemcmp関数を使用する。
memcmp関数は、s1が指すオブジェクトの始めのn文字と、s2が指すオブジェクトの始めのn文字を比較する関数である。
memcmp関数は、比較するオブジェクトが同じなら0、s1 > s2なら正の整数、s1 < s2なら負の整数を返す。
#include <string.h>
int memcmp (const void *s1, const void *s2, size_t n);
以下の例では、memcmp関数を使用して、int型の配列を比較している。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 8
int main(void)
{
int x1[] = {0, 1, 2, 3, 4, 5, 6, 7};
int x2[] = {0, 1, 2, 3, 4, 5, 6, 6};
int x3[] = {0, 1, 2, 3, 4, 5, 6, 8};
int x4[] = {0, 1, 2, 3, 4, 5, 6, 7};
/* x1 と x2 を比較 */
if ( memcmp(x1, x2, sizeof(int) * N) == 0 )
{
printf("x1とx2は同じ要素を持つ配列です.\n");
}
else
{
printf("x1とx2は異なる要素を持つ配列です.\n");
}
/* x1 と x3 を比較 */
if ( memcmp(x1, x3, sizeof(int) * N) == 0 )
{
printf("x1とx3は同じ要素を持つ配列です.\n");
}
else
{
printf("x1とx3は異なる要素を持つ配列です.\n");
}
/* x1 と x4 を比較 */
if ( memcmp(x1, x4, sizeof(int) * N) == 0 )
{
printf("x1とx4は同じ要素を持つ配列です.\n");
}
else
{
printf("x1とx4は異なる要素を持つ配列です.\n");
}
return EXIT_SUCCESS;
}
配列やメモリ領域の内容を整列(ソート)する
C言語で、配列やメモリ領域の内容を整列(ソート)するには、stdlib.hのqsort関数を使用する。
qsort関数は、baseが指すオブジェクトの配列(要素数がnmemb個、各要素の大きさがsizeである配列)を、compareが指す比較関数にしたがって整列する関数である。
ちなみに、qsort関数の名前はクイックソートに由来するが、内部でクイックソートアルゴリズムを使用してる保障はない。(処理系定義)
#include <stdlib.h>
void qsort (void *base, size_t nmemb, size_t size, int (*compare\)(const void *, const void *));
qsort関数の引数は以下の通りである。
- base : 整列したい配列
- nmemb : 配列の要素数
- size : 配列の個々の要素のサイズ
- compar : 比較関数
qsort関数を使用するには、事前にプログラマが比較関数を実装する必要がある。比較関数は、以下のルールに基づいて実装する必要がある。
- 第1引数が第2引数より小さい場合 : 0より小さい値を返す
- 第1引数が第2引数と一致する場合 : 0を返す
- 第1引数が第2引数よりも大きい場合 : 0より大きい値を返す
以下の例では、qsort関数を使用して、int型の配列を昇順に整列している。
#include <stdio.h>
#include <stdlib.h>
int compare(const int *val1, const int *val2);
int main(void)
{
int ary[] = {9, 8, 7, 6, 5, 4, 3, 2, 1};
int n = sizeof(ary) / sizeof(ary[0]);
/* 配列の内容を表示 */
printf("整列前: ");
for ( int i = 0; i < n; i++ )
{
printf("%d", ary[i]);
}
/* qsort 関数を使用して昇順に並び替える */
qsort(ary, n, sizeof(int), (int (*)(const void *, const void *))compare);
/* 配列の内容を表示 */
printf("\n整列後: ");
for ( int i = 0; i < n; i++ )
{
printf("%d", ary[i]);
}
printf("\n");
return EXIT_SUCCESS;
}
/* 比較関数 */
int compare(const int *val1, const int *val2)
{
if ( *val1 < *val2 )
{
return -1;
}
else if ( *val1 == * val2 )
{
return 0;
}
else
{
return 1;
}
}
配列やメモリ領域の内容から文字を探索する
C言語で、配列やメモリ領域の内容から文字を探索するには、string.hのmemchr関数を使用する。
memchr関数は、sが指すオブジェクトの先頭からn文字分検索して、文字cが最初に現れる位置を探索する関数である。
なお、探索中はsが指すオブジェクトとcはunsigned char型として解釈される。
memchr関数は、strchr関数と似ているが、'\0'があっても探索を続ける。
memchr関数は、文字が見つかった場合は探し出した文字へのポインタを返し、文字が見つからなかった場合はNULLを返す。
memchr関数を利用すると、メモリ領域の中で指定した文字が現れる位置を探すことができる。
#include <string.h>
void *memchr (const void *s, int c, size_t n);
以下の例では、memchr関数を使用して、char型の配列を探索している。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 256
int main(void)
{
char s[] = {'S', 'n', 'o', 'o', 'p', 'y', '\0', 'z'};
char *ret;
int c;
/* 入力 */
puts("文字を入力してください.");
c = getchar();
/* s が指す配列中に c があるか? */
if ((ret = (char *)memchr(s, c, sizeof(char) * N)) != NULL)
{
printf("%cは%d番目にありました.\n", c, ret - s);
}
else
{
printf("%cはありませんでした.\n", c);
}
return EXIT_SUCCESS;
}
配列やメモリ領域の内容から任意の値を探索する
C言語で、配列やメモリ領域の内容から任意の値を探索するには、stdlib.hのbsearch関数を使用する。
bsearch関数は、baseが指すオブジェクトの配列(要素数がnmemb個、各要素の大きさがsizeである配列)から、
keyが指すオブジェクトに一致する要素を探索する関数である。
なお、baseが指す配列は昇順に整列(ソート)されている必要がある。
#include <stdlib.h>
void *bsearch (const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
bsearch関数の引数は、以下の通りとなる。
- key: 探索キー
- base: 探索する配列
- nmemb: 配列の要素数
- size: 配列の個々の要素のサイズ
- compar: 比較関数
bsearch関数を使用するには、事前にプログラマが比較関数を実装する必要がある。また、比較関数は以下のルールに基づいて実装する。
比較関数は、keyへのポインタを第1引数とし、配列要素へのポインタを第2引数として呼び出される。
- 第1引数が第2引数より小さい場合 : 0より小さい値を返す
- 第1引数が第2引数と一致する場合 : 0を返す
- 第1引数が第2引数よりも大きい場合 : 0より大きい値を返す
以下の例では、bsearch関数を使用して、int型の配列を探索している。
#include <stdio.h>
#include <stdlib.h>
int compare(const int *val1, const int *val2);
int main(void)
{
int ary[] = {1, 2, 3, 4, 5, 6, 7, 8};
int key, *result;
int n = sizeof(ary) / sizeof(ary[0]);
/* keyを入力 */
scanf("%d", &key);
/* 探索 */
result = bsearch(&key, ary, n, sizeof(int), (int (*)(const void *, const void *))compare);
if ( result == NULL )
{
fprintf(stderr, "%dは見つかりませんでした.\n", key);
}
else
{
printf("%dは配列の%d番目の要素です.\n", key, (int)(result - &ary[0]));
}
return EXIT_SUCCESS;
}
/* 比較関数 */
int compare(const int *val1, const int *val2)
{
if ( *val1 < *val2 )
{
return -1;
}
else if ( *val1 == * val2 )
{
return 0;
}
else
{
return 1;
}
}