如何在C中确定数组的大小?

时间:2008-09-01 06:49:23

标签: c arrays memory

如何在C中确定数组的大小?

那就是阵列可以容纳的元素数量?

26 个答案:

答案 0 :(得分:1058)

执行摘要:

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

完整答案:

要确定数组的大小(以字节为单位),可以使用sizeof 操作者:

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

在我的电脑上,整数是4个字节长,所以n是68。

要确定数组中元素的数量,我们可以划分 数组的总大小由数组元素的大小决定。 您可以使用类型执行此操作,如下所示:

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

并得到正确的答案(68/4 = 17),但如果的类型 a改变了,如果你忘记改变,你会有一个讨厌的错误 sizeof(int)也是如此。

所以首选除数是sizeof(a[0]),即大小 数组的零元素。

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

另一个优点是您现在可以轻松参数化 宏中的数组名称并获取:

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

int a[17];
size_t n = NELEMS(a);

答案 1 :(得分:706)

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

答案 2 :(得分:119)

值得注意的是sizeof在处理已经衰减到指针的数组值时没有帮助:即使它指向数组的开头,对于编译器它也是一样的指向该数组的单个元素的指针。指针不会“记住”用于初始化它的数组的任何其他内容。

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

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

答案 3 :(得分:44)

“诀窍”的大小是我所知道的最好的方式,只有一个小但是(对我而言,这是一个主要的宠儿)在括号的使用中发生了重大变化。

正如维基百科条目所表明的那样,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);

现在你受到了保护。当然,你复制变量的名称,但如果你改变它,那么很有可能以编译器可以检测到的方式中断。

答案 4 :(得分:36)

int size = (&arr)[1] - arr;

查看this link了解

答案 5 :(得分:25)

您可以使用sizeof运算符,但它不适用于函数,因为它将引用指针 您可以执行以下操作来查找数组的长度:

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

最初在此处找到的代码: C program to find the number of elements in an array

答案 6 :(得分:20)

如果你知道数组的数据类型,你可以使用类似的东西:

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(数组名称)都是指针。

答案 7 :(得分:16)

每个人都在使用的宏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]);

这显然与数组的大小没有多大关系。我刚刚注意到很多错误都没有真正观察C预处理器的工作原理。您总是包装宏参数,而不是可能涉及的表达式。


这是正确的;我的例子很糟糕。但这实际上应该是应该发生的事情。正如我之前提到的那样p + 1将最终作为指针类型并使整个宏无效(就像你试图在带有指针参数的函数中使用宏一样)。

在一天结束时,在这个特定的实例中,错误并不重要(所以我只是浪费每个人的时间; huzzah!),因为你没有表达式有一种'数组'。但我认为关于预处理器评估小数的真正意义重大。

答案 8 :(得分:14)

对于多维数组,它有点复杂。通常人们定义显式宏常量,即

#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])
无限地等等。

答案 9 :(得分:13)

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

答案 10 :(得分:12)

sizeof(array) / sizeof(array[0])

答案 11 :(得分:10)

Variable.name

答案 12 :(得分:9)

“你已经介绍了一种微妙的射击自己的方法”

C'原生'数组不存储它们的大小。因此,建议将数组的长度保存在单独的变量/ const中,并在每次传递数组时传递它,即:

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

你应该总是避免使用原生数组(除非你不能,在这种情况下,请注意你的脚)。如果您正在编写C ++,请使用STL的'vector'容器。 “与数组相比,它们提供了几乎相同的性能”,它们更有用!

// 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/

答案 13 :(得分:4)

如果你真的想这样做来传递你的数组我建议实现一个结构来存储一个指向你想要一个数组的类型的指针和一个表示数组大小的整数。然后你可以将它传递给你的函数。只需将数组变量值(指向第一个元素的指针)赋给该指针即可。然后你可以去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;
}

答案 14 :(得分:4)

  

@Skizz:我很确定我是对的,虽然我现在可以给你的最好的“来源”是维基百科,来自关于sizeof的文章:

