https://youtu.be/sWtCdhvSDJA
\textcolor{pink}{四国めたん: }教師役ですわ
\textcolor{lime}{ずんだもん: }生徒役なのだ
\footnotesize \textcolor{pink}{四国めたん:} 皆さん、こんにちは。四国めたんです
\footnotesize \textcolor{lime}{ずんだもん:} ずんだもんなのだ。こんにちはなのだ
\footnotesize \textcolor{pink}{四国めたん:} 今回もC言語のお勉強をしていきましょう
\footnotesize \textcolor{lime}{ずんだもん:} レッツゴーなのだ
\footnotesize \textcolor{pink}{四国めたん:} 前回は 大きなサイズの配列 と 動的メモリ配置 についてお話ししましたわ
\footnotesize \textcolor{lime}{ずんだもん:} おぼえているのだ
\footnotesize \textcolor{pink}{四国めたん:} 今回はそれらの大きなサイズのメモリ領域に対する操作を簡単にする関数を見て行きますわ
\footnotesize \textcolor{lime}{ずんだもん:} 簡単になるのは良いことなのだ
\footnotesize \textcolor{pink}{四国めたん:} なお基本的なメモリ操作の関数は"string.h"で宣言されているので最初にインクルードする必要がありますわ
\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ
memset
\footnotesize \textcolor{pink}{四国めたん:} まず最初はmemset
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} memset
?
\footnotesize \textcolor{pink}{四国めたん:} はい、指定したメモリ領域の各バイトを指定の値にセットする関数ですわ
\footnotesize \textcolor{lime}{ずんだもん:} お~、forループでセットする必要がなくなるのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはvoid* memset(void* ptr, int value, size_t num)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} 詳しく説明してほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
\footnotesize \textcolor{pink}{四国めたん:} まず、メモリ領域の先頭のポインタをptr
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} malloc
で取得したメモリ領域をセットするのか?
\footnotesize \textcolor{pink}{四国めたん:} それ以外にも配列などもセット可能ですわね
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} 次に、値をセットする領域のサイズをバイト単位でnum
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} バイト単位なのか
\footnotesize \textcolor{pink}{四国めたん:} はい、malloc
と同様ですわね
\footnotesize \textcolor{lime}{ずんだもん:} ところでnum
がメモリ領域のサイズより大きい場合はどうなるのだ?
\footnotesize \textcolor{pink}{四国めたん:} 指定通りにデータをセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} それって大丈夫なのか?
\footnotesize \textcolor{pink}{四国めたん:} いいえ、他の重要なデータを破壊する可能性があるので、大丈夫ではありませんわ
\footnotesize \textcolor{pink}{四国めたん:} ですので、num
はメモリ領域のサイズを超えないようにして下さいね
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} 最後に、セットする値はvalue
で指定しますわ
\footnotesize \textcolor{lime}{ずんだもん:} int型 ということは、4バイトのデータを指定できるのか?
\footnotesize \textcolor{pink}{四国めたん:} いいえ、memset
は各バイトに値をセットする関係上、0~255(0x00~0xFF)の指定のみ有効ですわ
\footnotesize \textcolor{lime}{ずんだもん:} 255よりも大きな値をセットした場合はどうなるのだ?
\footnotesize \textcolor{pink}{四国めたん:} 関数内部でunsigned char
にキャストされてからセットされますわ
\footnotesize \textcolor{lime}{ずんだもん:} unsigned char
?
\footnotesize \textcolor{pink}{四国めたん:} char
が-128~127の整数を表すことができる型だというのは覚えていますわね
\footnotesize \textcolor{lime}{ずんだもん:} とうぜんなのだ
\footnotesize \textcolor{pink}{四国めたん:} それに対して、unsigned char
は、0~255の正の整数を表すことができる型ですわ
\footnotesize \textcolor{lime}{ずんだもん:} unsigned
は 符号なし という意味なので、正の整数なのか...
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{pink}{四国めたん:} ただ、意図しない値がセットされることになるので、0~255以外の値はセットしないことをお勧めしますわ
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} ちなみに戻り値に関してはptr
にセットした値がそのまま返りますわ
\footnotesize \textcolor{pink}{四国めたん:} では、サンプルコードを見ていきましょう
#include <stdio.h>
#include <string.h>
void main() {
int a[] = {1, 2, 3};
int size = sizeof(a);
memset(a, 0, size);
printf("aのサイズは%dバイトです。\n", size);
printf("a[0]の値は%dです。\n", a[0]);
printf("a[1]の値は%dです。\n", a[1]);
printf("a[2]の値は%dです。\n", a[2]);
}
\footnotesize \textcolor{lime}{ずんだもん:} 「aのサイズは12バイトです。」、「a[0]の値は0です。」、「a[1]の値は0です。」、「a[2]の値は0です。」と表示されたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、今回は配列の要素を0クリアしていますわね
\footnotesize \textcolor{lime}{ずんだもん:} 結果として全ての要素は0と表示されたのだ
\footnotesize \textcolor{lime}{ずんだもん:} とりあえずプログラムの説明をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、まず#include <string.h>
で"string.h"をインクルードしていますわ
\footnotesize \textcolor{lime}{ずんだもん:} メモリ操作の関数は"string.h"ファイルで宣言されているのだ
\footnotesize \textcolor{pink}{四国めたん:} そして配列a
に初期値を設定していますわ
\footnotesize \textcolor{lime}{ずんだもん:} 各要素に0以外の値をセットしているのだ
\footnotesize \textcolor{pink}{四国めたん:} 次に配列のサイズをsizeof
演算子で、バイト単位で取得しておきますわ
\footnotesize \textcolor{lime}{ずんだもん:} たしか、配列に対してはsizeof
演算子でサイズをバイト単位で取得できたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、でも 動的メモリ配置 で取得したメモリ領域についてはsizeof
演算子でのサイズ取得はできませんわ
\footnotesize \textcolor{lime}{ずんだもん:} おぼえているのだ
\footnotesize \textcolor{pink}{四国めたん:} 次にmemset
で配列a
の全体を0でクリアしていますわ
\footnotesize \textcolor{lime}{ずんだもん:} 配列名だけを指定すれば、配列へのポインタと同じになるのだ
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{pink}{四国めたん:} なおmemset
の"value"引数には、0や0xFFや0xEFなどの16進数、 a などのASCIIコードを指定することが多いですわ
\footnotesize \textcolor{lime}{ずんだもん:} そうなのか...
\footnotesize \textcolor{pink}{四国めたん:} また、memset
の"ptr"には、配列以外にもmalloc
で取得したメモリ領域や構造体等へのポインタを指定できますわね
\footnotesize \textcolor{lime}{ずんだもん:} いろいろと便利に使えそうなのだ
memcpy
\footnotesize \textcolor{pink}{四国めたん:} 次はmemcpy
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} memcpy
?
\footnotesize \textcolor{pink}{四国めたん:} はい、memcpy
は指定したメモリ領域間で、データをコピーしますわ
\footnotesize \textcolor{lime}{ずんだもん:} データのコピーは便利なのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはvoid* memcpy(void* dst, const void* src, size_t num)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} 詳しく説明してほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
\footnotesize \textcolor{pink}{四国めたん:} まず、コピー元のポインタをsrc
に、コピー先のポインタをdst
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} コピーするデータのサイズをバイト単位でnum
にセットするのか?
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{pink}{四国めたん:} ちなみに、データの コピー ですので、元のデータが残ることが前提ですわ
\footnotesize \textcolor{pink}{四国めたん:} ですのでコピー元とコピー先のメモリ領域が重なっていてはいけませんわね
\footnotesize \textcolor{lime}{ずんだもん:} 領域が重なるとどうなるのだ?
\footnotesize \textcolor{pink}{四国めたん:} Visual Studioですと問題なくデータのコピーを行えますが、一般的には正常にコピーされない場合がありますわ
\footnotesize \textcolor{lime}{ずんだもん:} ところでnum
にメモリ領域のサイズより大きな値をセットした場合はどうなるのだ?
\footnotesize \textcolor{pink}{四国めたん:} 指定通り、データをコピーしますわ
\footnotesize \textcolor{pink}{四国めたん:} 当然、他の重要なデータを破壊することになる可能性がありますわね
\footnotesize \textcolor{lime}{ずんだもん:} たいへんなのだ
\footnotesize \textcolor{pink}{四国めたん:} なお戻り値に関してはdst
にセットした値がそのまま返りますわ
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} では、サンプルコードを見ていきましょう
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE (3)
void main() {
int size_byte = sizeof(int) * SIZE;
int a[SIZE] = {1, 2, 3};
int* p = (int*)malloc(size_byte);
if (p != NULL) {
memset(p, 0, size_byte);
memcpy(p, a, size_byte);
printf("*pの値は%dです。\n", *p);
printf("*(p+1)の値は%dです。\n", *(p + 1));
printf("*(p+2)の値は%dです。\n", *(p + 2));
}
free(p);
p = NULL;
}
\footnotesize \textcolor{lime}{ずんだもん:} malloc
で確保したメモリ領域に、配列のデータをmemcpy
でコピーしているのだ
\footnotesize \textcolor{pink}{四国めたん:} とりあえずプログラムの説明をしますわね
\footnotesize \textcolor{lime}{ずんだもん:} おねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} まず、malloc
で配列a
と同じサイズでメモリ領域を確保していますわ
\footnotesize \textcolor{lime}{ずんだもん:} メモリ領域のサイズはbyte_size
として int型 のサイズと配列の要素数から計算しているのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、sizeof(a)
としてもOKですわね
\footnotesize \textcolor{pink}{四国めたん:} そして、memset
で確保したメモリ領域を0クリアした後、memcpy
で配列a
の全データをコピーしていますわ
\footnotesize \textcolor{lime}{ずんだもん:} memset
での0クリアは必要なのか?
\footnotesize \textcolor{pink}{四国めたん:} はっきり言って必要ないのですが、0クリアによる初期化の例として入れてみましたわ
\footnotesize \textcolor{lime}{ずんだもん:} 大人の事情なのだ
\footnotesize \textcolor{pink}{四国めたん:} 最後にfree
でメモリ領域の解放をしていますわ
\footnotesize \textcolor{lime}{ずんだもん:} 忘れたら大変なのだ
memmove
\footnotesize \textcolor{pink}{四国めたん:} 次はmemmove
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} memmove
?
\footnotesize \textcolor{pink}{四国めたん:} はい、指定したメモリ領域間で、データをコピーする関数ですわ
\footnotesize \textcolor{lime}{ずんだもん:} memcpy
とはどう違うのだ?
\footnotesize \textcolor{pink}{四国めたん:} memmove
はmemcpy
と異なり移動元と移動先のメモリ領域が重なっていても問題なくコピーが可能ということですわ
\footnotesize \textcolor{lime}{ずんだもん:} お~、それは便利なのだ
\footnotesize \textcolor{pink}{四国めたん:} ただ、重なっているメモリ領域については、コピーされたデータで上書きされますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} 形式としてはvoid* memmove(void* dst, const void* src, size_t num)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} 形式はmemcpy
と同じなのだ
\footnotesize \textcolor{pink}{四国めたん:} 注意点も同じで、移動するデータのサイズはメモリ領域より大きい値をセットしてはいけませんわ
\footnotesize \textcolor{lime}{ずんだもん:} 注意するのだ
\footnotesize \textcolor{pink}{四国めたん:} では、サンプルコードを見ていきましょう
#include <stdio.h>
#include <string.h>
void main() {
int a[] = {1, 2, 3, 4};
memmove(&a[1], &a[0], (sizeof(int) * 3));
printf("a[0]の値は%dです。\n", a[0]);
printf("a[1]の値は%dです。\n", a[1]);
printf("a[2]の値は%dです。\n", a[2]);
printf("a[3]の値は%dです。\n", a[3]);
}
\footnotesize \textcolor{lime}{ずんだもん:} 内容がよく分からないのだ
\footnotesize \textcolor{pink}{四国めたん:} 配列の内部で要素のデータを移動するプログラムですわ
\footnotesize \textcolor{pink}{四国めたん:} 要素数4の配列でa[0]からa[2]の要素をa[1]からa[3]に移動していますわね
\footnotesize \textcolor{lime}{ずんだもん:} なるほど、memmove
でサイズを配列の要素数ではなく、sizeof(int) * 3
としているのは、3つの要素を移動するためか...
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{lime}{ずんだもん:} 移動元のポインタは要素0のアドレスを、移動先のポインタを要素1のアドレスに指定しているのも、そのためか
\footnotesize \textcolor{pink}{四国めたん:} はい、結果として{1, 2, 3, 4}の配列が{1, 1, 2, 3}の配列になっていますわ
\footnotesize \textcolor{lime}{ずんだもん:} つまり、メモリ領域が重なっていても、正常にデータの移動が行われているということか...
\footnotesize \textcolor{pink}{四国めたん:} はい、その通りですわ
\footnotesize \textcolor{lime}{ずんだもん:} ところで、memmove
の方が使いやすいし、memcpy
はいらないのではないのか?
\footnotesize \textcolor{pink}{四国めたん:} たしかにそうなのですが、一般的にmemcpy
は制約がある分memmove
よりも高速に動作しますわ
\footnotesize \textcolor{lime}{ずんだもん:} 速度が必要なプログラムではmemcpy
を優先した方がいいのか...
\footnotesize \textcolor{pink}{四国めたん:} まぁ、今時のコンピューターは高速に動作するので、特にこだわりがなければmemmove
を使う方がいいでしょう
memcmp
\footnotesize \textcolor{pink}{四国めたん:} 最後はmemcmp
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} memcmp
?
\footnotesize \textcolor{pink}{四国めたん:} はい、指定したメモリ領域を比較して同じかどうかをチェックする関数ですわ
\footnotesize \textcolor{lime}{ずんだもん:} とりあえず便利なのか?
\footnotesize \textcolor{pink}{四国めたん:} 結構便利ですわね
\footnotesize \textcolor{pink}{四国めたん:} 形式としてはint memcmp(const void* ptr1, const void* ptr2, size_t num)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} 詳しく説明してほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
\footnotesize \textcolor{pink}{四国めたん:} まず、比較するメモリ領域のポインタをptr1
とptr2
にセットしますわ
\footnotesize \textcolor{pink}{四国めたん:} そして、データの比較はnum
にセットした値のバイト数分をバイト単位で行いますわ
\footnotesize \textcolor{lime}{ずんだもん:} バイト毎にデータを比較するのか?
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{pink}{四国めたん:} そして、比較結果が戻り値として返りますわ
\footnotesize \textcolor{lime}{ずんだもん:} 戻り値は int型 となっているが、どんな値が返ってくるのだ?
\footnotesize \textcolor{pink}{四国めたん:} 完全に一致していれば0が、一致していなければ0以外が返りますわ
\footnotesize \textcolor{pink}{四国めたん:} では、サンプルコードを見ていきましょう
#include <stdio.h>
#include <string.h>
void main() {
int a[] = {1, 2, 3};
int b[] = {1, 2, 3};
if (memcmp(a, b, sizeof(a) {
printf("aとbは同じではありません\n");
} else {
printf("aとbは同じです\n");
}
}
\footnotesize \textcolor{lime}{ずんだもん:} 「aとbは同じです」と表示されたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、同じ要素を持つ配列同士を比較したので当然ですわね
\footnotesize \textcolor{lime}{ずんだもん:} プログラムの説明をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、今回はmemcmp
をif
文の条件式として使っていますわ
\footnotesize \textcolor{lime}{ずんだもん:} 問題ないのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、以前、0以外の整数は真偽値のtrue
と同じとして扱われることをお話ししましたわね
\footnotesize \textcolor{lime}{ずんだもん:} 覚えているのだ
\footnotesize \textcolor{pink}{四国めたん:} memcmp
は一致していなければ0以外、つまり真偽値のtrue
を返すのでif
文の条件式として使えるのですわ
\footnotesize \textcolor{lime}{ずんだもん:} memcmp
で一致した場合は0、つまり真偽値のfalse
が返るので、if
文の条件式として使えるのか...
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{pink}{四国めたん:} ちなみに上記の配列の数値を変えて中身を一致しないようにすれば、結果は「aとbは同じではありません」と表示されますわ
#include <stdio.h>
#include <string.h>
void main() {
int a[] = {1, 2, 3};
int b[] = {1, 2, 0};
if (memcmp(a, b, sizeof(a))) {
printf("aとbは同じではありません\n");
} else {
printf("aとbは同じです\n");
}
}
\footnotesize \textcolor{lime}{ずんだもん:} 本当なのだ
まとめ
\footnotesize \textcolor{pink}{四国めたん:} お疲れさまでした
\footnotesize \textcolor{lime}{ずんだもん:} おつかれさまなのだ
\footnotesize \textcolor{pink}{四国めたん:} 以上で メモリ操作 についての説明は終わりですわ
Discussion