سؤال
هل هناك أي طريقة لإنشاء صفيف متغير الحجم بشكل مضاعف في 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
هناك نوعان من الحلول التقليدية:
فقط استخدم مجموعة ديناميكية أحادية البعد من العرض x ارتفاع العناصر ، وحساب مؤشرات 1D من الإحداثيات ثنائية الأبعاد
(y * width + x)
نفسك.استخدم المؤشر إلى المؤشرات:
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;
بوضوح ، نحتاج أيضًا إلى التحقق من تخصيص الذاكرة.