مضى على الشبكة و يوم من العطاء.

[ شرح ] اساسيات لغة C | المؤشرات ومقدمة الى ادارة وتخصيص الذاكرة 0x09

N0Tb1t

./عضو جديد
>:: v1p ::<

firefox
linux

السمعة:

بسم الله والصلاة والسلام على خير خلق الله وعلى آله وصحبه ومن والاه
في هذا المقال سنتعرف على المؤشرات 'pointers' وأنواعها وناخد مقدمة عن ادارة وتخصيص الذاكرة 'memory management and allocations' وهذا المقال من أمتع المواضيع التي يجب على المبرمج ان يتعلمها وهو آخر مقال بسلسلة الأساسيات إن شاء الله

رح اشرح بالعامية مشان حاول قد ما بقدر وصل الفكرة وتكون مفهومة.

لن يتم التوسع بهذا المقال بالقدر المطلوب بالنسبة لل memory management and allocations ولكن سنشرح المفاهيم الاساسية التي ستساعدنا على فهم المؤشرات ان شاء الله لان هي الموضوعات بدها مقال خاص ⁦;⁠)⁩⁦

المؤشرات تُعتبر أداة قوية تتيح التحكم المباشر في الذاكرة، مما يجعلها ذات أهمية قصوى عند تحليل البرامج وتحويل التعليمات الثنائية (executable) إلى كود يمكن فهمه.


المؤشرات (Pointers):
المؤشرات هي متغيرات تخزن عناوين الذاكرة لمتغيرات أخرى. يعني اذا كان عندك متغير عدد صحيح int فينك تنشىء مؤشر بيشير إلى عنوانو بالذاكرة لتقدر تقرأ قيمتو او تعدل عليها بشكل غير مباشر.
وهاد الشي الي بيخلي المؤشرات اداة قوية لادارة الذاكرة.

قبل ما نبدا بشرح المؤشرات لازم يكون عنا خلفية لامور متل تخطيط الذاكرة وتخصيصها وادارتها

تخطيط الذاكرة (memory layout):
بلغة C كل متغير يتم تخزينو في موقع ذاكرة محدد بعنوان فريد يعني إذا قمنا بتعريف متغير (int x=5;) ممكن يتخزن هاد المتغير بالstack اذا كان معرف داخل دالة (محلي) local او بيتخزن بالglobals اذا كان متعرف (عالمي) global.
ونحنا بنستخدم المؤشر للوصول لعنوان المتغير X فهون صار عندك تحكم دقيق بكيفية استخدام البرنامج للذاكرة.

طيب شو هي أقسام الذاكرة؟
1. Text Segment:

يعرف أيضاً ب "code segment"، هو جزء من الذاكرة بيحتوي على التعليمات التنفيذية (machine code) للبرنامج.
يعني بيحتوي على الكود المترجم (ال compiled) من لغة C إلى لغة الآلة. هو للقراءة فقط 'read only' يعني ما فينا نعدل على محتواه. وهاد الجزء بيحتوي على جميع التعليمات الي بينفذها المعالج متل الدوال والحلقات والشروط.

2. Data Segment:
هاد الجزء بيحتوي على المتغيرات العامة global والثابتة static التي تمت تهيئتها بقيم صحيحة 'Initialized Data'
متل:
C:
int x=10; // وقت منسند للمتغير قيمة يعني هيئناه

3. 'BSS Segment 'Block Started by Symbol :
هاد الجزء بيحتوي على المتغيرات العامة أو الثابتة غير المهيئة (أو إلي تمت تهيئتها بقيمة الصفر افتراضياً) 'Uninitialized Data'
متل:
C:
int x; // هون قيمتو الافتراضية 0


4.المكدس (Stack):
هو منطقة بالذاكرة تخزن المتغيرات المحلية الlocal ويخزن معلومات الدوال. مبدأ في التخصيص يسمى LIFO (Last In First Out) يعني اخر متغير بيدخل أول متغير بيطلع.
المكدس مؤقت بمجرد الانتهاء من الدالة يتم إلغاء الذاكرة المخصصة لها.
صورة موضحة:
images.webp

