Как определить размер моего массива в C?

Как определить размер моего массива в C?

то есть, количество элементов, которые может содержать массив?

21 ответов


резюме:

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

определить размер массива в байтах, вы можете использовать sizeof оператор:

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

на моем компьютере ints имеют длину 4 байта, поэтому n-68.

определить количество элементов в массиве, мы можем разделить общий размер массива по размеру элемента массива. Вы можете сделать это с типом, например:

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

и получаем правильный ответ (68 / 4 = 17), но если тип из a изменено у вас будет неприятная ошибка, если вы забыли изменить the sizeof(int) как хорошо.

так что выбранный делитель sizeof(a[0]), размер zeroeth элемент массива.

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 путь это правильный путь iff вы имеете дело с массивами не получили в качестве параметров. Массив, отправленный в качестве параметра функции, рассматривается как указатель, поэтому sizeof вернет размер указателя, а не массива.

таким образом, внутри функции этот метод не работает. Вместо этого всегда передавайте дополнительный параметр size_t size указание количества элементов в матрица.


стоит отметить, что 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's sizeof не является функцией; это оператор. Таким образом, он не требует скобок вокруг своего аргумента, если аргумент не является именем типа. Это легко запомнить, так как это делает аргумент похожим на выражение cast, которое также использует скобка.

Итак: если у вас есть следующие:

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) что все используют оценку неправильно. Это, реально, просто чувствительный вопрос, потому что вы не можете иметь выражения, которые приводят к типу "array".

/* 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]);

это действительно не имеет большого отношения к размеру массивов явно. Я только что заметил много ошибки не заметив, как препроцессор работает. Вы всегда обертываете параметр макроса, а не выражение, в котором может быть задействовано.


это верно, мой пример был неудачным. Но это именно то, что должно произойти. Как я уже упоминал ранее p + 1 закончится как тип указателя и аннулирует весь макрос (так же, как если бы вы попытались использовать макрос в функции с параметром указателя).

в конце концов, в этом особенности например, ошибка на самом деле не имеет значения (так что я просто трачу время всех; ура!), потому что у вас нет выражений типа 'массив'. Но на самом деле вопрос о подзаголовках оценки препроцессора, я думаю, является важным.


на многомерные массивы это немного сложнее. Часто люди определяют явных макро-константы, т. е.

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

etc. до бесконечности.


размер массива в 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]))

C "родные" массивы не сохраняют свой размер. Поэтому рекомендуется сохранить длину массива в отдельной переменной/const, и передать его, когда вы передаете массив, то есть:

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

вы всегда должны избегать собственных массивов (если вы не можете, в этом случае, помните о своей ноге). Если вы пишете C++, используйте STLконтейнер's 'vector'. "По сравнению с массивами, они обеспечивают почти такую же производительность", и они гораздо полезнее!

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


@ Magnus: стандарт определяет sizeof как число байтов в объекте, и этот sizeof (char) всегда один. Количество битов в байте зависит от реализации.

Edit: ANSI C++ стандартный раздел 5.3.3 Sizeof:

оператор sizeof дает количество байтов в представлении объекта своего операнда. [...] sizeof (char), sizeof (signed char) и sizeof (unsigned char) равны 1; результат sizeof применяется к любому другому фундаментальный тип определяется реализацией.

раздел 1.6 модель памяти C++:

основной единицей хранения в модели памяти C++ является байт. Байт по крайней мере достаточно велик, чтобы содержать любой член базового набора символов выполнения, и состоит из непрерывной последовательности битов, количество которых определяется реализацией.


@Skizz: я уверен, что я прав, хотя лучший "источник", который я могу дать вам на данный момент, - Википедия, из статьи о sizeof:

Википедия ошибается, Skizz прав. sizeof (char) равен 1 по определению.

Я имею в виду, просто прочитайте запись Википедии очень внимательно чтобы увидеть, что это неправильно. "multiples of char". 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;

реализуйте все необходимые функции, такие как create, destroy, check equality и все остальное, что вам нужно. Его легче передать в качестве параметра.


функции sizeof возвращает количество байтов, которое используется массивом в памяти. Если вы хотите вычислить количество элементов в вашем массиве, вы должны разделить это число на sizeof тип переменной массива. Скажем int array[10];, если переменная типа integer в вашем компьютере, 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 arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70 };
 int len = (int) sizeof(arr) / sizeof(*arr);
 printf("%d\n", len);