سؤال

هل هناك أي طريقة لإنشاء صفيف متغير الحجم بشكل مضاعف في C (وليس C ++ ، فقط ج)؟ أعلم أنه لإنشاء مجموعة متغيرة الحجم منفردة ، يمكنك فقط استخدام مؤشر ، على سبيل المثال

float *array;
array = (float *) calloc(sizeof(float), n);

يخلق مجموعة منفردة من عوامات الحجم n. هل هناك شيء مشابه يمكنني القيام به في صفائف مكتوبة مضاعفة؟

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

المحلول

لا توجد صفائف مزدوجة في C ؛ لا يوجد سوى صفائف من المصفوفات. على سبيل المثال:

int a[3][3];

يجب أن تقرأ على أنها "صفيف من 3 صفائف من 3 ints" ، وليس كـ "صفيف من 3x3 ints". هذا مرئي على الفور من أنواع التعبيرات - على سبيل المثال a[0] هو تعبير صحيح ، ونوعه هو int[3].

بالنسبة لأنواع الصفيف ، يعد حجم الصفيف جزءًا من النوع ، وبالتالي يجب أن يكون معروفًا في وقت الترجمة. لذلك ، على الرغم من أنه يمكنك الحصول على نوع "مؤشر إلى المصفوفات" لجعل بُعد واحد ديناميكيًا ، إلا أنه لا يزال يتعين إصلاح الأبعاد المتبقية:

int (*p)[3] // pointer to arrays of 3 ints each

هناك نوعان من الحلول التقليدية:

  1. فقط استخدم مجموعة ديناميكية أحادية البعد من العرض x ارتفاع العناصر ، وحساب مؤشرات 1D من الإحداثيات ثنائية الأبعاد (y * width + x) نفسك.

  2. استخدم المؤشر إلى المؤشرات:

    int** a = malloc(sizeof(int*) * height);
    for (i = 0; i < height; ++i) a[i] = malloc(sizeof(int) * width);
    a[0][0] = 123;
    ...
    

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

في C99 ، يمكنك أيضًا استخدام المصفوفات ذات الطول المتغير:

void foo(int width, int height) {
    int a[width][height];
    ...
}

نصائح أخرى

ال Comp.lang.c الأسئلة الشائعة لديه قسم جيد في هذا.

يمكنك أن تفعل نفس الشيء تقريبا للمصفوفات متعددة الأبعاد.

float **array;
array = calloc(sizeof(float*), n);
for(int i = 0; i < n; i++)
{
    array[i] = calloc(sizeof(float), n);
}

إذا كنت تريد مصفوفة مع صفوف N والأعمدة M ، فيمكنك استخدام مجموعة خطية من الطول m*n لتمثيل هذا ، حيث كل فهرس i يمثل

row = i  / n
col = i  % n

ورسم الخرائط العكسية

i  = row * n  + col

تستخدم معظم حزم الجبر التي تستخدم المصفوفات مثل MATLAB هذا التمثيل بالفعل ، لأنه يعتمد جيدًا على أي بُعد (يمكنك تعميم هذا إلى مصفوفة ثلاثية الأبعاد أيضًا).

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

int Index(int i, int j, int numCols)
{ 
    return i * numCols + j;
}

int numRows = 100;
int numCols = 200;

float *data = malloc(sizeof(float) * numRows * numCols);

data[Index(34, 56, numCols)] = 42.0f;

يمكنك استخدام المصفوفات المتغيرة الطول C99 (تعمل مع GCC):

#include <stdio.h>
#include <stdlib.h>

void foo(size_t rows, size_t cols, float array[rows][cols])
{
    printf("%f\n", array[2][3]);
}

int main(void)
{
    size_t rows = 4;
    size_t cols = 5;
    float (*array)[cols] = calloc(sizeof (float), rows * cols);
    array[2][3] = 42;
    foo(rows, cols, array);
}

أنا مندهش من أن أحداً لم يشر إلى البديل "الواضح" الذي يحافظ على التخصيص المتجاوب المفرد للمصفوفة الرئيسية ، ولكن لديه ناقل المؤشرات لإعطاء الاشتراك المزدوج. (أفترض أن هذا يعني أنه ليس واضحًا ، بعد كل شيء.)

float **array2d = malloc(sizeof(*array2d) * height);
float  *array1d = malloc(sizeof(*array1d) * height * width);

for (i = 0; i < height; ++i)
    array2d[i] = &array1d[i * width];

يمكنك الآن كتابة Array Array ثنائية الأبعاد كالمعتاد:

array2d[0][0] = 123.0;

بوضوح ، نحتاج أيضًا إلى التحقق من تخصيص الذاكرة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top