سؤال

في C ، أعلم أنه يمكنني تخصيص مجموعة ثنائية الأبعاد ديناميكيًا على الكومة باستخدام الكود التالي:

int** someNumbers = malloc(arrayRows*sizeof(int*));

for (i = 0; i < arrayRows; i++) {
    someNumbers[i] = malloc(arrayColumns*sizeof(int));
}

من الواضح أن هذا يخلق في الواقع مجموعة أحادية البعد من المؤشرات لمجموعة من المصفوفات أحادية البعد المنفصلة من الأعداد الصحيحة ، و "النظام" يمكن أن يكتشف ما أعنيه عندما أطلب:

someNumbers[4][2];

لكن عندما أعلن بشكل ثابت صفيف ثنائي الأبعاد ، كما في السطر التالي ...:

int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];

... هل يتم إنشاء بنية مماثلة على المكدس ، أم أنها من نموذج آخر تمامًا؟ (أي هل هي مجموعة 1D من المؤشرات؟ إذا لم يكن الأمر كذلك ، فما هو ، وكيف يتم اكتشاف الإشارات إليها؟)

أيضًا ، عندما قلت ، "النظام" ، ما هو المسؤول فعليًا عن اكتشاف ذلك؟ النواة؟ أو هل يقوم برنامج التحويل البرمجي C بفرزه أثناء التجميع؟

هل كانت مفيدة؟

المحلول

يبدو صفيف ثنائي الأبعاد ثابتًا وكأنه مجموعة من المصفوفات - إنها تم وضعها بشكل متجاور في الذاكرة. المصفوفات ليست نفس الشيء مثل المؤشرات ، ولكن لأنه يمكنك في كثير من الأحيان استخدامها بالتبادل إلى حد كبير يمكن أن تكون مربكة في بعض الأحيان. يحتفظ المترجم بالتعقب بشكل صحيح ، مما يجعل كل شيء يصطف بشكل جيد. يجب أن تكون حذراً مع صفائف ثنائية الأبعاد ثابتة كما ذكرت ، لأنه إذا حاولت تمرير واحدة إلى وظيفة تأخذ int ** المعلمة ، الأشياء السيئة ستحدث. هذا مثال سريع:

int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};

في الذاكرة تبدو هكذا:

0 1 2 3 4 5

بالضبط كمثل:

int array2[6] = { 0, 1, 2, 3, 4, 5 };

ولكن إذا حاولت المرور array1 إلى هذه الوظيفة:

void function1(int **a);

ستحصل على تحذير (وسوف يفشل التطبيق في الوصول إلى الصفيف بشكل صحيح):

warning: passing argument 1 of ‘function1’ from incompatible pointer type

لأن صفيف ثنائي الأبعاد ليس هو نفسه int **. إن التحلل التلقائي لمجموعة في مؤشر لا يذهب إلا إلى "مستوى واحد عميق" إذا جاز التعبير. تحتاج إلى إعلان الوظيفة على النحو التالي:

void function2(int a[][2]);

أو

void function2(int a[3][2]);

لجعل كل شيء سعيدًا.

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

نصائح أخرى

تعتمد الإجابة على فكرة أن C لا تفعل حقًا لديك المصفوفات ثنائية الأبعاد-لديها صفيفات. عندما تعلن هذا:

int someNumbers[4][2];

أنت تطلب someNumbers لتكون مجموعة من 4 عناصر ، حيث يكون كل عنصر من عناصر تلك الصفيف من النوع int [2] (وهو بحد ذاته مجموعة من 2 intس).

الجزء الآخر من اللغز هو أن المصفوفات يتم وضعها دائمًا في الذاكرة. إذا طلبت:

sometype_t array[4];

ثم سيبدو هذا دائمًا هكذا:

| sometype_t | sometype_t | sometype_t | sometype_t |

(4 sometype_t الكائنات الموضوعة بجوار بعضها البعض ، مع عدم وجود مسافات بينهما). لذلك في الخاص بك someNumbers صفيف المباراة ، سيبدو هكذا:

| int [2]    | int [2]    | int [2]    | int [2]    |

وكل int [2] العنصر هو نفسه صفيف ، يبدو أن هذا:

| int        | int        |

بشكل عام ، تحصل على هذا:

| int | int  | int | int  | int | int  | int | int  |
unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}};

في الذاكرة يساوي:

unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9};

رداً علىك أيضًا: كلاهما ، على الرغم من أن المترجم يقوم بمعظم الرفع الثقيل.

في حالة المصفوفات المخصصة بشكل ثابت ، سيكون "النظام" هو المترجم. سيحتفظ بالذاكرة كما لو كانت لأي متغير مكدس.

في حالة صفيف Malloc'd ، سيكون "النظام" هو تطبيق Malloc (النواة عادة). كل المترجم الذي سيخصصه هو المؤشر الأساسي.

سيتعامل المحول البرمجي دائمًا مع هذا النوع حيث يُعلن أنه إلا في المثال الذي أعطاه كارل حيث يمكنه معرفة الاستخدام القابل للتبديل. هذا هو السبب في أنك إذا مررت في [] [] إلى وظيفة ، فيجب أن تفترض أنها شقة مخصصة بشكل ثابت ، حيث يُفترض أن ** مؤشر للمؤشر.

للوصول إلى صفيف ثنائي الأبعاد معين ، ضع في اعتبارك خريطة الذاكرة لإعلان صفيف كما هو موضح في الكود أدناه:

    0  1
a[0]0  1
a[1]2  3

للوصول إلى كل عنصر ، يكفي تمرير الصفيف الذي تهتم به كمعلمات للوظيفة. ثم استخدم إزاحة العمود للوصول إلى كل عنصر على حدة.

int a[2][2] ={{0,1},{2,3}};

void f1(int *ptr);

void f1(int *ptr)
{
    int a=0;
    int b=0;
    a=ptr[0];
    b=ptr[1];
    printf("%d\n",a);
    printf("%d\n",b);
}

int main()
{
   f1(a[0]);
   f1(a[1]);
    return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top