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

c arrays memory

1685779 просмотра

20 ответа

180817 Репутация автора

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

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

Автор: Mark Harrison Источник Размещён: 01.09.2008 06:49

Ответы (20)


1087 плюса

180817 Репутация автора

Решение

Управляющее резюме:

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

Полный ответ:

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

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

На моем компьютере длина целых 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);
Автор: Mark Harrison Размещён: 01.09.2008 06:49

12 плюса

7088 Репутация автора

sizeof(array) / sizeof(array[0])
Автор: Ted Percival Размещён: 01.09.2008 06:50

122 плюса

17111 Репутация автора

Стоит отметить, что sizeofэто не помогает при работе со значением массива, которое распалось на указатель: даже если оно указывает на начало массива, для компилятора оно совпадает с указателем на отдельный элемент этого массива. , Указатель не «запоминает» что-либо еще о массиве, который использовался для его инициализации.

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

assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
Автор: Magnus Hoff Размещён: 01.09.2008 06:55

46 плюса

331511 Репутация автора

Размер «трюка» - лучший способ, который я знаю, с одним небольшим, но (для меня это главная любимая мозоль) важным изменением в использовании скобок.

Как ясно видно из статьи в Википедии, С 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);

Теперь вы защищены. Конечно, вы дублируете имя переменной, но вероятность того, что компилятор может обнаружить ее, если вы ее измените, высока.

Автор: unwind Размещён: 15.10.2008 10:11

14 плюса

4683 Репутация автора

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

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

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

Автор: Andreas Spindler Размещён: 17.08.2011 01:21

9 плюса

1777 Репутация автора

«Вы ввели тонкий способ выстрелить себе в ногу»

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

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

Вы ДОЛЖНЫ всегда избегать нативных массивов (если вы не можете, в этом случае, следите за своей ногой). Если вы пишете на C ++, используйте контейнер STL '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/

Автор: Ohad Размещён: 14.11.2011 10:45

727 плюса

8076 Репутация автора

Это 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]) ));
}

Вывод (в 64-битной ОС Linux):

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

Вывод (в 32-битной ОС Windows):

sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
Автор: Elideb Размещён: 27.04.2012 11:14

1 плюс

1461 Репутация автора

You can use the & operator. Here is the source code:

#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;
};

Here is the sample output

1549216672
1549216712
---- diff----
4
The size of array a is 10
Автор: Shih-En Chou Размещён: 03.05.2013 08:44

4 плюса

170 Репутация автора

Если вы действительно хотите сделать это для обхода вашего массива, я предлагаю реализовать структуру для хранения указателя на тип, для которого вы хотите массив, и целого числа, представляющего размер массива. Затем вы можете передать это своим функциям. Просто назначьте этому указателю значение переменной массива (указатель на первый элемент). Затем вы можете перейти 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;
}
Автор: Joel Dentici Размещён: 13.06.2013 02:10

37 плюса

7457 Репутация автора

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

Проверьте эту ссылку для объяснения

Автор: Arjun Sreedharan Размещён: 07.12.2013 10:43

21 плюса

1726 Репутация автора

Если вы знаете тип данных массива, вы можете использовать что-то вроде:

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(имя массива) является указателем.

Автор: Abhitesh khatri Размещён: 18.01.2014 07:30

17 плюса

0 Репутация автора

Макрос, 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]);

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


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

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

Автор: user2379628 Размещён: 28.02.2014 01:49

13 плюса

1509 Репутация автора

Размер массива в 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
Автор: Yogeesh H T Размещён: 20.11.2015 06:51

3 плюса

72 Репутация автора

Лучше всего сохранить эту информацию, например, в структуре:

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

Implement all necessary functions such as create, destroy, check equality, and everything else you need. It is easier to pass as a parameter.

Автор: Paulo Pinheiro Размещён: 17.02.2016 02:35

10 плюса

691 Репутация автора

#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Автор: Andy Nugent Размещён: 12.09.2016 02:54

25 плюса

519 Репутация автора

Вы можете использовать оператор sizeof, но он не будет работать для функций, потому что он будет использовать ссылку на указатель. Чтобы найти длину массива, выполните следующие действия:

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

Код, изначально найденный здесь: C программа для поиска количества элементов в массиве

Автор: Mohd Shibli Размещён: 27.05.2017 12:56

0 плюса

444 Репутация автора

int a[10];
int size = (*(&a+1)-a) ;

For more details see here and also here.

Автор: Pygirl Размещён: 18.07.2018 01:28

3 плюса

323 Репутация автора

The function sizeof returns the number of bytes which is used by your array in the memory. If you want to calculate the number of elements in your array, you should divide that number with the sizeof variable type of the array. Let's say int array[10];, if variable type integer in your computer is 32 bit (or 4 bytes), in order to get the size of your array, you should do the following:

int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
Автор: Keivan Размещён: 20.08.2018 09:20

0 плюса

24 Репутация автора

The simplest Answer:

#include <stdio.h>

int main(void) {

    int a[] = {2,3,4,5,4,5,6,78,9,91,435,4,5,76,7,34};//for Example only
    int size;

    size = sizeof(a)/sizeof(a[0]);//Method

    printf ("size = %d",size);
    return 0;
}
Автор: Jency Размещён: 08.08.2019 08:54

0 плюса

1334 Репутация автора

В этой теме были обнаружены важные ошибки: https://lkml.org/lkml/2015/9/3/428.

Я не согласен с решением, которое предлагает Линус, которое никогда не использует нотацию массива для параметров функций.

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

Из массива у нас есть три размера, которые мы могли бы знать:

  • Размер типа элементов массива
  • Количество элементов массива
  • Размер в байтах, который массив использует в памяти

Размер типа элементов массива

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

Пример использования:

void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
        qsort(arr, nmemb, sizeof(arr[0]), cmp);
}

qsort() нужно это значение в качестве третьего аргумента.


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


Количество элементов в массиве

Этот является наиболее распространенным, и многие ответы предоставили вам типичный макрос ARRAY_SIZE:

#define ARRAY_SIZE(arr)     (sizeof(arr) / sizeof((arr)[0]))

Последние версии компиляторов, такие как GCC 8, будут предупреждать вас, когда вы применяете этот макрос к указателю, поэтому он безопасен (есть другие способы сделать его более безопасным со старыми компиляторами).

Он работает путем деления размера в байтах всего массива на размер каждого элемента.

Примеры использования:

void foo(ptrdiff_t nmemb)
{
        char buf[nmemb];

        fgets(buf, ARRAY_SIZE(arr), stdin);
}

void bar(ptrdiff_t nmemb)
{
        int arr[nmemb];

        for (ptrdiff_t i = 0; i < ARRAY_SIZE(arr); i++)
                arr[i] = i;
}

Если бы эти функции не использовали массивы, а вместо этого получили их в качестве параметров, прежний код не скомпилировался бы, поэтому было бы невозможно иметь ошибку (учитывая, что используется последняя версия компилятора или что используется какой-то другой прием) и нам нужно заменить вызов макроса значением:

void foo(ptrdiff_t nmemb, char buf[nmemb])
{

        fgets(buf, nmemb, stdin);
}

void bar(ptrdiff_t nmemb, char arr[nmemb])
{

        for (ptrdiff_t i = 0; i < nmemb; i++)
                arr[i] = i;
}

Размер в байтах, который массив использует в памяти

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

Обычный способ получить это значение (НИКОГДА его не использовать!) - использовать sizeof(arr). Проблема: та же, что и с предыдущей; если у вас есть указатель вместо массива, ваша программа сойдет с ума.

Решение проблемы включает использование того же макроса, что и раньше, который, как мы знаем, безопасен (он нарушает компиляцию, если он применяется к указателю):

#define ARRAY_BYTES(arr)        (sizeof((arr)[0]) * ARRAY_SIZE(arr))

Как это работает, очень просто: оно отменяет деление, которое ARRAY_SIZEпроисходит, поэтому после математических отмен вы получите только один sizeof(arr), но с дополнительной безопасностью ARRAY_SIZEконструкции.

Пример использования:

void foo(ptrdiff_t nmemb)
{
        int arr[nmemb];

        memset(arr, 0, ARRAY_BYTES(arr));
}

memset() нужно это значение в качестве третьего аргумента.

Как и раньше, если массив получен как параметр (указатель), он не будет компилироваться, и нам придется заменить вызов макроса значением:

void foo(ptrdiff_t nmemb, char buf[nmemb])
{
        int arr[nmemb];

        memset(arr, 0, nmemb);
}


Следует сделать вывод, что НИКОГДА не использовать, sizeofчтобы получить любой из двух разных размеров массива, либо в элементах, либо в байтах, что является последними двумя случаями, которые я здесь показал. Для каждого из двух размеров ВСЕГДА используйте соответствующие безопасные макросы.

Автор: Cacahuete Frito Размещён: 17.08.2019 03:13
32x32