array_length в C

Я записал функцию array_length как это:

int array_length(int a[]){
    return sizeof(a)/sizeof(int);
}

Однако это возвращается 2, когда я сделал

unsigned int len = array_length(arr);
printf ("%i" , len);

где я имею

int arr[] = {3,4,5,6,1,7,2};
int * parr = arr;

Но когда я просто делаю

int k = sizeof(arr)/sizeof(int);
printf("%i", k);

в основной функции это возвращается 7.

Что корректный путь состоит в том, чтобы записать функции array_length и как я использую его?

10
задан SuperString 18 January 2010 в 20:44
поделиться

12 ответов

В заголовках, вперед объявить функции-члены:

class Node
{
    Tree * tree_;
    int id_;

public:
    Node(Tree * tree, int id);
    ~Node();
    void hi();
};

В отдельном файле .cpp, который включает в себя все необходимые заголовки, определите их:

#include "Tree.h"
#include "Node.h"

Node::Node(Tree * tree, int id) : tree_(tree), id_(id)
{
  tree_->incCnt();
}

Node::~Node() 
{
  tree_->decCnt();
}

etc

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

-121--3383578-

Можно ли не использовать тела конструктора/деструктора в файле .cxx? Вы можете включить туда Трея.

-121--3383581-

Вычислительные длины массивов в C в лучшем случае проблематичны.

Проблема с вашим кодом выше в том, что когда вы делаете:

int array_length(int a[]){ 
    return sizeof(a)/sizeof(int); 
} 

Вы действительно просто передаете в указателе как "a", так что sizeof (a) является sizeof (int *) . Если вы находитесь в 64-битной системе, вы всегда получите 2 для sizeof (a )/sizeof (int) внутри функции, так как указатель будет равен 64bits.

Вы можете (потенциально) сделать это как макрос вместо функции, но это имеет свои проблемы... (Он полностью вписывает это, так что вы получаете то же поведение, что и ваш int k =... блок, хотя.)

16
ответ дан 3 December 2019 в 13:15
поделиться

Ваша функция не будет работать. C Массивы и указатели C - это разные типы, но массив будет вырожден в указатель, если вы смотрите на него смешно.

В этом случае вы передаваете массив в качестве параметра, и он превращается в указатель в вызове, поэтому вы измеряете SizeOf (int *) / sizeOf (int) .

Единственный способ сделать эту работу состоит в том, чтобы использовать макрос:

#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x))

, и это будет работать только, если x X объявлен в этом объеме в качестве массива, а не как указатель.

12
ответ дан 3 December 2019 в 13:15
поделиться

Используйте макрос ...

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

У него также будет бонус работает на любой массив данных Тип данных :)

9
ответ дан 3 December 2019 в 13:15
поделиться

Простой ответ на Ваш вопрос: невозможно записать функцию array_length . Вы могли бы обойтись без определения макроса, но это зависит от контекста, в котором вы будете использовать макрос.

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

int array_length(int *a){
    return sizeof(a)/sizeof (int);
}

, который, по сути, делит размер int * на размер int. Также, по приведенному выше описанию, в функции невозможно узнать размер массива в Си.

Как правильно определить его размер вне функции? Ответ заключается в том, что оператор sizeof является одним из случаев, когда имя массива сводится к указателю на его первый элемент , а не . Различия более подробно я объяснил в ответе на этот вопрос . Также обратите внимание, что, несмотря на видимость, sizeof - это оператор, а не функция (как мы только что узнали, она не может быть функцией, так как тогда она не сможет вычислить размер массива).

Наконец, чтобы определить размер массива a любого типа T, я предпочитаю:

size_t sz = sizeof a / sizeof a[0];

Вышеуказанное - тип-диагностика: a может быть любого типа, указанного выше. Действительно, вы даже можете изменить тип a и вам не нужно будет менять вышеприведенный тип.

5
ответ дан 3 December 2019 в 13:15
поделиться

Попробуйте _Countof он определен в Winnt.h Как

// Return the number of elements in a statically sized array.
//   DWORD Buffer[100];
//   RTL_NUMBER_OF(Buffer) == 100
// This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc.
//
#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0]))
3
ответ дан 3 December 2019 в 13:15
поделиться

Проблема заключается в том, что параметры функции не могут быть массивами, хотя C позволяет сделать объявление, которое выглядит как один. Параметр заканчивается простым указателем. Я сказал в другом месте :

Это сводится к тому, что параметры простого массива в C / C ++ являются вымысел - они действительно указатели. Параметры массива следует избегать как можно больше - они действительно просто путают вопросы.

Вот почему этот тип конструкции для возврата количества элементов в массиве заканчивается, будучи макросом в C. см. Это предыдущий, поэтому ответьте на то, что я думаю, является хорошим (если она сложной) реализацией макроса:

