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

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

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

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

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

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

Ответ 5

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

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

Ответ 6

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

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

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

#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 и С++. Для массивов с более чем двумя измерениями используйте

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

и т.д., ad infinitum.

Ответ 10

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

Ответ 11

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

Ответ 12

"вы ввели тонкий способ стрелять себе в ногу"

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

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

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

Ответ 13

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

Ответ 14

@Магнус: стандарт определяет sizeof как уступающий количеству байтов в объекте, а sizeof (char) всегда один. Количество бит в байте является специфичным для реализации.

Изменить: стандартный раздел ANSI С++. 5.3.3. Размер:

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

Раздел 1.6 Модель памяти С++:

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

Ответ 15

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

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

Я имею в виду, просто внимательно прочитайте запись в Википедии, чтобы понять, что это неправильно. msgstr "кратные char". sizeof(char) никогда не может быть ничего, кроме "1". Если бы это было, скажем, 2, это означало бы, что sizeof(char) был в два раза меньше char!

Ответ 16

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

Ответ 17

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

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

Внедрите все необходимые функции, такие как создание, уничтожение, проверка равенства и все остальное, что вам нужно. Это легче передать в качестве параметра.

Ответ 18

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

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

Ответ 19

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

#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

Ответ 20

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

Для более подробной информации смотрите здесь, а также здесь.

Ответ 21

пример

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

Ответ 22

Много полезных ответов. Я обычно использую sizeof (массив)/sizeof (массив [0]).

Ответ 23

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

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

Ответ 24

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



В этой теме были обнаружены важные ошибки: 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]))

Учитывая, что результат 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);
}

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

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

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

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

        fgets(buf, nmemb, stdin);
}

void bar(ptrdiff_t nmemb, int 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, int arr[nmemb])
{

        memset(arr, 0, sizeof(arr[0]) * nmemb);
}

Ответ 25

sizeof() не должен использоваться для получения количества элементов во всех случаях. Отдельный параметр для размера (или длины) массива, т.е. size_t следует передать функции.

#include<stdio.h>
void fun(int arr[], size_t arr_size)  
{
 int i;   
 for (i = 0; i < arr_size; i++) 
 {  
  arr[i] = i;  
  }
 }

 int main()
 {
  int i;  
  int arr[4] = {0, 0 ,0, 0};
  fun(arr, 4);
  for(i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
   printf(" %d ", arr[i]);
   getchar();  
   return 0;
  }    

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

 #include<stdio.h>
 void fun(int arr[])  
  {
   int i; //sizeof should not be used here to get number of element of array
   int arr_size = sizeof(arr)/sizeof(arr[0]); //incorrect use of sizeof
   for (i = 0; i < arr_size; i++) 
   {  
     arr[i] = i;  /*executed only once */
    } 
    }
    int main()
    {
     int i;  
     int arr[4] = {0, 0 ,0, 0};
      fun(arr);
      for(i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) //sizeof is fine here
     printf(" %d " ,arr[i]);
     getchar();  
     return 0; 
    }    

Ответ 26

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

Ответ 27

Использование:

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

Вывод:

5

Причина: вычисляет количество элементов, хранящихся в массиве, а не количество свободных пространств, выделенных ему.