Поиск длины массива внутри функции

В программе ниже длина массива ar правильна в основном, но в temp она показывает длину указателя на ar который на моем компьютере равен 2 (в единицах sizeof(int)).

#include <stdio.h>

void temp(int ar[]) // this could also be declared as 'int *ar'
{
    printf("%d\n", (int) sizeof(ar)/sizeof(int));
}

int main(void)
{
    int ar[]={1,2,3};
    printf("%d\n", (int) sizeof(ar)/sizeof(int));
    temp(ar);
    return 0;
}

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

Ответ 1

Нет встроенного способа определения длины внутри функции. Однако вы проходите arr, sizeof(arr) всегда будет возвращать размер указателя. Поэтому лучший способ - передать количество элементов в качестве отдельного аргумента. В качестве альтернативы вы можете иметь специальное значение, например 0 или -1 которое указывает конец (например, это \0 в строках, которые являются только char []). Но тогда, конечно, размер "логического" массива был sizeof(arr)/sizeof(int) - 1

Ответ 2

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

#include <stdio.h>

void temp(int *ar)
{
    printf("%d\n", ar[-1]);
}

int main(void)
{
    int ar[]= {0, 1, 2, 3};
    ar[0] = sizeof(ar) / sizeof(ar[0]) - 1;
    printf("%d\n", ar[0]);
    temp(ar + 1);
    return 0;
}

Ответ 3

Не используйте функцию, используйте макрос для этого:

//Adapted from K&R, p.135 of edition 2.
#define arrayLength(array) (sizeof((array))/sizeof((array)[0]))

int main(void)
{
    int ar[]={1,2,3};
    printf("%d\n", arrayLength(ar));
    return 0;
}

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

Альтернативой, если вы хотите передать один тип данных, является определение типа, имеющего как массив, так и емкость:

typedef struct
{
  int *values;
  int capacity;
} intArray;

void temp(intArray array)
{
  printf("%d\n", array.capacity);
}

int main(void)
{
    int ar[]= {1, 2, 3};
    intArray arr;
    arr.values = ar;
    arr.capacity = arrayLength(ar);
    temp(arr);
    return 0;
}

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

Ответ 4

Когда вы пишете size(ar) вы передаете указатель, а не массив.

Размер указателя и int равен 4 или 8 - в зависимости от ABI (или, как упоминалось в @H2CO3, что-то совершенно другое), поэтому вы получаете sizeof(int *)/sizeof int (sizeof(int *)/sizeof int= 1 для 32 -битные машины и 8/4 = 2 для 64-битных машин), который составляет 1 или 2 (или.. что-то другое).

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

Ответ 5

Я не думаю, что вы могли бы сделать это, используя функцию. Он всегда будет возвращать длину указателя, а не длину всего массива.

Ответ 6

Внутри функции ar есть указатель, поэтому оператор sizeof возвращает длину указателя. Единственный способ вычислить его - сделать глобальным или изменить его имя. Самый простой способ определить длину - это размер (array_name)/(size_of (int)). Другое, что вы можете сделать, это передать это вычисление в функцию.

Ответ 7

Вам нужно преобразовать массив в структуру:

#include<stdio.h>

struct foo {int arr[5];};
struct bar {double arr[10];};

void temp(struct foo f, struct bar g)
{
    printf("%d\n",(sizeof f.arr)/(sizeof f.arr[0]));
    printf("%d\n",(sizeof g.arr)/(sizeof g.arr[0]));
}

void main(void)
{
    struct foo tmp1 = {{1,2,3,4,5}};
    struct bar tmp2;
    temp(tmp1,tmp2);

    return;
}

Ответ 8

10 марта 2018 г. Редакция:

Код OP вызывает temp() и передает указатель на данные типа int через имя массива, которое по умолчанию относится к arr [0]. Формальный аргумент temp() указывает указатель на данные типа int с обозначением массива, указывающий, что указатель относится к элементу в массиве.

На geeksforgeeks:

Параметры массива [рассматриваются] как указатели из-за эффективности.

Другая статья в geeksforgeeks объясняет, что использование sizeof с указателем означает количество байтов, необходимых для типа данных, а не длину массива. В статье рекомендуется передать дополнительный параметр: фактический размер массива. В этом ключе я создал константу с помощью жесткого кодирования этого значения, как показано в следующем примере:

    #define ARR_SIZE 3

    #include <stdio.h>

    void temp(int arr[], size_t arr_size)
    {
        int i;
        puts ("In temp:");
        for (i = 0; i <= arr_size - 1; i++) 
        {  
            printf(" %d",arr[i]);
        }
        puts("\nExiting temp...\n");
    }


    int main(void)
    {

        int ar[ARR_SIZE]={1,2,3};
        int i=0;
        temp(ar,ARR_SIZE);
        puts("In main():");
        for(i = 0; i < sizeof(ar)/sizeof(ar[i]); i++)
            printf(" %d ", ar[i]);

        return 0;
    }

См. Демонстрацию

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

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

#include <stdio.h>

    void temp(int arr[], size_t arr_size)
    {
        int i;

        printf("\nArray size is: %d\nValues are:\n", (int) arr_size);
        for (i = 0; i <= arr_size - 1; i++) 
        {  
            printf(" %d",arr[i]);
        }

    }


    int main(void)
    {

        int ar[]={1,2,3};
        int i=0;
        temp( ar, array_len(ar) );
        return 0;
    }

Просмотреть код в реальном времени

Интересная связанная дискуссия и хорошее чтение о макросах здесь.