memcpy وmemset
دوال الذاكرة الخام
memcpy وmemset درس مجاني في C Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في 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);
تنسخ بالضبط n بايت من src إلى dest وتعيد 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 عندما تتداخل منطقتا المصدر والوجهة إلى سلوك غير معرّف.
عندما يُحتمل تداخل النطاقين، مثل إزاحة العناصر داخل مصفوفة واحدة، استخدموا 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);
تملأ memset عدد n من البايتات عند ptr بقيمة البايت 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، وهو تمثيل صالح للصفر في الأعداد الصحيحة والعائمة والمؤشرات.
#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، فتكون القيمة 0x01010101، لا 1.
#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 مفيدة لتهيئة بنية كاملة إلى الصفر في استدعاء واحد، بدلاً من ضبط كل حقل يدوياً.
#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;) يؤدي المهمة نفسها عادةً بوضوح أكبر.
تُفضَّل memcpy عند النسخ عبر مؤشرات عامة من النوع void *، حيث لا تعود الأنواع محفوظة.
#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 يدوياً بلغة التجميع لنقل بايتات كثيرة في كل تعليمة.
وعادةً ما تكونان أسرع بكثير من حلقة بايتات مكتوبة يدوياً، لذا فضّلوهما لنقل البيانات وتهيئتها بكميات كبيرة.
#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 من البايتات بقيمة بايت واحدة؛ وهي مناسبة جداً للتصفير.
- تُعبَّر الأعداد بالـ بايتات — استخدموا
sizeofوانتبهوا إلى الفرق بين البايت والعنصر. - تقارن memcmp البايتات الخام دون التوقف عند
'\0'.
تعلم C مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 39
- الدروس
- 144
الأسئلة الشائعة
هل درس «memcpy وmemset» مجاني؟
نعم — نص درس «memcpy وmemset» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C Academy 4 دروس في المجموع.
ماذا ستتعلم في «memcpy وmemset»؟
دوال الذاكرة الخام تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟
لا تُشترط خبرة سابقة. C Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «memcpy وmemset»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C Academy هذا؟
نعم. كل درس في C Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.