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

صحة استخدام Const

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

عند كتابة دوال تعمل كطرق (methods)، يجب أن يقوم بعضها بتعديل الكائن (مثل player_take_damage)، بينما يجب على البعض الآخر قراءة البيانات فقط دون تغيير أي شيء. تسمح لك الكلمة المفتاحية const بفرض هذا التمييز على مستوى المترجم (compiler).

من خلال تمييز معامل المؤشر كـ const، فإنك تتعهد بأن الدالة لن تقوم بتعديل البيانات التي يشير إليها. إذا حاولت تغيير أحد الأعضاء عن طريق الخطأ، فسيقوم المترجم (compiler) بإنتاج خطأ:

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

// هذه الدالة يمكنها فقط قراءة النقطة
void point_print(const Point *self) {
    printf("(%d, %d)\n", self->x, self->y);
    // self->x = 10;  // خطأ: لا يمكن التعديل من خلال مؤشر ثابت (const pointer)
}

// هذه الدالة يمكنها تعديل النقطة
void point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

تخبر المعلمة const Point *self كلاً من المترجم والمبرمجين الآخرين أن point_print هي عملية "getter" أو عملية للقراءة فقط. يسمى هذا بـ صحة الثوابت (const correctness)—وهي استخدام const في أي مكان لا يلزم فيه التعديل.

تكتشف هذه الممارسة الأخطاء مبكرًا. إذا كتبت دالة display وقمت بتعديل حقل بالخطأ، فإن المترجم (compiler) يوقفك على الفور بدلاً من ترك الخطأ يتسلل إلى برنامجك.

challenge icon

التحدي

سهل

لنقم ببناء وحدة Temperature تقوم بتخزين قيمة درجة الحرارة وتوفر عمليات للقراءة فقط وعمليات للتعديل. سيساعدك هذا على التدرب على استخدام مؤشرات const للتمييز بوضوح بين الدوال التي تقرأ البيانات فقط وتلك التي تقوم بتغييرها.

ستقوم بإنشاء ثلاثة ملفات:

  • temperature.h: قم بالتصريح عن هيكل Temperature يحتوي على عضو واحد من نوع double celsius. قم أيضاً بالتصريح عن ثلاث دوال:
    • temp_display — تأخذ مؤشر const إلى Temperature وتطبع درجة الحرارة الحالية (للقراءة فقط)
    • temp_adjust — تأخذ مؤشراً عادياً إلى Temperature وقيمة double، ثم تضيف هذه القيمة إلى celsius (للتعديل)
    • temp_to_fahrenheit — تأخذ مؤشر const إلى Temperature وتعيد القيمة محولة إلى فهرنهايت (للقراءة فقط)
    استخدم حواجز التضمين (include guards) مع الرمز TEMPERATURE_H.
  • temperature.c: قم بتنفيذ الدوال الثلاث جميعها. يجب أن تطبع دالة temp_display بالتنسيق Current: {celsius}C. يجب أن تعيد دالة temp_to_fahrenheit القيمة celsius * 9.0 / 5.0 + 32.0. تذكر أن الدوال التي تستخدم مؤشرات const لا يمكنها تعديل بيانات الهيكل.
  • main.c: قم بإنشاء Temperature، وإجراء العمليات، وعرض النتائج.

ستتلقى مدخلين: قيمة السيلزيوس الأولية (كـ double) و مقدار التعديل (كـ double).

في ملفك الرئيسي:

  1. قم بتهيئة Temperature بقيمة السيلزيوس الأولية
  2. استدعِ temp_display لإظهار درجة حرارة البداية
  3. استدعِ temp_adjust لتعديل درجة الحرارة بمقدار التعديل
  4. استدعِ temp_display مرة أخرى لإظهار درجة الحرارة المحدثة
  5. اطبع تحويل الفهرنهايت باستخدام temp_to_fahrenheit

اطبع النتائج بهذا التنسيق:

Current: {celsius}C
Current: {celsius}C
Fahrenheit: {fahrenheit}F

استخدم %.1f لجميع قيم درجات الحرارة لعرض منزلة عشرية واحدة.

على سبيل المثال، مع قيمة أولية 20.0 وتعديل قدره 5.0، سيكون الناتج:

Current: 20.0C
Current: 25.0C
Fahrenheit: 77.0F

ورقة مرجعية

يمكن استخدام الكلمة المفتاحية const مع معاملات المؤشر للإشارة إلى أن الدالة لن تقوم بتعديل البيانات التي يتم الإشارة إليها. يسمى هذا بـ صحة الثوابت (const correctness).

عندما يتم تمييز معامل المؤشر كـ const، سيمنع المترجم أي تعديلات على البيانات من خلال ذلك المؤشر:

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

// دالة للقراءة فقط - لا يمكنها تعديل النقطة
void point_print(const Point *self) {
    printf("(%d, %d)\n", self->x, self->y);
    // self->x = 10;  // خطأ: لا يمكن التعديل من خلال مؤشر ثابت (const)
}

// دالة تعديل - يمكنها تغيير النقطة
void point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

استخدام const Point *self يوضح لكل من المترجم والمبرمجين الآخرين أن الدالة هي عملية للقراءة فقط. يساعد هذا في اكتشاف الأخطاء البرمجية مبكرًا—إذا حاولت بالخطأ تعديل البيانات في دالة لا ينبغي أن تغير أي شيء، فسيقوم المترجم بإصدار خطأ على الفور.

أفضل الممارسات: استخدم const لمعاملات المؤشر كلما لم تكن الدالة بحاجة إلى تعديل البيانات. هذا يجعل نية الكود الخاص بك أكثر وضوحًا ويمنع التعديلات العرضية.

جرّب بنفسك

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

int main() {
    double initial_celsius, adjustment;
    scanf("%lf", &initial_celsius);
    scanf("%lf", &adjustment);
    
    // TODO: قم بإنشاء هيكل Temperature وقم بتهيئته باستخدام initial_celsius
    
    // TODO: قم باستدعاء temp_display لعرض درجة الحرارة الأولية
    
    // TODO: قم باستدعاء temp_adjust لتعديل درجة الحرارة بمقدار adjustment
    
    // TODO: قم باستدعاء temp_display مرة أخرى لعرض درجة الحرارة المحدثة
    
    // TODO: قم بطباعة تحويل Fahrenheit باستخدام temp_to_fahrenheit
    // التنسيق: "Fahrenheit: %.1fF\n"
    
    return 0;
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming