Как определить размер моего массива в C?
То есть количество элементов, которое может содержать массив?
Как определить размер моего массива в C?
То есть количество элементов, которое может содержать массив?
Ответы:
Управляющее резюме:
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])
или эквивалентен sizeof(*a)
размер первого элемента массива.
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);
ARRAYSIZE
определенный макрос WinNT.h
(который добавляется другими заголовками). Таким образом, пользователям WinAPI не нужно определять свои собственные макро.
static int a[20];
. Но ваш комментарий полезен для читателей, которые могут не осознавать разницу между массивом и указателем.
Это 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
length of parameter:2
если передается только указатель на первый элемент массива?
(sizeof array / sizeof *array)
.
Стоит отметить, что sizeof
это не помогает при работе со значением массива, который распался на указатель: даже если он указывает на начало массива, для компилятора он такой же, как указатель на один элемент этого массива , Указатель не «запоминает» что-либо еще о массиве, который использовался для его инициализации.
int a[10];
int* p = a;
assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
char
32 битами. Все, что говорится в стандарте, заключается в том, что могут быть представлены целочисленные значения от 0 до 127, а его диапазон составляет по крайней мере от -127 до 127 (символ подписан) или от 0 до 255 (символ без знака).
Размер «трюка» - лучший способ, который я знаю, с одним небольшим, но (для меня это главная любимая мозоль) важным изменением в использовании скобок.
Как ясно видно из статьи в Википедии, С 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);
Теперь вы защищены. Конечно, вы дублируете имя переменной, но вероятность того, что компилятор может обнаружить ее, если вы ее измените, высока.
sizeof(int)
меньших инструкций, чем sizeof(foo)
?
int x = 1+1;
против int x = (1+1);
. Здесь круглые скобки сугубо просто эстетичны.
sizeof
всегда будет постоянным в C ++ и C89. С массивами переменной длины C99 это может быть оценено во время выполнения.
sizeof
может быть оператором, но это следует рассматривать как функцию в соответствии с Линусом Торвальдсом. Согласен. Прочитайте его рациональное здесь: lkml.org/lkml/2012/7/11/103
int size = (&arr)[1] - arr;
Проверьте эту ссылку для объяснения
ptrdiff_t
. (Обычно в 64-битной системе это будет больший тип, чем int
). Даже если вы измените int
на ptrdiff_t
в этом коде, он все равно имеет ошибку, если arr
занимает более половины адресного пространства.
/3G
возможностью разделения пользователя / ядра 3G / 1G, что позволяет иметь размер массивов до 75% от размера адресного пространства.
foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];
качестве глобальных переменных. buf3[]
декларация терпит неудачу, поскольку (&buf1)[1] - buf1
не является константой.
Вы можете использовать оператор 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
(имя массива) является указателем.
int noofele = sizeof(arr)/sizeof(int);
только наполовину лучше, чем кодирование int noofele = 9;
. Использование sizeof(arr)
поддерживает гибкость при изменении размера массива. Все же sizeof(int)
нуждается в обновлении, если тип arr[]
изменения. Лучше использовать, sizeof(arr)/sizeof(arr[0])
даже если тип хорошо известен. Непонятно, почему используется int
для noofele
против size_t
, тип, возвращаемый sizeof()
.
Макрос, 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
, в конечном итоге это будет указатель типа и сделает недействительным весь макрос (как если бы вы пытались использовать макрос в функции с параметром указателя).
В конце дня, в данном конкретном случае, ошибка на самом деле не имеет значения (так что я просто трачу время каждого; хазз!), Потому что у вас нет выражений с типом «массив». Но на самом деле вопрос о тонкостях оценки препроцессора, я думаю, является важным.
(sizeof (x) / sizeof (*x))
?
Для многомерных массивов это немного сложнее. Часто люди определяют явные макроконстанты, т.е.
#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])
и т.д. до бесконечности.
sizeof(array) / sizeof(array[0])
array
имеет, вам не нужно использовать , sizeof(array) / sizeof(array[0])
если array
это массив либо char
, unsigned char
или signed char
- Цитата из C18,6.5.3.4 / 4: «Когда SizeOf применяются к операнду , который имеет тип CHAR, беззнаковый символ или символ подписанный , (или его квалифицированная версия) результат равен 1 ». В этом случае вы можете просто сделать, sizeof(array)
как описано в моем ответе .
Размер массива в 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
size_t size_of_element
еще int
с int n = sizeof (a) / sizeof (a[0]);
и неsize_t n = sizeof (a) / sizeof (a[0]);
char a[INT_MAX + 1u];
, int n
как он используется в int n = sizeof (a) / sizeof (a[0]);
недостаточном (это УБ). Использование size_t n = sizeof (a) / sizeof (a[0]);
не влечет за собой этой проблемы.
Я бы посоветовал никогда не использовать sizeof
(даже если это можно использовать) для получения любого из двух разных размеров массива, либо по количеству элементов, либо в байтах, которые являются двумя последними случаями, которые я здесь показываю. Для каждого из двух размеров макросы, показанные ниже, могут быть использованы для повышения безопасности. Причина заключается в том, чтобы сделать понятным намерение кода для сопровождающих, и отличие sizeof(ptr)
от sizeof(arr)
на первый взгляд (которое написано таким образом не очевидно), чтобы ошибки были очевидны для всех, кто читает код.
TL; DR:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
must_be_array(arr)
(определено ниже) IS необходим, так как -Wsizeof-pointer-div
глючит (по состоянию на апрель / 2020):
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a) ( \
0 * (int)sizeof( \
struct { \
Static_assert_array(a); \
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
В этой теме были обнаружены важные ошибки: 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);
}
-Wsizeof-pointer-div
глючит :Сегодня я узнал, что новое предупреждение в GCC работает, только если макрос определен в заголовке, который не является системным заголовком. Если вы определяете макрос в заголовке, который установлен в вашей системе (обычно /usr/local/include/
или /usr/include/
) ( #include <foo.h>
), компилятор НЕ выдаст предупреждение (я попробовал GCC 9.3.0).
Итак, мы #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
хотим и хотим сделать это безопасным. Нам понадобится C11 _Static_assert()
и некоторые расширения GCC: операторы и объявления в выражениях , __builtin_types_compatible_p :
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
sizeof(arr) / sizeof((arr)[0]); \
} \
)
Теперь ARRAY_SIZE()
это абсолютно безопасно, и, следовательно, все его производные будут в безопасности.
__arraycount()
:Libbsd предоставляет макрос __arraycount()
in <sys/cdefs.h>
, что небезопасно, поскольку в нем отсутствует пара круглых скобок, но мы можем сами добавить эти скобки, и поэтому нам даже не нужно записывать деление в нашем заголовке (зачем дублировать уже существующий код? ). Этот макрос определен в системном заголовке, поэтому, если мы его используем, мы вынуждены использовать макросы выше.
#include <sys/cdefs.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
__arraycount((arr)); \
} \
)
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
Некоторые системы обеспечивают nitems()
в <sys/param.h>
вместо этого, и в некоторых системах обоих. Вы должны проверить свою систему и использовать ту, которая у вас есть, и, возможно, использовать некоторые условные выражения препроцессора для переносимости и поддержки обоих.
К сожалению, ({})
расширение gcc не может быть использовано на уровне файла. Чтобы иметь возможность использовать макрос в области видимости файла, статическое утверждение должно быть внутри sizeof(struct {})
. Затем умножьте его на, 0
чтобы не повлиять на результат. Приведение к (int)
может быть полезно для имитации возвращаемой функции (int)0
(в этом случае это не обязательно, но затем ее можно использовать для других целей).
#include <sys/cdefs.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a) ( \
0 * (int)sizeof( \
struct { \
Static_assert_array(a); \
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
#define ARRAY_SIZE(arr) (__arraycount((arr)) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
sizeof(arr)
), не отображаются в другом месте: ARRAY_BYTES(arr)
.
sizeof
, а использовать вместо этого эти конструкции; если вам хочется писать эти конструкции каждый раз, вы, скорее всего, совершите ошибку (очень часто, если вы копируете вставить, и также очень часто, если вы пишете их каждый раз, потому что у них много скобок) ...
sizeof
явно небезопасно (причины в ответе), и не использование макросов, а использование предоставленных мною конструкций, каждый раз, еще более небезопасно, поэтому единственный путь это макросы.
«Вы ввели тонкий способ выстрелить себе в ногу»
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();
enum
объявление.
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Если вы действительно хотите сделать это, чтобы обойти массив, я предлагаю реализовать структуру для хранения указателя на тип, для которого вы хотите массив, и целого числа, представляющего размер массива. Затем вы можете передать это своим функциям. Просто назначьте этому указателю значение переменной массива (указатель на первый элемент). Затем вы можете перейти 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;
}
strcpy(d.name, name);
без обработки переполнения.
Лучше всего сохранить эту информацию, например, в структуре:
typedef struct {
int *array;
int elements;
} list_s;
Реализуйте все необходимые функции, такие как создание, уничтожение, проверка равенства и все остальное, что вам нужно. Проще передать в качестве параметра.
int elements
против size_t elements
?
Функция 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
ptrdiff_t
. sizeof()
результаты в size_t
. С не определяет, кто шире или выше / того же ранга. Таким образом, тип фактора ((char *)(&a+1)-(char *)a)/(sizeof(a[0]))
не обязательно size_t
и, следовательно, печать с z
может привести к UB. Простого использования printf("The size of array a is %zu\n", sizeof a/sizeof a[0]);
достаточно.
(char *)(&a+1)-(char *)a
не является константой и может быть рассчитана во время выполнения, даже с фиксированным размером a[10]
. sizeof(a)/sizeof(a[0])
в этом случае выполняется постоянно во время компиляции.
Более элегантное решение будет
size_t size = sizeof(a) / sizeof(*a);
Помимо уже предоставленных ответов, я хочу указать на особый случай с использованием
sizeof(a) / sizeof (a[0])
Если a
это либо массив char
, unsigned char
либо signed char
вам не нужно использовать sizeof
дважды, так как sizeof
выражение с одним операндом этих типов всегда приводит к 1
.
Цитата из C18,6.5.3.4 / 4:
« Когда
sizeof
применяется к операнду, который имеет типchar
,unsigned char
илиsigned char
(или его квалифицированную версию), результат будет1
».
Таким образом, sizeof(a) / sizeof (a[0])
было бы эквивалентно, NUMBER OF ARRAY ELEMENTS / 1
если a
это массив типа char
, unsigned char
или signed char
. Деление на 1 является излишним.
В этом случае вы можете просто сократить и сделать:
sizeof(a)
Например:
char a[10];
size_t length = sizeof(a);
Если вы хотите доказательства, вот ссылка на GodBolt .
Тем не менее, подразделение поддерживает безопасность, если тип значительно изменяется (хотя эти случаи редки).
Примечание: это может дать вам неопределенное поведение, как указано ММ в комментарии.
int a[10];
int size = (*(&a+1)-a) ;
Для более подробной информации смотрите здесь, а также здесь .
*
оператор не может быть применен к пришедшим к конечному указателю
*(&a+1) - a;
, отличается от (&a)[1] - a;
выше, не так *(&a+1)
и (&a)[1]
считаются 1 в конце прошлого?
x[y]
определяется как*(x + (y))