コンテンツ
1.memcpy関数の概要
1.関数宣言
void * memcpy (void * destination、const void * source、size_t num);
2.機能と注意事項
- 関数memcpyは、numバイトのデータをソースの場所から宛先のメモリの場所に逆方向にコピーします。
- この関数は、「\0」に遭遇しても停止しないことに注意してください。
- ソースと宛先の間に重複がある場合、コピーの結果は未定義です。
- 文字列のみをコピーできるstrcpy関数とは異なり、memcpy関数は任意のタイプのデータをコピーできます。
3.機能の使用
#include <stdio.h> #include <string.h>//使用memcpy函数时记得引用它的头文件 int main() { int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int arr2[5] = { 0 };//总共大小为20字节 memcpy(arr1, arr2, 20//拷贝20个字节的数据);//将arr2中的数据拷贝到arr1中 int i = 0; printf("拷贝后arr1中的数据为:"); for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }
演算結果:
次に、memcpy関数の実装をシミュレートします
1.シミュレーション分析
1.コピーするデータの種類がわからないため、char型データ、int型データ、double型データのいずれかである可能性があります。これらの異なる種類のデータのサイズは異なります。すべてのタイプのデータをコピーできるmemcpy関数を実装するには、最小タイプのサイズが1バイトであり、すべてのタイプのデータをコピーできるため、バイトごとにしかコピーできません。
2. memcpy関数に渡されるアドレスのタイプがわからないため、渡されたアドレスを受け取るためにvoid*タイプのポインターを使用します。
3.送信元アドレスに保存されているデータをターゲットアドレスにコピーするだけでよいので、送信元アドレスに保存されているアドレスではなく、ターゲットアドレスに保存されているコンテンツを変更するだけで済みます。したがって、送信元アドレスを受け取るには、constvoid*型のポインターを使用する必要があります。
4.連鎖アクセスを実現するには、渡された宛先の開始アドレス(宛先)を返す必要があります。この関数は実行時に宛先ストレージの内容を変更するため、このアドレスを格納するためにvoid*タイプのポインターを再作成する必要があります。
5.着信アドレスがnullポインターになるのを避けるために、assertを使用して着信アドレスがnullポインターではないことをアサートする必要があります。
2.シミュレーションの実装
#include<stdio.h> #include<assert.h> //模拟实现memcpy void* my_memcpy(void* dest, const void* scr, size_t count) { assert(dest && scr);//断言传进来的地址不是空指针 void* ret = dest;//保存目标起始地址 while (count--)//拷贝源地址存储的数据 { *(char*)dest = *(char*)scr; (char*)dest = (char*)dest + 1; (char*)scr = (char*)scr + 1; } return ret;//返回目标起始地址 } //应用模拟实现的函数 int main() { int arr1[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }; int arr2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; my_memcpy(arr2, arr1, 24);//拷贝6个字节的数据 int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr2[i]); } return 0; }
演算結果:
第三に、memmove機能の導入
1.関数宣言
void * memmove (void * destination、const void * source、size_t num);
2.memmove機能があるのはなぜですか
memmove関数があるのはなぜですか?これも上記のmemcpy関数から始まります。memcpy関数は配列内のデータをそれ自体にコピーできないため(つまり、ターゲットデータはそれ自体であり、ソースデータもそれ自体ですが、配列内の異なる場所からのデータは別の場所にコピーされます)、この重複するコピーが発生し、予想とは異なる結果になります。
このコードのように:
//应用模拟实现的memcpy函数 int main() { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; my_memcpy(arr + 2, arr, 24);//预期出现结果为1 2 1 2 3 4 5 6 9 10 int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]);//实际出现结果 } return 0; }
演算結果:
期待される結果と実際の結果が異なる可能性がある理由:
この結果の理由は、memcpy関数が自身のデータをそれ自体の異なる場所にコピーするときに重複コピーが発生するためです。ソースデータの開始アドレスはarrであり、ターゲットデータの開始アドレスはarr + 2です。memcpy関数に入ると、最初にarrのデータをarr + 2にコピーし、arr+1のデータをコピーします。 。データはarr+3にコピーされます。arr+2のデータをarr+4にコピーする場合、arr + 2のデータがarr (1)のデータに置き換えられていることがわかります。1をarr+4にコピーするだけです。arr+3のデータをarr+5にコピーする場合、arr+3のデータはすでにarr+1に置き換えられていることがわかります。data (2)、2をarr+5にコピーするだけで、このように繰り返します重複コピーの場合、コピーするバイト数がコピーされるまで、コピーされるデータは常に1/2/1/2/1/2です。
したがって、自分のデータを自分の別の場所にコピーするには、memmove関数を使用して実装する必要があります。memmove関数は、上記の問題を解決するために作成されました。
3.機能と注意事項
- memmoveとmemcpyの違いは、memmove関数によって処理されるソースメモリブロックとターゲットメモリブロックがオーバーラップする可能性があることです。
- ソーススペースとターゲットスペースが重なっている場合は、memmove関数を使用して処理する必要があります。
4.関数の使用
#include<stdio.h> #include<string.h>//使用memmove函数时记得引用它的头文件 int main() { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; memmove(arr + 2, arr, 24);//预期出现结果为1 2 1 2 3 4 5 6 9 10 int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]);//实际出现结果 } return 0; }
今回、memmove関数でコピーされた期待される結果が実際の結果と同じであることがわかりました。memmove関数のシミュレーション実装について話しましょう。
第4に、memmove関数の実装をシミュレートします
1.シミュレーション分析
1.アドレスを関数に渡す方法と、アドレスを受け取る関数は、上記のmemcpy関数と同じです。memcpy関数は、memmove関数に注意を払う必要があります。ここでは、繰り返しません。
2. memmove関数についてのもう1つの注意点は、重複しないようにコピーする方法を分析する必要があるということです。以下は図です。
ケース1:destがsrcのアドレス以下である
下のように前から後ろにコピーして、重なりがないようにします。
ケース2:destのアドレスがscrより大きい
下のように後ろから前にコピーして、重なりがないようにします。
2.シミュレーションの実装
#include<stdio.h> #include<assert.h> //模拟实现memmove void* my_memmove(void* dest, const void* scr, size_t count) { assert(dest && scr);//断言传进来的地址不是空指针 void* ret = dest; //保存目标起始地址 if (dest <= scr)//从前往后拷贝 { while (count--) { *(char*)dest = *(char*)scr; (char*)dest = (char*)dest + 1; (char*)scr = (char*)scr + 1; } } else//从后往前拷贝 { while (count--) { *((char*)dest + count) = *((char*)scr + count); } } return ret; } //应用模拟实现的函数 int main() { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; my_memmove(arr + 2, arr, 24);//预期出现结果为1 2 1 2 3 4 5 6 9 10 int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]);//实际出现结果 } return 0; }
運転結果
要約する
今日の内容はこれで全部です。お役に立てば、ぜひフォローしてください。応援よろしくお願いします。最後に、大学院生が上陸し、就職活動をしている学生が入場できることを願っています。大廠。