مصفوفة متغيرة الطول

في برمجة الحاسوب ، تُعرف المصفوفة ذات الطول المتغير ( VLA )، والتي تُسمى أيضًا المصفوفة ذات الحجم المتغير أو المصفوفة ذات الحجم المحدد وقت التشغيل ، بأنها بنية بيانات مصفوفة يتم تحديد طولها أثناء التشغيل ، وليس أثناء الترجمة . [ 1 ] في لغة C ، يُقال إن المصفوفة ذات الطول المتغير لها نوع بيانات مُعدَّل متغير يعتمد على قيمة معينة (انظر النوع التابع ).

يتمثل الغرض الرئيسي من المصفوفات الكبيرة جدًا في تبسيط برمجة الخوارزميات العددية .

تشمل لغات البرمجة التي تدعم المصفوفات ذات المصفوفات الطويلة جدًا (VLAs) كلاً من Ada و ALGOL 68 (للصفوف غير المرنة) و APL و C# (كمصفوفات مخصصة في وضع غير آمن على المكدس ) و COBOL و Fortran 90 و J و Object Pascal (اللغة المستخدمة في Delphi و Lazarus ، والتي تستخدم FPC). أضافت C99 دعمًا للمصفوفات ذات المصفوفات الطويلة جدًا، إلا أنها أصبحت في C11 ميزة شرطية، لا يُشترط على التطبيقات دعمها؛ [ 2 ] [ 3 ] في بعض المنصات، كان من الممكن سابقًا تنفيذ المصفوفات ذات المصفوفات الطويلة جدًا باستخدام alloca()دوال مشابهة.

تُعدّ المصفوفات القابلة للتوسيع (وتُسمى أيضًا المصفوفات الديناميكية ) أكثر فائدةً من المصفوفات ذات الطول المتغير، لأنها تُتيح القيام بكل ما تُتيحه المصفوفات ذات الطول المتغير، بالإضافة إلى دعم توسيع المصفوفة أثناء التشغيل. لهذا السبب، تدعم العديد من لغات البرمجة ( مثل JavaScript و Java و Python و R وغيرها) المصفوفات القابلة للتوسيع فقط. حتى في اللغات التي تدعم المصفوفات ذات الطول المتغير، يُنصح غالبًا بتجنب استخدامها (المبنية على المكدس)، واستخدام المصفوفات الديناميكية ( المبنية على الكومة ) بدلاً منها. [ 4 ]

ذاكرة

توزيع

  • تقوم مجموعة مترجمات GNU (GCC) للغة C بتخصيص الذاكرة لوحدات VLA مع مدة تخزين تلقائية على المكدس . [ 5 ] هذا هو الخيار الأسرع والأكثر مباشرة مقارنة بتخصيص الذاكرة على الكومة، ويستخدمه معظم المترجمات.
  • يمكن أيضًا تخصيص وحدات الذاكرة الافتراضية (VLAs) على الكومة والوصول إليها داخليًا باستخدام مؤشر إلى هذه الكتلة.

تطبيق

آدا

فيما يلي نفس المثال بلغة Ada . تحمل مصفوفات Ada حدودها معها، لذلك لا حاجة لتمرير الطول إلى دالة Process.

نوع Vals_Type هو مصفوفة ( نطاق موجب <>) من نوع Float ؛دالة Read_And_Process ( N : عدد صحيح ) تُرجع Float هي Vals : Vals_Type ( 1 .. N ); ابدأ حلقة for I in 1 .. N حلقة Vals ( I ) := Read_Val ; نهاية الحلقة ; إرجاع Process ( Vals ); نهاية Read_And_Process ;

فورتران 90

الدالة المكافئة في لغة فورتران 90 هي

دالة read_and_process ( n ) result ( o ) عدد صحيح ، نية ( in ) :: n عدد حقيقي :: oحقيقي ، بُعد ( ن ) :: قيم عدد صحيح :: ido i = 1 , n vals ( i ) = read_val () end do o = process ( vals ) end function read_and_process

عند استخدام ميزة Fortran 90 للتحقق من واجهات الإجراءات في وقت الترجمة؛ من ناحية أخرى، إذا كانت الدوال تستخدم واجهة استدعاء ما قبل Fortran 90، فيجب أولاً تعريف الدوال (الخارجية)، ويجب تمرير طول المصفوفة بشكل صريح كوسيط (كما هو الحال في لغة C):

دالة read_and_process ( n ) result ( o ) عدد صحيح ، نية ( in ) :: n عدد حقيقي :: oحقيقي ، بُعد ( ن ) :: قيم حقيقي :: قراءة_القيمة ، عملية عدد صحيح :: ido i = 1 , n vals ( i ) = read_val () end do o = process ( vals , n ) end function read_and_process