维基百科错了,Skizz是对的。根据定义,sizeof(char)为1。

我的意思是,只是非常仔细地阅读维基百科条目,看它是错的。 “char的倍数”。 sizeof(char)永远不会是其他而不是“1”。如果它是2,则意味着sizeof(char)是char的两倍!

答案 15 :(得分:4)

@ Magnus:标准将sizeof定义为产生对象中的字节数,而sizeof(char)始终为1。字节中的位数是特定于实现的。

编辑:ANSI C ++标准部分5.3.3 Sizeof:

  

sizeof运算符产生其操作数的对象表示中的字节数。 [...] sizeof(char),sizeof(signed char)和sizeof(unsigned char)为1; sizeof应用于任何其他基本类型的结果是实现定义的。

第1.6节C ++内存模型:

  

C ++内存模型中的基本存储单元是字节。一个字节至少足以包含基本执行字符集的任何成员,并由一个连续的位序列组成,其数量是实现定义的。

答案 16 :(得分:3)

最好的方法是保存此信息,例如,在结构中保存:

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

实现所有必要的功能,例如创建,销毁,检查相等以及您需要的所有其他功能。作为参数传递更容易。

答案 17 :(得分:3)

函数sizeof返回数组在内存中使用的字节数。如果要计算数组中元素的数量,则应将该数字除以数组的sizeof变量类型。假设int array[10];,如果您计算机中的变量类型为32位(或4字节),那么为了获得数组的大小,您应该执行以下操作:

int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);

答案 18 :(得分:3)

我建议不要使用sizeof(即使可以使用它)来获取数组的两个不同大小中的任何一个,无论是元素数量还是字节数,这都是最后一个我在这里展示两种情况。对于这两种大小,可以使用下面显示的宏使其更安全。原因是使代码的意图明显地体现给维护者,乍一看sizeof(ptr)sizeof(arr)的区别(这种写法并不明显),因此对于每个阅读本书的人来说,错误都是显而易见的代码。



有关此主题的重要错误:https://lkml.org/lkml/2015/9/3/428

我不同意Linus提供的解决方案,即永远不要将数组符号用作函数的参数。

我喜欢将数组表示法用作将指针用作数组的文档。但这意味着需要采用一种简单的解决方案,以便不可能编写错误的代码。

在数组中,我们可能需要知道三种大小:

  • 数组元素的大小
  • 数组中的元素数
  • 数组在内存中使用的字节大小

数组元素的大小

第一个非常简单,我们处理数组还是指针都没有关系,因为它是通过相同的方式完成的。

用法示例:

void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
        qsort(arr, nmemb, sizeof(arr[0]), cmp);
}

qsort()需要此值作为其第三个参数。


对于其他两个大小(这是问题的主题),我们要确保我们正在处理数组,如果没有,则中断编译,因为如果我们在处理指针,我们将得到错误的值。当编译中断时,我们将能够轻松地看到,我们并没有在处理数组,而是在使用指针,并且我们只需要使用存储变量大小的变量或宏编写代码即可。指针后面的数组。


数组中的元素数

这是最常见的,许多答案为您提供了典型的宏ARRAY_SIZE:

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

鉴于ARRAY_SIZE的结果通常与类型为ptrdiff_t的带符号变量一起使用,最好定义此宏的带符号变体:

#define ARRAY_SSIZE(arr)    ((ptrdiff_t)ARRAY_SIZE(arr))

具有超过PTRDIFF_MAX个成员的数组将为此宏的签名版本提供无效的值,但是通过阅读C17 :: 6.5.6.9,类似的数组已经开始发挥作用。在这种情况下,只能使用ARRAY_SIZEsize_t

当您将此宏应用于指针时,最新版本的编译器(例如GCC 8)会向您发出警告,因此它是安全的(还有其他方法可以使较旧的编译器安全)。

通过将整个数组的字节大小除以每个元素的大小来工作。

用法示例:

void foo(ptrdiff_t nmemb)
{
        char buf[nmemb];

        fgets(buf, ARRAY_SIZE(buf), stdin);
}

void bar(ptrdiff_t nmemb)
{
        int arr[nmemb];

        for (ptrdiff_t i = 0; i < ARRAY_SSIZE(arr); i++)
                arr[i] = i;
}

如果此函数未使用数组,而是将其作为参数使用,则先前的代码将无法编译,因此将不可能有错误(假设使用的是最新的编译器版本,或使用其他技巧)使用),我们需要将宏调用替换为以下值:

void foo(ptrdiff_t nmemb, char buf[nmemb])
{

        fgets(buf, nmemb, stdin);
}

void bar(ptrdiff_t nmemb, int arr[nmemb])
{

        for (ptrdiff_t i = 0; i < nmemb; i++)
                arr[i] = i;
}

数组在内存中使用的字节大小

ARRAY_SIZE通常用作前一种情况的解决方案,但这种情况很少被安全地编写,可能是因为它不太常见。

获取此值的常用方法是使用sizeof(arr)。问题:与上一个相同;如果您使用的是指针而不是数组,那么您的程序将会失败。

该问题的解决方案包括使用与以前相同的宏,我们知道这是安全的(如果将其应用于指针,它将破坏编译):

#define ARRAY_BYTES(arr)        (sizeof((arr)[0]) * ARRAY_SIZE(arr))

它的工作原理非常简单:它消除了ARRAY_SIZE所做的除法运算,因此,在进行数学取消后,您最终仅得到一个sizeof(arr),但是又增加了ARRAY_SIZE的安全性施工。

用法示例:

void foo(ptrdiff_t nmemb)
{
        int arr[nmemb];

        memset(arr, 0, ARRAY_BYTES(arr));
}

memset()需要此值作为其第三个参数。

和以前一样,如果将数组作为参数(指针)接收,它将无法编译,因此我们必须将宏调用替换为值:

void foo(ptrdiff_t nmemb, int arr[nmemb])
{

        memset(arr, 0, sizeof(arr[0]) * nmemb);
}

答案 19 :(得分:2)

最简单的答案:

#include <stdio.h>

int main(void) {

    int a[] = {2,3,4,5,4,5,6,78,9,91,435,4,5,76,7,34};//for Example only
    int size;

    size = sizeof(a)/sizeof(a[0]);//Method

    printf ("size = %d",size);
    return 0;
}

答案 20 :(得分:2)

一个更优雅的解决方案是

size_t size = sizeof(a) / sizeof(*a);

答案 21 :(得分: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

答案 22 :(得分:1)

int a[10];
int size = (*(&a+1)-a) ;

有关更多详细信息,请参见 here 还有here

答案 23 :(得分:0)

示例

#include <stdio.h>

int main() {
    int size;
    scanf("%d", &size);
    int array[size];
    printf("%d\n", (int) (sizeof(array) / sizeof(int)));
    printf("%d\n", (int) (sizeof(array) / sizeof(array[0])));
    return 0;
}

答案 24 :(得分:0)

对于预定义数组:

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

计算数组中的元素数:

 element _count =sizeof(a) / sizeof(a[0]);

答案 25 :(得分:-1)

除了已经提供的答案外,我想通过使用

来指出一种特殊情况
sizeof(a) / sizeof (a[0])

如果acharunsigned charsigned char的数组,则自sizeof起,您无需使用sizeof两次。带有这些类型的一个操作数的表达式总是会导致1

引用自C18,6.5.3.4 / 4:

sizeof应用于类型为charunsigned charsigned char(或其限定版本)的操作数时,结果为1。”

因此,如果sizeof(a) / sizeof (a[0])NUMBER OF ARRAY ELEMENTS / 1achar类型的数组,则unsigned char等效于signed char。除以1是多余的。

在这种情况下,您可以简单地缩写并执行:

sizeof(a)

例如:

char a[10];
size_t length = sizeof(a);

如果您想证明,这里是指向GodBolt的链接。


尽管如此,如果类型发生重大变化(尽管这种情况很少见),该部门仍将保持安全。