使用函数计算C语言数组的长度

14

我希望创建一个函数,用于计算传递数组的大小。

我将输入一个数组,它应该返回它的长度。我想要一个函数

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

}

尽管大小为8,但长度应该为5,因为它包含5个元素(即使是8也可以,但5会更好)

我尝试了这个:

int ArraySize(int * Array)
{

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

}

这是行不通的,因为"sizeof(Array)"将返回Int指针的大小。 "sizeof"只在同一个函数中起作用。

实际上,我从C#转回来已经很多天了,所以我记不得(也想念Array.Length()

问候!


1
你的数组 MyArray 包含 8 个元素。其中 5 个已经被明确地初始化为 1、2、3、0 和 5;另外 3 个则被隐式地初始化为 0。 - pmg
是的,我知道... 但是有没有方法可以得到计数5? - Swanand
9个回答

34

当你只有一个指针时,无法计算数组的大小。

将其“类似于函数”的唯一方法是定义一个宏:

#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++)。


谢谢!这很好,但如果有函数的话我会更开心! - Swanand
@Swanand Purankar:我能理解,但在C语言中这是根本不可能的。 - DevSolar
@Swanand Purankar:我刚看到你在问题下的评论...请注意,这个宏不会给你一个5,而是8。C语言无法知道哪些/有多少数组元素实际上已经被赋值(除非您手动插入未初始化元素的特殊值并进行相应的非特殊值手动计数)。C本身只能告诉您数组的总大小。 - DevSolar
@DevSolar: 我尝试了这个宏,但问题是我不能在函数中使用这个宏,因为函数是通过指针传递数组的!有什么帮助吗?? - Swanand
@DevSolar:再次感谢!我的应用程序必须使用C语言,所以正如你所说,我必须在限制条件下编写代码!非常感谢!! - Swanand
你应该在宏定义周围添加更多的括号:#define array_length(array) (sizeof(array) / sizeof(array[0]))否则,在更大的方程式上下文中使用时可能会得到一些奇怪的结果。 - superlogical

12

一旦数组衰变成指针,您就不能这样做 - 您总是会得到指针大小。

您需要做的是:

  • 如有可能,请使用哨兵值,例如指针的 NULL 或正数的 -1。
  • 在数组仍然存在时计算其大小,并将该大小传递给任何函数。
  • 与上述相同,但使用花哨的宏魔法,例如:
    #define arrSz(a) (sizeof(a)/sizeof(*a))
  • 创建自己的抽象数据类型,其中将长度作为结构中的项进行维护,以便您有一种获取Array.length()的方法。

不一定需要传递指针... 通过传递数组的任何方法都可以。 - Swanand
6
在C语言中,“void foo(int[] arr)”和“void foo(int ptr)”是一样的。因此,传递给函数的数组总是*会衰变为指向数组第一个元素的指针。 - mk12

3
你所要求的事情是不可能完成的。
在运行时,程序只能获得数组第一个元素的地址信息。即使是元素的大小也只能从使用数组的类型上下文中推断出来。

2
在C语言中不行,因为当传递数组到函数时,它会衰减(变成指向第一个元素的指针)。但是在C++中,你可以使用模板参数推导来实现相同的功能。

我希望你在C++中使用<vector>。;-) - DevSolar
@DevSolar:是的!顺便看看我的链接帖子 :P - Prasoon Saurav

1
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
你能解释一下为什么要用“0xfd”和“0xcc”吗? - Swanand
这仅适用于MS Visual C++调试模式,并且仅适用于大小<256的情况,其中没有元素是合法的“0xfd”(由于i是char类型)。因为答案不是通用的,并且甚至没有记录何时可能或不可能工作,所以我要进行反对。请参见此答案以获取Visual C++使用的一些神奇数字。 - tucuxi

1

你需要通过额外的参数传递长度(就像strncpy一样),或者使用零终止数组(就像strcpy一样)。

这些技术存在一些小变化,比如将长度与指针捆绑在自己的类中,或者使用不同的标记表示数组的长度,但基本上这些是你唯一的选择。


1
但是你知道长度,你写了它! - Blindy
好的...我明白你希望我传递什么...但是那会如何帮助,我不太理解! - Swanand

1
无法实现。您需要从调用此函数的函数中传递数组的大小。当您将数组传递给函数时,只传递了起始地址而不是整个大小。当您计算数组的大小时,编译器不知道指针已经被分配了多少空间/内存。因此,最终的调用方式是,在调用该函数时需要传递数组大小。

0

已经很晚了,但我找到了一个解决方法。我知道这不是正确的解决方案,但如果您不想遍历整个整数数组,它可以起作用。

在此处检查 '\0' 将无效

首先,在初始化时将任何字符放入数组中

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

然后在传递值后检查 'x'

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

如果有用的话,请让我知道。


-4

C语言中数组的大小是:

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

printf("Size : %d",sizeof(a)/sizeof(int));

1
一旦您将a作为参数传递给函数,这个技巧就不起作用了,因为sizeof()是一个编译时函数。 - tucuxi
2
这并没有回答问题。由于已经有其他的回答,我建议您删除这个回答。如果有什么的话,这个提议的答案会让人认为您是一个连最基本技能都欠缺的开发者。 - IInspectable
@Md-Shahriar 我正在寻找一个能够完成这个任务的函数。 - Swanand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接