Рассчитать длину массива в C с помощью функции - PullRequest
11 голосов
/ 12 ноября 2010

Я хочу создать ФУНКЦИЮ, которая вычисляет размер переданного массива.

Я передам массив в качестве входных данных и он должен вернуть его длину.Я хочу функцию

int ArraySize(int * Array   /* Or int Array[] */)
{
   /* Calculate Length of Array and Return it */

}

void main()
{
  int MyArray[8]={1,2,3,0,5};
  int length;

  length=ArraySize(MyArray);

  printf("Size of Array: %d",length);

}

Длина должна быть 5, поскольку она содержит 5 элементов, хотя ее размер равен 8 (даже 8 подойдет, но 5 будет отлично)

Я пробовал это:

int ArraySize(int * Array)
{

  return (sizeof(Array)/sizeof(int));

}

Это не будет работать, поскольку "sizeof(Array)" перенастроит размер Int Pointer.Эта вещь "sizeof" работает, только если вы находитесь в той же функции.

На самом деле я вернулся к C после многих дней из C #, поэтому я не могу вспомнить (и пропал Array.Length())

Привет!

Ответы [ 9 ]

27 голосов
/ 12 ноября 2010

Вы не можете вычислить размер массива, когда у вас есть только указатель.

Единственный способ сделать это "подобным функции" - это определить макрос:

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

Это, конечно, со всеми обычными оговорками макросов.

Редактировать: (комментарии ниже действительно относятся к ответу ...)

  1. Вы не можете определить количество элементов , инициализированных в массиве, если только вы сначала не инициализируете все элементы с «недопустимым» значением и не выполните подсчет «допустимых» значений вручную. Если ваш массив определен как имеющий 8 элементов, то для компилятора он имеет 8 элементов, независимо от того, инициализированы ли вы только 5 из них.
  2. Вы не можете определить размер массива внутри функции, которой этот массив был передан в качестве параметра. Не напрямую, не через макрос, ни в коем случае. Вы можете только определить размер массива в области, которая была объявлена ​​в .

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

В области действия объявлен массив, у компилятора есть информация о том, что он на самом деле является массивом, и сколько у него элементов.

В функции, в которую передается массив, компилятор видит только указатель. (Учтите, что функция может вызываться со многими различными массивами, и помните, что sizeof() является оператором времени компиляции .

Вы можете переключиться на C ++ и использовать <vector>. Вы можете определить struct vector плюс функции, обрабатывающие это, но это не совсем удобно:

#include <stdlib.h>

typedef struct
{
    int *  _data;
    size_t _size;
} int_vector;

int_vector * create_int_vector( size_t size )
{
    int_vector * _vec = malloc( sizeof( int_vector ) );
    if ( _vec != NULL )
    {
        _vec._size = size;
        _vec._data = (int *)malloc( size * sizeof( int ) );
    }
    return _vec;
}

void destroy_int_vector( int_vector * _vec )
{
    free( _vec->_data );
    free( _vec );
}

int main()
{
    int_vector * myVector = create_int_vector( 8 );
    if ( myVector != NULL && myVector->_data != NULL )
    {
        myVector->_data[0] = ...;
        destroy_int_vector( myVector );
    }
    else if ( myVector != NULL )
    {
        free( myVector );
    }
    return 0;
}

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

11 голосов
/ 12 ноября 2010

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

Вам нужно либо:

  • если возможно, используйте значение Sentinel, например, NULL для указателей или -1 для положительных чисел.
  • вычислите его, когда он все еще является массивом, и передайте этот размер любым функциям.
  • как указано выше, ноиспользуя фанки макросов, что-то вроде:
    #define arrSz(a) (sizeof(a)/sizeof(*a)).
  • создайте свой собственный абстрактный тип данных, который поддерживает длину как элемент в структуре, так что вы можете иметь способполучить свой Array.length().
2 голосов
/ 12 ноября 2010

То, что вы просите, просто не может быть сделано.

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

1 голос
/ 26 октября 2012
int getArraySize(void *x)
{
    char *p = (char *)x;
    char i = 0;
    char dynamic_char = 0xfd;
    char static_char = 0xcc;

    while(1)
    {
        if(p[i]==dynamic_char || p[i]==static_char)
            break;
        i++;
    }
    return i;
}

int _tmain(int argc, _TCHAR* argv[])
{   
    void *ptr = NULL;
    int array[]={1,2,3,4,5,6,7,8,9,0};
    char *str;
    int totalBytes;

    ptr = (char *)malloc(sizeof(int)*3);
    str = (char *)malloc(10);

    totalBytes = getArraySize(ptr);
    printf("ptr = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(int)));

    totalBytes = getArraySize(array);
    printf("array = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(int)));

    totalBytes = getArraySize(str);
    printf("str = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(char)));
    return 0;
}
1 голос
/ 12 ноября 2010

Вам нужно либо передать длину в качестве дополнительного параметра (как strncpy делает), либо завершить нулем массив (как strcpy делает).

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

1 голос
/ 12 ноября 2010

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

Однако в C ++ вы можете использовать Удержание аргумента шаблона для достижения того же.

0 голосов
/ 19 января 2019

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

0 голосов
/ 26 марта 2017

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

проверка '\ 0' здесь не сработает

Сначала поместите любой символ в массив во время инициализации

for(i=0;i<1000;i++)
array[i]='x';

затем после передачи значений проверьте 'x'

i=0;
while(array[i]!='x')
{
i++;
return i;
}

Дайте мне знать, если это будет полезно.

0 голосов
/ 16 декабря 2015

Размер массива в C:

int a[]={10,2,22,31,1,2,44,21,5,8};

printf("Size : %d",sizeof(a)/sizeof(int));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...