ج

تتطلب بعض معايير لغة C دعم المصفوفات ذات الأطوال المتغيرة. لم تكن المصفوفات ذات الأطوال المتغيرة جزءًا من معيار لغة C++ .

تقوم دالة C99 التالية بتخصيص مصفوفة متغيرة الطول بحجم محدد، وتملأها بقيم عشرية، ثم تمررها إلى دالة أخرى للمعالجة. ولأن المصفوفة مُعرّفة كمتغير تلقائي، فإن عمرها ينتهي عند readAndProcess()انتهاء الدالة.

float readAndProcess ( int n ) { float vals [ n ];for ( int i = 0 ; i < n ; ++ i ) { scanf ( "%f" , & vals [ i ]); }return process ( n , vals ); }

في معيار C99، يجب أن يسبق مُعامل الطول مُعامل المصفوفة ذات الطول المتغير في استدعاءات الدوال. [ 1 ] في معيار C11، __STDC_NO_VLA__يتم تعريف ماكرو في حال عدم دعم المصفوفات ذات الطول المتغير. [ 6 ] يُعيد معيار C23 فرض أنواع المصفوفات ذات الطول المتغير. إنشاء كائنات المصفوفات ذات الطول المتغير بمدة تخزين تلقائية هو الخيار الوحيد. [ 7 ] كان لدى GCC امتداد للمصفوفات ذات الطول المتغير قبل معيار C99، وهو امتداد يمتد أيضًا إلى لهجة C++ الخاصة به.

أعرب لينوس تورفالدز سابقًا عن استيائه من استخدام VLA للمصفوفات ذات الأحجام الصغيرة المحددة مسبقًا، لأنه يُنتج شيفرة تجميعية أقل جودة. [ 8 ] مع نواة لينكس 4.20، أصبحت نواة لينكس خالية فعليًا من VLA. [ 9 ]

على الرغم من أن معيار C11 لا يحدد صراحةً حدًا أقصى لحجم VLAs، يعتقد البعض أنه ينبغي أن يكون له نفس الحجم الأقصى لجميع الكائنات الأخرى، أي SIZE_MAXبالبايت. [ 10 ] ومع ذلك، ينبغي فهم هذا في السياق الأوسع لحدود البيئة والمنصة، مثل حجم صفحة حماية المكدس النموذجي البالغ 4 كيلوبايت، وهو أصغر بكثير من حجم VLAs SIZE_MAX.

من الممكن الحصول على كائن VLA مع تخزين ديناميكي باستخدام مؤشر إلى مصفوفة.

#include <stdio.h> #include <stdlib.h>float readAndProcess ( int n ) { float ( * vals )[ n ] = malloc ( sizeof ( float [ n ]));for ( int i = 0 ; i < n ; ++ i ) { scanf ( "%f" , & ( * vals )[ i ]); }float ret = process ( n , * vals ); free ( vals ); return ret ; }

لغة سي++

على الرغم من أن لغة C++ لا تدعم المصفوفات ذات الطول المتغير المُخصصة في الذاكرة المكدسة (على عكس لغة C التي تدعمها)، إلا أن بعض إضافات المُصرّف، مثل GCC و Clang ، قد تسمح بذلك . وإلا، فسيتم تخصيص المصفوفة في الذاكرة الديناميكية، ولكن std::vectorمن الأفضل استخدام نوع مجموعة مثل `collection`. وذلك لأن أنواع المجموعات الموجودة في C++ تستخدم تلقائيًا " استحواذ الموارد هو التهيئة " (RAII)، وستقوم بإلغاء تخصيصها تلقائيًا بمجرد الخروج من نطاقها.