для простоты ссылки, вот макрос:

#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

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

3
ответ дан 3 December 2019 в 13:15
поделиться

нет возможности определить размер массива, переданного в такую функцию

 void foo(int a[]);

, на момент компиляции или во время выполнения не хватает информации для его разбора

Трюки sizeof работают только в исходных местах, где указан размер массива

.
2
ответ дан 3 December 2019 в 13:15
поделиться

Я думаю, что вы должны использовать указатель на 'a' типа:

class b {
public:
    b() : aInstance(new a(5)) {}
    a *aInstance;
};

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

-121--2934043-

Еще одна вещь, которую следует учитывать, если вы планируете использовать Unicode, это то, что вы должны установить опцию charvocabulary , чтобы сказать, что вы хотите разрешить любой символ в диапазоне Unicode 0 через FFFE

options
{
charVocabulary='\u0000'..'\uFFFE';
}

По умолчанию вы обычно увидите в примерах

options
{
charVocabulary = '\3'..'\377';
}

Чтобы охватить точки, сделанные выше Как правило, если вам нужен как диапазон символов ascii 'A'.. 'Z' , так и диапазон Юникод, вы бы создали правило lexer Юникод, как: '\u0080 '.. '\ufffe'

-121--4746516-

Общая процедура вычисления количества элементов в массиве - sizeof arr/sizeof arr [0] (или sizeof arr/sizeof * arr ). Сказав это...

Запись функции для вычисления длины массива, передаваемого в качестве аргумента, обречена на неудачу, поскольку получаемая функция является указателем, а не массивом. При вызове функции с выражением массива в качестве аргумента тип выражения массива будет неявно преобразован из «array of T» в «pointer to T», а его значение будет установлено как указывающее на первый элемент массива. Функция не видит объект массива; он видит указатель.

В контексте объявления параметра функции, int a [] точно такой же, как int * a , но это только верно для объявлений параметров функции (ничто не сделает меня счастливее, чем увидеть первую форму, исключенную из всех будущих версий C, но этого не произойдет).

2
ответ дан 3 December 2019 в 13:15
поделиться

Int Arr [Что бы ни] Внутренний список аргументов функции определяет указатель , а не массив. Следовательно, информация о длине теряется навсегда.

Почему!?

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

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

2
ответ дан 3 December 2019 в 13:15
поделиться

Ссылка на массиве будет решать это, хотя я никогда не предложу, используя такую ​​вещь (поскольку она будет работать только, если вы всегда будете проходить через ref, или использовать его в объеме, в котором массив Был определен):

#include <iostream>

template <typename Arrtype>
unsigned mysize (Arrtype (&arr)) {
 return sizeof(arr) / sizeof(arr[0]);
}

int main () {
 unsigned arr[13];
 std::cout << mysize(arr) << std::endl; // prints 13
}

также упоминается здесь: http://cplusplus.co.il/2009/09/06/more-on-arrays/

Редактировать: как предложено в комментариях, еще один возможный Решение это:

template <typename T, unsigned N>
unsigned mysize(T (&)[N]) {
    return N;
} 
1
ответ дан 3 December 2019 в 13:15
поделиться

Синтаксис "int a[]", используемый в качестве аргумента функции, эквивалентен "int *a".

Этот синтаксис:

int arr[] = {3,4,5,6,1,7,2};

Работает только во время компиляции.

Итак, пока вы можете писать: int arr[] = {3,4,5,5,6,1,7,2}; printf("size=%d\n", sizeof(arr));

Это будет работать только во время компиляции.

Один из способов обойти это - сделать массивы динамическими и создать свой собственный тип массива.

например,

typedef struct array{
int length;
int *arr;
} array;

И использовать malloc для установки его размера. Вы можете заполнить его с помощью элипсов.

populate_array(array, ...);

например, затем вызвать populate_array(arr, 1,2,3,4,5,6); см. stdarg.

Однако, так как ваш Си-компилятор, скорее всего, тоже является Си++ компилятором. Подумайте об использовании вместо него std::vector. Тогда мы сделаем за Вас тяжелую работу.

1
ответ дан 3 December 2019 в 13:15
поделиться

В целом невозможно измерить размер массива C. В вашей основной функции компилятор подсчитывает элементы, которые вы написали между брекетами для вас, поэтому вы действительно объявляете INT ART [7] Отказ Это имеет размер, который вы ожидаете.

В вашей функции, однако, int a [] эквивалентно int * A - указатель на целое число. Вы знают, что это массив, поэтому существует больше целых чисел, но ваша функция Array_Length может быть пропущена любой целочисленного указателя, поэтому он не может знать.

Это одна из многих причин использования STD :: Vector вместо необработанных массивов, когда это возможно.

5
ответ дан 3 December 2019 в 13:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: