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

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

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

Комментарии к вопросу (1)
Решение

Исполнительное резюме:

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 изменился, у вас будет неприятная ошибка, если вы забыли измениться 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);
Комментарии (20)

Путь sizeof - это правильный путь iff , с которым вы имеете дело с массивами, не полученными в качестве параметров. Массив, отправленный в качестве параметра функции, обрабатывается как указатель, поэтому sizeof вернет размер указателя вместо размера массива.

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

Тест:

#include 
#include 

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
Комментарии (21)

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

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

assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
Комментарии (4)

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

Как ясно показывает запись в Википедии, C sizeof < / code > это не функция; это < strong > оператор < / strong >. Таким образом, он не требует скобок вокруг своего аргумента, если только аргумент не является именем типа. Это легко запомнить, поскольку это делает аргумент похожим на выражение, которое также использует скобки.

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

int myArray[10];

Вы можете найти количество элементов с кодом, как это:

size_t n = sizeof myArray / sizeof *myArray;

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

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

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

Например, скажем, у вас есть функция, которая выводит некоторые данные в виде потока байтов, например, по сети. Давайте назовем функцию send () < / code > и возьмем в качестве аргументов указатель на отправляемый объект и количество байтов в объекте. Итак, прототип становится:

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

И тогда вам нужно отправить целое число, чтобы вы кодировали его следующим образом:

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

Теперь вы ввели тонкий способ выстрелить себе в ногу, указав тип foo < / code > в двух местах. Если один изменяется, а другой нет, код ломается. Таким образом, всегда делай так:

send(&foo, sizeof foo);

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

Комментарии (4)
int size = (&arr)[1] - arr;

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

Комментарии (4)

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

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

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

Комментарии (0)

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

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

Комментарии (1)

Макрос ARRAYELEMENTCOUNT (x), который каждый использует, оценивает incorrectly. Это, по сути, просто чувствительный вопрос, потому что у вас не может быть выражений, которые приводят к типу «массив».

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

ARRAYELEMENTCOUNT(p + 1);

Actually оценивается как:

(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 будет в конечном итоге в виде типа указателя и сделает недействительным весь макрос (как если бы вы попытались использовать макрос в функции с параметром указателя).

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

Комментарии (3)

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

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

так далее., до бесконечности.

Комментарии (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
Комментарии (4)
sizeof(array) / sizeof(array[0])
Комментарии (0)

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

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

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

Вы ДОЛЖНЫ всегда избегать нативных массивов (если вы не можете, в этом случае, следите за своей ногой). Если вы пишете C ++, используйте «векторный» контейнер [STL][1]. «По сравнению с массивами они обеспечивают почти одинаковую производительность», и они гораздо полезнее!


// vector is a template, the  means it is a vector of ints
vector 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 
Комментарии (2)
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Комментарии (1)

Если вы действительно хотите сделать это, чтобы обойти ваш массив, я предлагаю реализовать структуру для хранения указателя на тип, который вы хотите, массив и целое число, представляющее размер массива. Тогда вы можете передать это своим функциям. Просто назначьте значение переменной массива (указатель на первый элемент) этому указателю. Затем вы можете перейти на 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 
#include 
/*
#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;
}
Комментарии (1)

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

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

Реализуйте все необходимые функции, такие как создание, уничтожение, проверка равенства и все остальное, что вам нужно. Проще передать в качестве параметра.

Комментарии (1)

Функция sizeof возвращает количество байтов, которое используется вашим массивом в памяти. Если вы хотите рассчитать количество элементов в вашем массиве, вам следует разделить это число с типом переменной sizeof массива. Допустим, int array [10];, если целое число с переменным типом на вашем компьютере составляет 32 бита (или 4 байта), чтобы получить размер вашего массива, вы должны сделать следующее:

int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
Комментарии (0)

Я бы посоветовал никогда не использовать sizeof (даже если его можно использовать), чтобы получить любой из двух разных размеров массива, будь то количество элементов или байты, которые являются последними двумя случаями, которые я показываю здесь. Для каждого из двух размеров приведенные ниже макросы можно использовать, чтобы сделать их более безопасными. Причина в том, чтобы сделать очевидным намерение кода сопровождающим, и на первый взгляд отличить sizeof (ptr) от sizeof (arr)(который написан таким образом не очевиден), так что ошибки тогда очевидны для каждый читает код.



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

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

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

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

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

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

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

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

void foo (ptrdiff_t nmemb, int arr [статический nmemb])
{
        qsort (arr, nmemb, sizeof (arr [0]), cmp) ;
}

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


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


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

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

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

Учитывая, что результат ARRAY_SIZE обычно используется с подписанными переменными типа ptrdiff_t, хорошо определить подписанный вариант этого макроса:

#define ARRAY_SSIZE (arr) ((ptrdiff_t) ARRAY_SIZE (arr))

Массивы с более чем PTRDIFF_MAX собираются давать недопустимые значения для этой подписанной версии макроса, но из чтения C17 :: 6.5.6.9 подобные массивы уже играют с огнем. В этих случаях следует использовать только ARRAY_SIZE и size_t.

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

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

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

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

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

пустота (ptrdiff_t nmemb)
{
        int arr [nmemb] ;

        для (ptrdiff_t i = 0; i < ARRAY_SSIZE (arr); i ++)
                arr [i] = i;
}

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

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

        фгетс (buf, nmemb, stdin) ;
}

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

        для (ptrdiff_t i = 0; i < nmemb; i ++)
                arr [i] = i;
}

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

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

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

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

#define ARRAY_BYTES (arr) (размер ((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, int arr [nmemb])
{

        memset (arr, 0, sizeof (arr [0]) * nmemb) ;
}
Комментарии (8)

Вы можете использовать оператор &. Вот исходный код:

#include
#include
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
Комментарии (4)

Самый простой ответ:

#include 

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;
}
Комментарии (2)
int a[10];
int size = (*(&a+1)-a) ;

Для более подробной информации см [здесь](https://aticleworld.com/how-to-find-size of-array-in-cc-without-using-sizeof/) а также здесь.

Комментарии (2)