Push: للاضافة
Pop: للحذف

5.الكومة (HEAP):
هي منطقة بالذاكرة تستخدم لتخصيص الذاكرة الديناميكية.
التخصيص هون بيكون يدوياً باستخدام دوال متل: calloc, malloc
طبعا هون عكس المكدس الذاكرة المخصصة بتضل محجوزة حتى نقوم بالغائها او تحريرها بالدالة free لأنه غير مؤقت.


ملاحظات:
بإدارة الذاكرة: الStack, data segment, bss segment (تدار تلقائياً بواسطة النظام) اما الheap (بدها ادارة يدوية من المبرمج).

بالأداء: المكدس اسرع من الكومة بسبب بساطة ادارته ولكن حجمه محدود مقارنة بالكومة.



تخصيص وإدارة الذاكرة (memory management and allocation):

تخصيص الذاكرة(Memory Allocation):

هي عبارة عن حجز مساحة في ذاكرة الحاسب لتخزين البيانات اثناء تنفيذ البرنامج. بلغة C فينا نخصص الذاكرة بثلاث طرق:
1.الثابتة 'static'
2.التلقائية 'automatic'
3.الديناميكية 'dynamic'
كل طريقة الها خصائص واستخدامات رح نركز على التخصيص الثابت والديناميكي.


أنواع تخصيص الذاكرة:
1.التخصيص الثابت (static memory allocation):

يتم تخصيص الذاكرة الثابتة بوقت الترجمة للمتغيرات إلى بتستمر طوال مدة تشغيل البرنامج. تستخدم للمتغيرات العامة أو المعلنة بكلمة 'static'. وتخزن اما بالdata segment (اذا كانت مهيئة) او بال bss segment (اذا كانت غير مهيئة).

2.التخصيص التلقائي (Automatic memory allocation):
يستخدم التخصيص التلقائي للمتغيرات المحلية داخل الدوال. يتم تخصيص الذاكرة على المكدس عند استدعاء الدالة وإلغاء تخصيصها عند الانتهاء منها.

3.التخصيص الديناميكي (dynamic memory allocation):
يسمح التخصيص الديناميكي بطلب الذاكرة أثناء تشغيل البرنامج. مما يوفر مرونة في الحجم والعمر الافتراضي. يتم التخصيص على الكومة باستخدام دوال من مكتبة <stdlib.h>
متل: malloc, calloc, realloc, free


إدارة الذاكرة:
تتضمن التحكم في تخصيص الذاكرة وإلغاء تخصيصها لضمان الاداء الافضل وتجنب الاخطاء مثل تسرب الذاكرة. في C بيتحمل المبرمج مسؤولية إدارة الذاكرة الديناميكية يدوياً لأن ما فيها (garbage collection) متل لغة Java.


طيب منرجع لموضوع المؤشرات..

صيغة تعريف المؤشر(syntax):
C:
data_type *pointer_name;

// data_type: نوع البيانات التي يشير إليها المؤشر.
// pointer_name: اسم المؤشر.
// '*': تُشير إلى أن المتغير هو مؤشر.

كيف يتم استخدام المؤشرات: هون الوضع بدو ايس شاي

1. تعريف المؤشر وتخصيص عنوان له:
C:
int a = 10;     // متغير عادي
int *p = &a;    // تعريف المؤشر وربطه بعنوان المتغير

// &a: هاد اسمو الand operator هو المسؤول عن اعطاء قيمة المتغير للمؤشر.
// p: يحتوي على عنوان a.
// *p: تُستخدم للحصول على قيمة المتغير الموجود في العنوان.

2. إلغاء الإشارة (Dereferencing): رح حاول اشرحها بطريقة سهلة
عند استخدام '*' مع مؤشر، يُمكن الوصول إلى القيمة الموجودة في العنوان الذي يشير إليه يعني عنا متغير a وعنا المؤشر الي بيدل عليه p اذا بدنا نطبع *p رح يعطينا قيمة المتغير a
C:
printf("Value of a: %d\n", *p);

3. تعديل القيمة باستخدام المؤشر:
C:
*p = 20; // تغيير قيمة a عبر المؤشر
printf("New value of a: %d\n", a); // الناتج: 20


ما هي أنواع المؤشرات:

1. المؤشرات الأساسية:
* تشير الى متغير بسيط
C:
int x = 5;
int *ptr = &x;

2. المؤشرات إلى المؤشرات (Pointer to Pointer):
* تُستخدم للتعامل مع المؤشرات متعددة المستويات.
C:
int x = 10;
int *ptr = &x;
int **ptr2 = &ptr; // مؤشر إلى المؤشر ptr

3. المؤشرات إلى المصفوفات (Array Pointers):
* المؤشرات تُستخدم للتنقل في المصفوفات.
C:
int arr[] = {1, 2, 3};
int *ptr = arr; // يشير إلى العنصر الأول

4. المؤشرات إلى دوال (Function Pointers):
* تُستخدم لاستدعاء دوال عبر العناوين.
C:
void func() {
    printf("Hello, Function Pointer!\n");
}

void (*fptr)() = func;
fptr(); // استدعاء الدالة عبر المؤشر

5. المؤشرات الفارغة (Void Pointers):
* يمكنها الإشارة إلى أي نوع من البيانات.
C:
void *ptr;
int a = 10;
ptr = &a; // الآن يشير إلى عدد صحيح

6. المؤشرات الثابتة (Constant Pointers):
* المؤشر أو القيمة التي يشير إليها لا يمكن تغييرها.
C:
int x = 10;

int *const ptr = &x;  // لا يمكن تعديل قيمته


طيب خلونا نتوسع شوي بامور الانواع ونشرحا بطريقة عملية:

1. المؤشرات والعناوين (Pointers and Addresses):

متل ما عرفنا المؤشر فوق هو متغير يخزن عنوان ذاكرة لمتغير آخر، وهو أساسي لفهم كيفية التعامل مع الذاكرة في C. يتم استخدام عامل & للحصول على العنوان، و * للوصول إلى القيمة في ذلك العنوان.

مثال:
C:
#include <stdio.h>
    int main() {
        int x = 10;
        int *ptr = &x;
        printf("قيمة x: %d\n", x);          // 10
        printf("عنوان x: %p\n", &x);        // عنوان الذاكرة
        printf("قيمة ptr: %p\n", ptr);      // نفس عنوان x
        printf("القيمة عبر ptr: %d\n", *ptr); // 10
        return 0;
    }
الشرح:
-
&x: يعطي عنوان المتغير x في الذاكرة.
- *ptr: يُستخدم للوصول إلى القيمة المخزنة في العنوان الذي يشير إليه ptr.

2. المؤشرات والمصفوفات (Pointers and Arrays):
في C، اسم المصفوفة يتحول إلى مؤشر لأول عنصر عند استخدامه في التعبيرات. هذا يعني أن a مكافئ ل *(a + i).

مثال:
C:
#include <stdio.h>
    int main() {
        int arr[4] = {1, 2, 3, 4};
        int *p = arr;
        for (int i = 0; i < 4; i++) {
            printf("arr[%d] = %d\n", i, *(p + i));
        }
        return 0;
    }
الشرح:
- arr: هو مؤشر ثابت لأول عنصر في المصفوفة.
- *(p + i): يُستخدم للوصول إلى العنصر في الموقع i.

3. حسابات العناوين (Address Arithmetic):
حسابات العناوين بتيح إجراء عمليات مثل الجمع والطرح على المؤشرات، حيث يتم حساب التنقل بناءً على حجم نوع البيانات الData type.

مثال:
C:
#include <stdio.h>
    int main() {
        int arr[3] = {10, 20, 30};
        int *ptr = arr;
        printf("العنصر الأول: %d\n", *ptr);   // 10
        ptr++; // الانتقال إلى العنصر التالي
        printf("العنصر الثاني: %d\n", *ptr);  // 20
        ptr++; // الانتقال إلى العنصر التالي
        printf("العنصر الثالث: %d\n", *ptr);  // 30
        return 0;
    }
الشرح:
عند زيادة المؤشر (ptr++)، ينتقل إلى العنوان التالي بناءً على حجم نوع البيانات (مثلًا، 4 بايت لـ int) ونحنا بمقال الData Types حكينا عن الاحجام.

4. المؤشرات إلى المصفوفات (Pointers to Arrays):
المؤشر إلى مصفوفة هو مؤشر يشير إلى مصفوفة كاملة، ويُستخدم غالبًا مع المصفوفات متعددة الأبعاد. وهو مفيد لتمرير المصفوفات متعددة الأبعاد إلى الدوال.

مثال:
C:
#include <stdio.h>
    int main() {
        int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
        int (*ptr)[3] = arr;
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 3; j++) {
                printf("%d ", ptr[i][j]);
            }
            printf("\n");
        }
        return 0;
    }
الشرح:
ptr:
يشير إلى مصفوفة من 3 أعداد صحيحة (صف في المصفوفة ثنائية الأبعاد).
يُستخدم للوصول إلى الصفوف والأعمدة بسهولة.

5. المؤشرات ووسائط الدوال (Pointers and Function Arguments):
تُستخدم المؤشرات كوسائط للدوال لتمرير البيانات بالمرجع، مما يسمح بتعديل القيم الأصلية داخل الدالة.(بالعادة التغييرات داخل الدالة ما بتأثر على المتغيرات الاصلية, بس المؤشرات تتيح تمرير العناوين لتعديل المتغيرات الاصلية).

مثال:
C:
#include <stdio.h>
    void swap(int *a, int *b) {
        int temp = *a;
        *a = *b;
        *b = temp;
    }
    int main() {
        int x = 5, y = 10;
        printf("قبل التبديل: x = %d, y = %d\n", x, y);
        swap(&x, &y);
        printf("بعد التبديل: x = %d, y = %d\n", x, y);
        return 0;
    }
الشرح:
تُمرر العناوين (&x و &y) إلى الدالة.
تُستخدم *a و *b لتعديل القيم الأصلية.

6. المؤشرات النصية (Pointers to Strings):
المؤشرات إلى النصوص تُستخدم للإشارة إلى سلاسل نصية، حيث تشير إلى أول حرف في السلسلة. هي مصفوفات من حروف.

مثال:
C:
#include <stdio.h>
    int main() {
        char *str = "Hello, World!";
        printf("النص: %s\n", str);
        printf("الحرف الأول: %c\n", *str);  // H
        printf("الحرف الثاني: %c\n", *(str + 1));  // e
        return 0;
    }
الشرح:
str:
يشير إلى أول حرف في السلسلة.

7. مصفوفات المؤشرات والمؤشرات إلى مؤشرات (Arrays of Pointers and Pointers to Pointers):
مصفوفة المؤشرات:
مصفوفة تحتوي على مؤشرات كعناصرها.
المؤشر إلى مؤشر: مؤشر يشير إلى مؤشر آخر.

مثال لمصفوفة المؤشرات:
C:
        #include <stdio.h>
        int main() {
            int a = 1, b = 2, c = 3;
            int *ptr[3] = {&a, &b, &c};
            for (int i = 0; i < 3; i++) {
                printf("القيمة: %d\n", *ptr[i]);
            }
            return 0;
        }
مصفوفة المؤشرات تُستخدم لتخزين عناوين متعددة.

مثال لمؤشر الي مؤشر:
C:
#include <stdio.h>
        int main() {
            int x = 10;
            int *p = &x;
            int **pp = &p;
            printf("القيمة عبر pptr: %d\n", **pp);  // 10
            return 0;
        }
المؤشر إلى مؤشر مفيد في هياكل البيانات المتقدمة مثل المصفوفات الديناميكية Dynamic Arrays.

8. المؤشرات إلى الدوال (Pointers to Functions):
المؤشر إلى دالة يشير إلى عنوان بداية دالة، مما يتيح استدعائها ديناميكيًا.

مثال:
C:
include <stdio.h>
    int add(int a, int b) {
        return a + b;
    }
    int main() {
        int (*func_ptr)(int, int) = add;
        int result = func_ptr(3, 4);
        printf("النتيجة: %d\n", result);  // 7
        return 0;
    }