int * createIntArray ( size_t n ) { return new int [ n ]; }int main ( int argc , char * argv []) { int * a = createIntArray ( 5 ); // تنفيذ إجراء ما على المصفوفةحذف [] أ ; }

سي شارب

يُعلن جزء الكود التالي في لغة C# عن مصفوفة أعداد صحيحة ذات طول متغير. قبل إصدار C# 7.2، كان يلزم وجود مؤشر إلى المصفوفة، مما يستلزم استخدام سياق "غير آمن". تتطلب الكلمة المفتاحية "غير آمن" أن يكون التجميع الذي يحتوي على هذا الكود مُعلَّمًا على أنه غير آمن.

دالة غير آمنة تُسمى DeclareStackBasedArrayUnsafe ( int size ) { int * p = stackalloc int [ size ]; p [ 0 ] = 123 ; }

تسمح إصدارات C# 7.2 والإصدارات الأحدث بتخصيص المصفوفة بدون استخدام الكلمة المفتاحية "unsafe"، وذلك من خلال استخدام هذه System.Span<T>الميزة. [ 11 ]

باستخدام النظام ؛void DeclareStackBasedArraySafe ( int size ) { Span < int > a = stackalloc int [ size ]; a [ 0 ] = 123 ; }

كوبول

يُعلن جزء COBOL التالي عن مصفوفة سجلات DEPT-PERSONذات طول متغير، حيث يتم تحديد طولها (عدد عناصرها) بواسطة قيمة PEOPLE-CNT:

قسم البيانات . قسم التخزين المؤقت . 01 قسم-الأفراد . 05 عدد الأفراد PIC S9(4) ثنائي . 05 قسم-الشخص يتكرر من 0 إلى 20 مرة حسب عدد الأفراد . 10 اسم الشخص PIC X(20) . 10 أجر الشخص PIC S9(7)V99 عشري مضغوط .

تتميز لغة COBOL VLA، على عكس اللغات الأخرى المذكورة هنا، بأنها آمنة لأن COBOL تتطلب تحديد الحد الأقصى لحجم المصفوفة. في هذا المثال، DEPT-PERSONلا يمكن أن تحتوي المصفوفة على أكثر من 20 عنصرًا، بغض النظر عن قيمة PEOPLE-CNT.

جافا

تقوم لغة جافا بتحديد حجم المصفوفات بمجرد إنشائها، ولكن يمكن تحديد حجمها في وقت التشغيل.

public class Example { public static int [] createIntArray ( int size ) { return new int [ size ] ; }public static void main ( String [] args ) { try { String s = IO . readln ( "أدخل عددًا صحيحًا لحجم المصفوفة: " ); int size = Integer . parseInt ( s ); int [] a = createArray ( size ); System . out . printf ( "تم إنشاء مصفوفة من نوع int[] بحجم %d" , size ); } catch ( NumberFormatException e ) { System . err . printf ( "قراءة عدد صحيح غير صالحة: %s%n" , e . getMessage ()); } } }

أوبجكت باسكال

يتم تخصيص المصفوفات الديناميكية في لغة Object Pascal على الكومة. [ 12 ]

في هذه اللغة، يُطلق عليه اسم المصفوفة الديناميكية. يشبه تعريف هذا النوع من المتغيرات تعريف المصفوفة الثابتة، ولكن دون تحديد حجمها. يُحدد حجم المصفوفة عند استخدامها.

برنامج إنشاء مصفوفة ديناميكية من الأرقام ( الحجم : عدد صحيح ) ؛ متغير مصفوفة الأرقام : مصفوفة من الكلمات الطويلة ؛ ابدأ تعيين الطول ( مصفوفة الأرقام ، الحجم ) ؛ مصفوفة الأرقام [ 0 ] := 2020 ؛ نهاية .

تتم إزالة محتويات المصفوفة الديناميكية عن طريق تعيين حجم لها يساوي صفرًا.

... SetLength ( NumberArray , 0 ) ; ...

مراجع

  1. 1 2 "المصفوفات ذات الطول المتغير" . مؤرشف من الأصل بتاريخ 2018-01-26.
  2. "طول متغير - استخدام مجموعة مترجمات GNU (GCC)" .
  3. ISO 9899:2011 لغات البرمجة – C 6.7.6.2 4.
  4. ريموند، إريك س. (2000). "دليل ريموند لممارسات إصدار البرمجيات: 6. ممارسات التطوير الجيدة" . مشروع توثيق لينكس .
  5. "خيارات توليد الكود - مترجم GNU Fortran" .
  6. § 6.10.8.3 من معيار C11 (n1570.pdf)
  7. § 6.10.9.3 من معيار C23 (n3054.pdf)
  8. تورفالدز، لينوس (7 مارس 2018). "LKML: لينوس تورفالدز: ردًا على: إزالة VLA (كان ردًا على: [ RFC 2/2 ] lustre: استخدام VLA_SAFE)" . نواة لينكس (قائمة بريدية).
  9. "نواة لينكس الآن خالية من VLA: مكسب للأمان، وتقليل النفقات العامة، وتحسين أداء Clang - Phoronix " . www.phoronix.com
  10. §6.5.3.4 و §7.20.3 من معيار C11 (n1570.pdf)
  11. "عامل تخصيص الذاكرة المكدسية (مرجع C#)" . مايكروسوفت. 10 يوليو 2024.
  12. مايكل فان كانيت. "دليل مرجعي مجاني لـ Free Pascal: المصفوفات الديناميكية" .