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

StackOverflow https://stackoverflow.com/questions/37538

  •  09-06-2019
  •  | 
  •  

سؤال

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

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

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

المحلول

ملخص تنفيذي:

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

الإجابة الكاملة:

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

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

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

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

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

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

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

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

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

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

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

نصائح أخرى

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

وبالتالي، فإن الوظائف الداخلية لا تعمل هذه الطريقة.بدلاً من ذلك، قم دائمًا بتمرير معلمة إضافية size_t size تشير إلى عدد العناصر في المصفوفة.

امتحان:

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

void printSizeOf(int intArray[]);
void printLength(int intArray[]);

int main(int argc, char* argv[])
{
    int array[] = { 0, 1, 2, 3, 4, 5, 6 };

    printf("sizeof of array: %d\n", (int) sizeof(array));
    printSizeOf(array);

    printf("Length of array: %d\n", (int)( sizeof(array) / sizeof(array[0]) ));
    printLength(array);
}

void printSizeOf(int intArray[])
{
    printf("sizeof of parameter: %d\n", (int) sizeof(intArray));
}

void printLength(int intArray[])
{
    printf("Length of parameter: %d\n", (int)( sizeof(intArray) / sizeof(intArray[0]) ));
}

الإخراج (في نظام التشغيل Linux 64 بت):

sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2

الإخراج (في نظام التشغيل Windows 32 بت):

sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1

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

int a[10];
int* p = a;

assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));

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

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

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

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);

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

int size = (&arr)[1] - arr;

الدفع هذا الرابط للتوضيح

يمكنك استخدام مشغل SizeOF ولكنه لن يعمل من أجل وظائف لأنه سيستغرق مرجع المؤشر الذي يمكنك القيام بما يلي للعثور على طول المصفوفة:

len = sizeof(arr)/sizeof(arr[0])

تم العثور على الكود في الأصل هنا:برنامج C للعثور على عدد العناصر في مجموعة

إذا كنت تعرف نوع بيانات المصفوفة، فيمكنك استخدام شيء مثل:

int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};

int noofele = sizeof(arr)/sizeof(int);

أو إذا كنت لا تعرف نوع بيانات المصفوفة، فيمكنك استخدام شيء مثل:

noofele = sizeof(arr)/sizeof(arr[0]);

ملحوظة:يعمل هذا الشيء فقط إذا لم يتم تعريف المصفوفة في وقت التشغيل (مثل malloc) ولم يتم تمرير المصفوفة في دالة.في كلتا الحالتين، arr (اسم الصفيف) هو المؤشر.

الماكرو 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 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",        " " },
};

ولكن يمكن تقييم هذه الثوابت في وقت الترجمة أيضًا باستخدام حجم:

#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])

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

حجم المصفوفة في لغة 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
sizeof(array) / sizeof(array[0])
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))

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

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

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

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

// 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/

@ جحش:يعرّف المعيار sizeof بأنه ينتج عدد البايتات في الكائن وأن sizeof (char) هو دائمًا واحد.عدد البتات في البايت محدد بالتنفيذ.

يحرر:القسم القياسي ANSI C++ 5.3.3 الحجم:

يعطي عامل sizeof عدد البايتات في تمثيل الكائن لمعامله.[...] sizeof (char)، sizeof (char مُوقع) وsizeof (char غير مُوقع) هي 1؛يتم تحديد نتيجة تطبيق sizeof على أي نوع أساسي آخر.

القسم 1.6 نموذج الذاكرة C++:

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

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

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

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

إذا كنت تريد حقًا القيام بذلك لتمرير المصفوفة الخاصة بك، أقترح تنفيذ بنية لتخزين مؤشر إلى النوع الذي تريد مصفوفة به وعددًا صحيحًا يمثل حجم المصفوفة.ثم يمكنك تمرير ذلك إلى وظائفك.ما عليك سوى تعيين قيمة متغير الصفيف (مؤشر إلى العنصر الأول) لهذا المؤشر.ثم يمكنك الذهاب 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;
}

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

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

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

الوظيفة sizeof تقوم بإرجاع عدد البايتات التي تستخدمها الصفيف الخاص بك في الذاكرة.إذا كنت تريد حساب عدد العناصر في المصفوفة الخاصة بك، فيجب عليك تقسيم هذا الرقم على sizeof نوع متغير من المصفوفة.دعنا نقول int array[10];, ، إذا كان عدد صحيح من النوع المتغير في جهاز الكمبيوتر الخاص بك هو 32 بت (أو 4 بايت)، فمن أجل الحصول على حجم المصفوفة الخاصة بك، يجب عليك القيام بما يلي:

int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);

يمكنك استخدام ال & المشغل أو العامل.هنا هو شفرة المصدر:

#include<stdio.h>
#include<stdlib.h>
int main(){

    int a[10];

    int *p; 

    printf("%p\n", (void *)a); 
    printf("%p\n", (void *)(&a+1));
    printf("---- diff----\n");
    printf("%zu\n", sizeof(a[0]));
    printf("The size of array a is %zu\n", ((char *)(&a+1)-(char *)a)/(sizeof(a[0])));


    return 0;
};

هنا هو إخراج العينة

1549216672
1549216712
---- diff----
4
The size of array a is 10
int a[10];
int size = (*(&a+1)-a) ;

لمزيد من التفاصيل انظرهناو أيضا هنا.

مثال

#include <stdio.h>

int main() {
    int size;
    scanf("%d", &size);
    int array[size];
    printf("%d\n", (int) (sizeof(array) / sizeof(int)));
    printf("%d\n", (int) (sizeof(array) / sizeof(array[0])));
    return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top