func_ptr يشير إلى دالة add.


ما هي أهمية المؤشرات في الثغرات الأمنية؟
1. Buffer overflow:

* عند تخصيص مساحة ذاكرة محدودة، يمكن تجاوزها باستخدام مؤشرات غير آمنة.
C:
void vulnerable_function(char *input) {
    char buffer[10];
    strcpy(buffer, input); // يمكن تجاوز حجم buffer
}

- في الهندسة العكسية، يتم تحليل مثل هذه الثغرات لاستغلالها أو فهم كيفية عمل الهجمات.

2. Use after free:
* يحدث عندما يتم تحرير المؤشر واستخدامه لاحقًا.(تحرير المؤشر يعني عدم تخصيصه بالذاكرة)
C:
char *ptr = malloc(10);
free(ptr);     // تحرير الذاكرة
strcpy(ptr, "data"); // استخدام المؤشر بعد تحريره


3. Null Pointer Dereference:
* إذا أشار المؤشر إلى عنوان فارغ، فإن إلغاء الإشارة (dereference) يؤدي إلى انهيار البرنامج.


4. Double Free:
* عندما يتم تحرير نفس المؤشر مرتين، مما قد يؤدي إلى ثغرات في تخصيص الذاكرة.
C:
char *ptr = malloc(10);
free(ptr);
free(ptr); // تحرير مرتين


ملاحظة هامة:
* في الهندسة العكسية، المؤشرات هي المفتاح لفهم كيفية تدفق البيانات بين أجزاء البرنامج لأنه من خلال تحليل المؤشرات في الكود أو التنفيذ الثنائي، يمكن كشف ثغرات مثل Buffer Overflow وUse After Free.

أتمنى أن تكون هذه السلسلة مفيدة وإن شاء الله سيكون هناك سلسلة للأمور المتقدمة وسيكون التوسع فيها أكبر بإذن الله وحتى بخصوص المؤشرات الأمور السابقة رح يكون في توسع هائل ان شاء الله، المرحلة القادمة رح تكون دسمة ورح تكون المقالات بتحوي معلومات اكثر غزارة
ح نركز ع أمور السيستم لأن قوة لغة C بتعاملها مع الOS وسرعتها, وبشكر المشرفين والادارة لمنحي الثقة في الشبكة اذكرونا بدعوة والسلام عليكم ورحمة الله وبركاته:ninja:
 
التعديل الأخير:
ح نركز ع أمور السيستم لأن قوة لغة C بتعاملها مع الOS وسرعتها, وبشكر المشرفين والادارة لمنحي الثقة في الشبكة اذكرونا بدعوة والسلام عليكم ورحمة الله وبركاته:ninja:
بارك الله فيك وجزاك الله كل خير حبيبي على هذا الطرح المُميز
ولا داعي للشكر إنما نحن جميعاً في ثغر واحد وهذا واجب الإدارة
الله ييسر امورك ويفتح عليك ويرزقك الرزق الحلال ويغفر لنا ولك وللجميع ذنوبنا بإذن الله
سوف يتم نقل المواضيع المميزة هذه الى قسم خاص " اساسيات لغة ال C مع N0Tb1t "

تحياتي
 
بارك الله فيك وجزاك الله كل خير حبيبي على هذا الطرح المُميز
ولا داعي للشكر إنما نحن جميعاً في ثغر واحد وهذا واجب الإدارة
الله ييسر امورك ويفتح عليك ويرزقك الرزق الحلال ويغفر لنا ولك وللجميع ذنوبنا بإذن الله
سوف يتم نقل المواضيع المميزة هذه الى قسم خاص " اساسيات لغة ال C مع N0Tb1t "

تحياتي
حياك الله وبياك وجعل الجنة مأوانا ومأواك
هذا من بعض ما عندكم اخي الحبيب
آمين يارب واياك ان شاء الله
الله يجزيكم كل خير وان شاء الله في ميزان حسناتكم
 
  • Love
التفاعلات: STORM

آخر المشاركات

عودة
أعلى