C Academy · レッスン

memcpy と memset

生メモリを扱う関数です。

レッスン 4/413 ステップ

「memcpy と memset」はCoddyKit上の無料C Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。

生メモリー関数

文字列関数とは異なり、memcpyとmemsetは生のバイトを扱い、ヌル終端文字を無視します。

これらは<string.h>で宣言され、指定したバイト数を処理するため、あらゆるデータ型に使える汎用的な関数です。

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

int main(void) {
    int src[] = {1, 2, 3};
    int dest[3];
    memcpy(dest, src, sizeof(src));
    printf("%d %d %d\n", dest[0], dest[1], dest[2]);
    return 0;
}

memcpyのシグネチャ

void *memcpy(void *dest, const void *src, size_t n);

srcからdestへ正確にnバイトをコピーし、destを返します。正しいバイト数を取得するにはsizeofを使用してください。

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

int main(void) {
    char src[] = "copy me";
    char dest[16];
    memcpy(dest, src, strlen(src) + 1);
    printf("%s\n", dest);
    return 0;
}

バイト数を正しく数える

指定する数は要素数ではなくバイト数です。intの配列では、sizeof(int)を掛ける必要があります。

実際の配列にsizeof(array)を使うと、合計のバイトサイズが自動的に得られます。

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

int main(void) {
    double a[4] = {1.5, 2.5, 3.5, 4.5};
    double b[4];
    memcpy(b, a, 4 * sizeof(double));
    printf("%.1f %.1f\n", b[0], b[3]);
    return 0;
}

領域を重複させてはいけない

コピー元とコピー先の領域が重複している場合、memcpyは未定義の動作になります。

範囲が重複する可能性がある場合(たとえば1つの配列内で要素を移動する場合)は、重複を安全に処理できるmemmoveを使用してください。

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

int main(void) {
    char buf[] = "ABCDEF";
    memmove(buf + 2, buf, 4);
    printf("%s\n", buf);
    return 0;
}

memsetのシグネチャ

void *memset(void *ptr, int value, size_t n);

ptrから始まるnバイトを、バイト値valueで埋めます。値はunsigned charとして解釈されるため、下位8ビットだけが意味を持ちます。

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

int main(void) {
    char buf[6];
    memset(buf, 'x', 5);
    buf[5] = '\0';
    printf("%s\n", buf);
    return 0;
}

メモリーをゼロで初期化する

memsetの最も一般的な用途は、バッファーや構造体を使用前にすべてゼロにしてクリアすることです。

memset(arr, 0, sizeof(arr))はすべてのバイトを0に設定します。これはint、float、ポインターで有効なゼロ値です。

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

int main(void) {
    int counts[5];
    memset(counts, 0, sizeof(counts));
    for (int i = 0; i < 5; i++) printf("%d ", counts[i]);
    printf("\n");
    return 0;
}

memsetはバイト単位で動作する

注意してください。memsetが設定するのは各バイトであり、各要素ではありません。int配列を値1で埋めるために使っても、1にはなりません。

各intのすべてのバイトが0x01に設定されるため、値は1ではなく0x01010101になります。

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

int main(void) {
    int a[2];
    memset(a, 1, sizeof(a));
    printf("%d\n", a[0]);
    return 0;
}

構造体をクリアする

memsetを使うと、各フィールドを手動で設定する代わりに、構造体全体を1回の呼び出しでゼロに初期化できます。

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

struct Point { int x; int y; int z; };

int main(void) {
    struct Point p;
    memset(&p, 0, sizeof(p));
    printf("%d %d %d\n", p.x, p.y, p.z);
    return 0;
}

構造体のコピー

memcpyで構造体をコピーできますが、通常は単純な代入(b = a;)のほうが同じ処理を明確に記述できます。

型情報が失われる汎用的なvoid *ポインター経由でコピーする場合は、memcpyが適しています。

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

struct Rec { int id; char tag; };

int main(void) {
    struct Rec a = {42, 'A'};
    struct Rec b;
    memcpy(&b, &a, sizeof(a));
    printf("%d %c\n", b.id, b.tag);
    return 0;
}

memcmp:メモリーの比較

関連する関数にmemcmp(a, b, n)があります。これはnバイトの生データを比較し、一致すると0を返します。

strcmpとは異なり、ヌル終端文字で停止しないため、あらゆるバイナリーデータを扱えます。

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

int main(void) {
    int a[] = {1, 2, 3};
    int b[] = {1, 2, 3};
    if (memcmp(a, b, sizeof(a)) == 0)
        printf("Arrays have identical bytes\n");
    return 0;
}

高速に動作する理由

memcpyとmemsetは、多くのバイトを1命令で移動できるよう、アセンブリで手作業による最適化が施されていることがよくあります。

通常は手書きのバイト処理ループよりはるかに高速なので、大量のデータ移動や初期化にはこれらを使用してください。

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

int main(void) {
    char big[1000];
    memset(big, 0, sizeof(big));
    printf("Cleared %lu bytes\n", sizeof(big));
    return 0;
}

クイックチェック

memsetのバイト単位の動作についての理解度を確認しましょう。

まとめ

生メモリー関数について学びました。

  • memcpyはnバイトをコピーします。領域を重複させてはいけません(重複する可能性がある場合はmemmoveを使用します)。
  • memsetはnバイトを1つのバイト値で埋めます。ゼロ初期化に適しています。
  • 指定する数はバイト数です。sizeofを使用し、バイトと要素の取り違えに注意してください。
  • memcmpは'\0'で停止せず、生のバイトを比較します。
無料で開始

AI チューターと学ぶ C — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
39
レッスン
144

よくある質問

「memcpy と memset」レッスンは無料ですか?

はい。「memcpy と memset」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。

「memcpy と memset」で何を学びますか?

生メモリを扱う関数です。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「memcpy と memset」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC Academyレッスンでコードを書いて実行できますか?

はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. strlen、strcpy、strcat
  2. strcmp と比較
  3. strtok とトークン化
  4. memcpy と memset
← C Academyに戻る