Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

تبديل عام

جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 51 من 61.

تعد عملية تبديل قيمتين عملية شائعة في البرمجة. عادةً، ستقوم بكتابة دالة تبديل (swap) منفصلة لكل نوع — واحدة لـ int، وأخرى لـ double، وهكذا. ولكن باستخدام void* و memcpy، يمكننا كتابة دالة واحدة تقوم بتبديل أي متغيرين.

الفكرة الأساسية هي أن عملية التبديل هي مجرد نقل للبايتات. إذا كنت تعرف حجم البيانات، يمكنك نسخ البايتات دون معرفة النوع الفعلي. يبدو توقيع الدالة كما يلي:

void generic_swap(void* a, void* b, size_t size);

تخبر المعلمة size الدالة بعدد البايتات التي يجب نقلها. في الداخل، نستخدم مخزناً مؤقتاً و memcpy من <string.h> لتبديل البايتات:

void generic_swap(void* a, void* b, size_t size) {
    char temp[size];      // مخزن مؤقت
    memcpy(temp, a, size);  // temp = a
    memcpy(a, b, size);     // a = b
    memcpy(b, temp, size);  // b = temp
}

الآن تعمل هذه الدالة الواحدة مع أي نوع:

int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x الآن هي 10، و y الآن هي 5
double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p هي الآن 2.71، q هي الآن 3.14

هذا النمط — استخدام void* مع size_t — هو الطريقة التي تنفذ بها مكتبة C القياسية الدوال العامة مثل qsort و bsearch.

challenge icon

التحدي

سهل

لنقم ببناء أداة تبديل (swap) عامة يمكنها تبادل قيم أي متغيرين، بغض النظر عن نوعهما — باستخدام قوة مؤشرات void* و memcpy.

ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:

  • swap.h: قم بالتصريح عن دالة generic_swap التي تأخذ مؤشرين من نوع void* ومعامل size_t يشير إلى حجم البيانات المراد تبديلها. لا تنسَ حواجز التضمين (include guards)!
  • swap.c: قم بتنفيذ دالة generic_swap. استخدم مخزناً مؤقتاً (temporary buffer) و memcpy لنقل البايتات بين موقعي الذاكرة. تذكر نمط التبديل المكون من ثلاث خطوات: نسخ القيمة الأولى إلى المؤقت، نسخ الثانية إلى الأولى، ثم نسخ المؤقت إلى الثانية.
  • main.c: قم بإثبات عمل أداة التبديل العامة مع أنواع بيانات مختلفة. اقرأ مؤشر النوع (i للأعداد الصحيحة، d للأعداد العشرية double) متبوعاً بقيمتين. أنشئ متغيرين من النوع المناسب، وقم بتبديلهما باستخدام دالة generic_swap، ثم اطبع كلتا القيمتين بعد التبديل.

سيتلقى برنامجك ثلاثة مدخلات:

  1. مؤشر النوع: i للعدد الصحيح أو d للعدد العشري double
  2. القيمة الأولى
  3. القيمة الثانية

بعد التبديل، اطبع كلتا القيمتين في سطرين منفصلين. بالنسبة للأعداد العشرية (doubles)، استخدم منزلتين عشريتين.

مثال على المخرجات عندما تكون المدخلات i، و 5، و 10:

10
5

مثال على المخرجات عندما تكون المدخلات d، و 3.14، و 2.71:

2.71
3.14

مثال على المخرجات عندما تكون المدخلات i، و -7، و 42:

42
-7

مثال على المخرجات عندما تكون المدخلات d، و 99.99، و 0.01:

0.01
99.99

جمال هذا النهج هو أن دالة generic_swap الخاصة بك ليس لديها أدنى فكرة عن الأنواع التي تقوم بتبديلها — فهي تقوم فقط بنقل البايتات. تعمل نفس الدالة مع الأعداد الصحيحة، والأعداد العشرية، والهياكل (structs)، أو أي نوع بيانات آخر. ستحتاج إلى تضمين <string.h> من أجل memcpy و <stddef.h> أو <stdlib.h> من أجل size_t.

ورقة مرجعية

تستخدم دالة التبديل العامة (generic swap function) مؤشرات من نوع void* و memcpy لتبديل قيم من أي نوع عن طريق نقل البايتات دون معرفة النوع الفعلي.

توقيع الدالة:

void generic_swap(void* a, void* b, size_t size);

التنفيذ باستخدام مخزن مؤقت (temporary buffer) و memcpy:

void generic_swap(void* a, void* b, size_t size) {
    char temp[size];      // مخزن مؤقت
    memcpy(temp, a, size);  // temp = a
    memcpy(a, b, size);     // a = b
    memcpy(b, temp, size);  // b = temp
}

الاستخدام مع أنواع مختلفة:

int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x الآن 10، و y الآن 5

double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p الآن 2.71، و q الآن 3.14

الترويسات المطلوبة: <string.h> من أجل memcpy و <stddef.h> أو <stdlib.h> من أجل size_t.

جرّب بنفسك

#include <stdio.h>
#include "swap.h"

int main() {
    char type;
    scanf("%c", &type);
    
    if (type == 'i') {
        int a, b;
        scanf("%d", &a);
        scanf("%d", &b);
        
        // TODO: استدعِ generic_swap لتبديل a و b
        // تلميح: استخدم &a و &b و sizeof(int)
        
        printf("%d\n", a);
        printf("%d\n", b);
    } else if (type == 'd') {
        double a, b;
        scanf("%lf", &a);
        scanf("%lf", &b);
        
        // TODO: استدعِ generic_swap لتبديل a و b
        // تلميح: استخدم &a و &b و sizeof(double)
        
        printf("%.2f\n", a);
        printf("%.2f\n", b);
    }
    
    return 0;
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming