مصفوفة - شرح المصفوفات في c++




كيف يمكنني تحديد حجم المصفوفة في C؟ (13)

كيف يمكنني تحديد حجم المصفوفة في C؟

أي عدد العناصر التي يمكن أن تحتويها الصفيف؟


Skizz: أنا متأكد من أنني على حق ، على الرغم من أن أفضل "مصدر" أستطيع أن أعطيكم في الوقت الحالي هو ويكيبيديا ، من المادة على sizeof:

ويكيبيديا مخطئة ، سكيز على حق. sizeof (char) هو 1 ، بحكم التعريف.

أعني ، مجرد قراءة مدخل ويكيبيديا عن كثب لمعرفة أنه من الخطأ. "مضاعفات شار". لا يمكن أن يكون sizeof(char) أي شيء آخر غير "1". إذا كان ، على سبيل المثال ، 2 ، فهذا يعني أن sizeof(char) كان ضعف حجم char!


"لقد قمت بتقديم طريقة خفية لإطلاق النار على نفسك في القدم"

لا تقوم صفائف C 'native' بتخزين حجمها. لذلك يوصى بحفظ طول الصفيف في متغير / const منفصل ، وتمريره كلما قمت بالمرور ، أي:

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

يجب عليك دائما تجنب المصفوفات الأصلية (إلا إذا كنت لا تستطيع ، في هذه الحالة ، مانع قدمك). إذا كنت تكتب C ++ ، فاستخدم حاوية ناقلات STL . "بالمقارنة مع المصفوفات ، فإنها توفر نفس الأداء تقريبًا" ، وهي أكثر فائدة بكثير!

// vector is a template, the <int> means it is a vector of ints
vector<int> numbers;  

// push_back() puts a new value at the end (or back) of the vector
for (int i = 0; i < 10; i++)
    numbers.push_back(i);

// Determine the size of the array
cout << numbers.size();

انظر: http://www.cplusplus.com/reference/stl/vector/


أفضل طريقة هي حفظ هذه المعلومات ، على سبيل المثال ، في بنية:

typedef struct {
     int *array;
     int elements;
} list_s;

تنفيذ جميع الوظائف الضرورية مثل إنشاء ، تدمير ، التحقق من المساواة ، وكل ما تحتاجه. من السهل تمرير كمعلمة.


إذا كنت تريد حقاً القيام بذلك لتمرير الصفيف الخاص بك ، أقترح تنفيذ بنية لتخزين مؤشر إلى النوع الذي تريده من صفيف وعدد صحيح يمثل حجم الصفيف. ثم يمكنك تمرير ذلك حول وظائفك. فقط قم بتعيين قيمة متغير الصفيف (المؤشر إلى العنصر الأول) إلى هذا المؤشر. ثم يمكنك الانتقال Array.arr[i] للحصول على العنصر i واستخدام Array.size للحصول على عدد العناصر في الصفيف.

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

/* Absolutely no one should use this...
   By the time you're done implementing it you'll wish you just passed around
   an array and size to your functions */
/* This is a static implementation. You can get a dynamic implementation and 
   cut out the array in main by using the stdlib memory allocation methods,
   but it will work much slower since it will store your array on the heap */

#include <stdio.h>
#include <string.h>
/*
#include "MyTypeArray.h"
*/
/* MyTypeArray.h 
#ifndef MYTYPE_ARRAY
#define MYTYPE_ARRAY
*/
typedef struct MyType
{
   int age;
   char name[20];
} MyType;
typedef struct MyTypeArray
{
   int size;
   MyType *arr;
} MyTypeArray;

MyType new_MyType(int age, char *name);
MyTypeArray newMyTypeArray(int size, MyType *first);
/*
#endif
End MyTypeArray.h */

/* MyTypeArray.c */
MyType new_MyType(int age, char *name)
{
   MyType d;
   d.age = age;
   strcpy(d.name, name);
   return d;
}

MyTypeArray new_MyTypeArray(int size, MyType *first)
{
   MyTypeArray d;
   d.size = size;
   d.arr = first;
   return d;
}
/* End MyTypeArray.c */


void print_MyType_names(MyTypeArray d)
{
   int i;
   for (i = 0; i < d.size; i++)
   {
      printf("Name: %s, Age: %d\n", d.arr[i].name, d.arr[i].age);
   }
}

int main()
{
   /* First create an array on the stack to store our elements in.
      Note we could create an empty array with a size instead and
      set the elements later. */
   MyType arr[] = {new_MyType(10, "Sam"), new_MyType(3, "Baxter")};
   /* Now create a "MyTypeArray" which will use the array we just
      created internally. Really it will just store the value of the pointer
      "arr". Here we are manually setting the size. You can use the sizeof
      trick here instead if you're sure it will work with your compiler. */
   MyTypeArray array = new_MyTypeArray(2, arr);
   /* MyTypeArray array = new_MyTypeArray(sizeof(arr)/sizeof(arr[0]), arr); */
   print_MyType_names(array);
   return 0;
}

استعمال:

int a=[10] = {1, 2, 3, 4, 5};
int n = sizeof(a);
printf("%d", n);

انتاج:

5

السبب: يحسب عدد العناصر المحتفظ بها في المصفوفة بدلاً من عدد المساحات الحرة المخصصة لها.


بالنسبة إلى المصفوفات متعددة الأبعاد ، يعد الأمر أكثر تعقيدًا. في كثير من الأحيان يحدد الناس الثوابت الكلي صريحة ، أي

#define g_rgDialogRows   2
#define g_rgDialogCols   7

static char const* g_rgDialog[g_rgDialogRows][g_rgDialogCols] =
{
    { " ",  " ",    " ",    " 494", " 210", " Generic Sample Dialog", " " },
    { " 1", " 330", " 174", " 88",  " ",    " OK",        " " },
};

ولكن يمكن تقييم هذه الثوابت في وقت التجميع أيضًا مع sizeof :

#define rows_of_array(name)       \
    (sizeof(name   ) / sizeof(name[0][0]) / columns_of_array(name))
#define columns_of_array(name)    \
    (sizeof(name[0]) / sizeof(name[0][0]))

static char* g_rgDialog[][7] = { /* ... */ };

assert(   rows_of_array(g_rgDialog) == 2);
assert(columns_of_array(g_rgDialog) == 7);

لاحظ أن هذا الرمز يعمل في C و C ++. للصفائف مع أكثر من استخدام البعدين

sizeof(name[0][0][0])
sizeof(name[0][0][0][0])

إلخ ، إلى ما لا نهاية للإعلان.


حجم "خدعة" هو أفضل طريقة أعرف ، مع واحد صغير ولكن (بالنسبة لي ، وهذا هو غضب الحيوانات الأليفة الرئيسية) تغيير مهم في استخدام قوس.

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

لذلك: إذا كان لديك ما يلي:

int myArray[10];

يمكنك العثور على عدد العناصر ذات الكود كما يلي:

size_t n = sizeof myArray / sizeof *myArray;

هذا ، بالنسبة لي ، يقرأ أسهل بكثير من البديل مع قوسين. أنا أيضا أؤيد استخدام العلامة النجمية في الجزء الأيمن من القسم ، نظرًا لأنها أكثر إيجازًا من الفهرسة.

بالطبع ، هذا هو كل وقت تجميع أيضا ، لذلك لا داعي للقلق بشأن التقسيم الذي يؤثر على أداء البرنامج. لذلك استخدم هذا النموذج أينما كنت.

من الأفضل دائمًا استخدام sizeof على كائن فعلي عندما يكون لديك كائن ، بدلاً من نوع ، حيث لا داعي للقلق بشأن حدوث خطأ وتحديد نوع الخطأ.

على سبيل المثال ، لنفترض أن لديك دالة تقوم بإخراج بعض البيانات كدفق من وحدات البايت ، على سبيل المثال عبر شبكة. دعنا نطلق الدالة send() ، ونجعلها تأخذ كوسيط إلى الكائن المطلوب إرساله ، وعدد البايتات في الكائن. لذلك ، يصبح النموذج الأولي:

void send(const void *object, size_t size);

ومن ثم تحتاج إلى إرسال عدد صحيح ، بحيث يمكنك ترميزه على النحو التالي:

int foo = 4711;
send(&foo, sizeof (int));

الآن ، لقد قمت بتقديم طريقة خفية لتصوير نفسك في القدم ، من خلال تحديد نوع foo في مكانين. إذا تغير واحد ولكن الآخر لا ، فسينقسم الكود. وهكذا ، دائما افعل ذلك على النحو التالي:

send(&foo, sizeof foo);

أنت الآن محمي. بالتأكيد ، أنت تقوم بتكرار اسم المتغير ، لكن ذلك له احتمالية عالية لكسر الطريقة التي يمكن أن يكتشفها المجمع ، إذا قمت بتغييرها.


حجم صفيف في C:

int a[10];
size_t size_of_array = sizeof(a);      // Size of array a
int n = sizeof (a) / sizeof (a[0]);    // Number of elements in array a
size_t size_of_element = sizeof(a[0]); // Size of each element in array a                                          
                                       // Size of each element = size of type

ملخص تنفيذي:

int a[17];
n = sizeof(a)/sizeof(a[0]);

لتحديد حجم الصفيف بالبايت ، يمكنك استخدام مشغل sizeof :

int a[17];
int n = sizeof(a);

على جهاز الكمبيوتر الخاص بي ، يبلغ طول البايت 4 بايت ، لذا فإن n يبلغ 68.

لتحديد عدد العناصر في الصفيف ، يمكننا تقسيم الحجم الإجمالي للصفيف حسب حجم عنصر الصفيف. يمكنك فعل هذا بالنوع ، مثل هذا:

int a[17];
int n = sizeof(a) / sizeof(int);

والحصول على الإجابة المناسبة (68/4 = 17) ، ولكن إذا كان نوع التغيير قد يكون لديك خطأ مقرف إذا نسيت تغيير حجم sizeof(int) كذلك.

وبالتالي فإن المقسوم المفضل هو sizeof(a[0]) ، حجم عنصر الصفر في المصفوفة.

int a[17];
int n = sizeof(a) / sizeof(a[0]);

ميزة أخرى هي أنه يمكنك الآن بسهولة تعيين اسم الصفيف في الماكرو والحصول على:

#define NELEMS(x)  (sizeof(x) / sizeof((x)[0]))

int a[17];
int n = NELEMS(a);

يتم ARRAYELEMENTCOUNT(x) الماكرو ARRAYELEMENTCOUNT(x) الذي يستخدمه الجميع بشكل غير صحيح . هذا ، في الواقع ، هو مجرد مسألة حساسة ، لأنه لا يمكن أن يكون لديك تعبيرات تؤدي إلى نوع "مصفوفة".

/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))

ARRAYELEMENTCOUNT(p + 1);

يقيم في الواقع على النحو التالي:

(sizeof (p + 1) / sizeof (p + 1[0]));

بينما

/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])

ARRAYELEMENTCOUNT(p + 1);

يقيّم بشكل صحيح إلى:

(sizeof (p + 1) / sizeof (p + 1)[0]);

هذا حقا ليس لديها الكثير لتفعله مع حجم المصفوفات بشكل واضح. لقد لاحظت الكثير من الأخطاء من عدم ملاحظة كيف يعمل المعالج الأولي C. دائمًا ما تقوم بتغليف معلمة الماكرو ، وليس تعبيرًا قد يكون متورطًا فيه.

هذا صحيح؛ كان مثالى سيئًا لكن هذا في الواقع ما يجب أن يحدث. كما ذكرت سابقا p + 1 سوف ينتهي كنوع المؤشر وإبطال الماكرو بأكمله (تماما مثل إذا حاولت استخدام الماكرو في وظيفة مع مؤشر المؤشر).

في نهاية اليوم ، في هذه الحالة بالذات ، الخطأ لا يهم حقا (لذلك أنا فقط أهدر وقت الجميع ، huzzah!) ، لأنك لا تملك تعبيرات مع نوع من 'مجموعة'. ولكن في الحقيقة ، فإن النقطة التي تتعلق بأجزاء فرعية من التقييمات المسبقة للابتكار هي فكرة مهمة.



#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))

sizeof(array) / sizeof(array[0])




memory