2008-09-01 2 views

ответ

859

Резюме:

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

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

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

На моем компьютере, Интс имеют длину 4 байта, так n is 68.

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

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

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

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

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

Другим преимуществом является то, что теперь вы можете легко параметризировать имя массива в макрос и получите:

#define NELEMS(x) (sizeof(x)/sizeof((x)[0])) 

int a[17]; 
int n = NELEMS(a); 
+0

Но не `sizeof (int)` более результативно, чем `sizeof (* int_arr) `во время выполнения? Или переведенный код идентичен? – Pacerier 2013-09-21 05:43:10

+5

Сгенерированный код будет идентичным, поскольку компилятор знает тип * int_arr во время компиляции (и, следовательно, значение sizeof (* int_arr)). Он будет постоянным, и компилятор может соответствующим образом оптимизировать. – 2013-09-21 19:58:10

+0

Какой компилятор вы используете? – Pacerier 2013-09-22 05:01:08

98

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

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

assert(sizeof(a)/sizeof(a[0]) == 10); 
assert(sizeof(p) == sizeof(int*)); 
assert(sizeof(*p) == sizeof(int)); 
+1

Я помню, что у CRAY был C с `char` из 32 бит. Весь стандарт говорит о том, что целочисленные значения от 0 до 127 могут быть представлены, а его диапазон составляет как минимум от -127 до 127 (char подписан) или от 0 до 255 (char беззнаковый). – vonbrand 2013-02-01 20:57:58

4

@ Magnus: Стандарт определяет SizeOf как они дают число байтов в объекте, и что SizeOf (Char) всегда один. Количество бит в байте является специфичным для реализации.

Редактировать: ANSI C++ стандартный раздел 5.3.3 Sizeof:

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

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

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

+3

Есть ли ссылки C вместо ссылок на C++? – Pacerier 2013-09-21 06:59:13

3

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

Википедия неправильно , Скизз прав. sizeof (char) равен 1, по определению.

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

+0

... да, и мы обеспечиваем `assert (sizeof (char) 2012-01-26 09:02:45

34

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

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

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

+0

Btw, они идентичные инструкции на уровне процессора? Требует ли `sizeof (int)` меньше инструкций, чем `sizeof (foo)`? – Pacerier 2013-09-21 06:53:51

+0

@ Pacerier: нет, они идентичны. Подумайте о `int x = 1 + 1;` против `int x = (1 + 1);`. Здесь круглые скобки чисто абсолютно эстетичны. – quetzalcoatl 2013-10-05 13:22:54

13

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

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

и т.п., ad infinitum.

7

«вы ввели тонкий способ съемки себя в ногу»

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

#define MY_ARRAY_LENGTH 15 
int myArray[MY_ARRAY_LENGTH]; 

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

+0

Я читал, что правильный способ объявления целочисленных констант в C состоит в использовании декларации enum. – 2013-08-03 23:08:30

+12

Вопрос не в C++ ..... – Pacerier 2013-09-21 06:56:56

578

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 
+1

Из любопытства компилятор обрабатывает массивы так же, как указатели, когда они параметризуются? – lukecampbell 2013-06-24 17:46:24

+8

Почему `length of parameter: 2`, если передан только указатель на 1-й элемент массива? – Bbvarghe 2013-08-05 02:42:00

+9

@Bbvarghe Это потому, что указатели в 64-битных системах - 8 байтов (sizeof (intArray)), но ints по-прежнему (обычно) 4 байта (sizeof (intArray [0])). – Elideb 2013-08-28 17:33:20

1

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

#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 
3

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

Заканчивать this link для объяснения

18

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

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

14

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

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


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

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

-17

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

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

Выход:

5 

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

11

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

Самый лучший способ сохранения этой информации, например, в структуре:

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

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

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

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

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

код первоначально здесь: C program to find the number of elements in an array

-2

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