,就是数组可以容纳的元素数量?
#1 楼
执行摘要: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])
或等效的sizeof(*a)
,即数组第一个元素的大小。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);
评论
生成的代码将是相同的,因为编译器在编译时就知道* int_arr的类型(因此知道sizeof(* int_arr)的值)。这将是一个常数,编译器可以相应地进行优化。
–马克·哈里森(Mark Harrison)
2013年9月21日19:58在
所有编译器都应该如此,因为sizeof的结果被定义为编译时常量。
–马克·哈里森(Mark Harrison)
2013年9月22日下午5:39
重要提示:不要在这里停止阅读,请阅读下一个答案!这仅适用于堆栈上的数组,例如如果您使用的是malloc()或访问函数参数,那么您就不走运了。见下文。
–马库斯
2014年1月27日14:21
对于使用C或C ++进行Windows API编程,在WinNT.h中定义了ARRAYSIZE makro(由其他标头拉入)。因此,WinAPI用户无需定义自己的Makro。
–卢米
2014年4月23日在8:24
@Markus它适用于任何具有数组类型的变量;这不必是“堆栈上的”。例如。 static int a [20]; 。但是您的评论对可能没有意识到数组和指针之间的区别的读者很有用。
– M.M
2014年10月6日,下午2:45
#2 楼
如果您要处理未作为参数接收的数组,则sizeof
方法是正确的方法。作为参数发送给函数的数组被视为指针,因此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 OS中):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
评论
如果仅传递指向第一个数组元素的指针,为什么参数:2的长度呢?
– Bbvarghe
13年8月5日,下午2:42
@Bbvarghe这是因为64位系统中的指针为8个字节(sizeof(intArray)),但int仍(通常)仍为4个字节长(sizeof(intArray [0]))。
– Elideb
13年8月28日在17:33
@Pacerier:没有正确的代码-通常的解决方案是将长度和数组作为单独的参数传递。
–吉恩·霍米纳尔(Jean Hominal)
13-10-5在13:58
等待,所以没有办法直接从指针访问数组并查看其大小?这里是C的新手。
– sudo
2013年12月1日下午6:37
@Michael Trouw:如果可以使您感觉更好,则可以使用运算符语法:(sizeof数组/ sizeof * array)。
– chqrlie
2015年4月28日在17:00
#3 楼
值得注意的是,sizeof
在处理已衰减为指针的数组值时无济于事:即使它指向数组的开头,但对于编译器,它与指向该数组单个元素的指针相同数组。指针不会“记住”用于初始化数组的其他任何信息。int a[10];
int* p = a;
assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
评论
@ Magnus:该标准将sizeof定义为产生对象中的字节数,并且sizeof(char)始终为1。字节中的位数是特定于实现的。编辑:ANSI C ++标准第5.3.3节Sizeof:“ sizeof运算符产生其操作数的对象表示形式中的字节数。sizeof(char),sizeof(signed char)和sizeof(unsigned char)是1;将sizeof应用于任何其他基本类型的结果是实现定义的。”
– Skizz
08年9月1日在8:34
第1.6节C ++内存模型:“ C ++内存模型中的基本存储单元是字节。一个字节至少要大到足以包含基本执行字符集的任何成员,并且由连续的位序列(即数字)组成其中由实现定义。”
– Skizz
08年9月1日在8:34
我记得CRAY的C具有32位的char。所有标准说的是,可以表示从0到127的整数值,并且其范围至少为-127到127(带符号的字符)或0到255(无符号的字符)。
– vonbrand
13年2月1日于20:57
这是一个很好的回应。我想评论所有以上断言都被评估为TRUE。
– Javad
2015年6月4日23:23
#4 楼
sizeof技巧是我所知的最好方法,在括号的使用上有一个很小但是(对我来说,这是一个主要的麻烦)。维基百科条目清楚地表明, 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);
现在您已受到保护。当然,您可以重复变量的名称,但是如果您更改它,则很有可能以编译器可以检测的方式破坏该变量。
评论
顺便说一句,它们在处理器级别上是相同的指令吗? sizeof(int)所需的指令是否少于sizeof(foo)?
–起搏器
2013年9月21日在6:53
@Pacerier:不,它们是相同的。认为int x = 1 + 1;与int x =(1 + 1);。在这里,括号纯粹是完全美学的。
–quetzalcoatl
13-10-5 13:22
@Aidiakapi并非如此,请考虑使用C99 VLA。
–放松
16年1月13日在13:18
sizeof可能是运算符,但根据Linus Torvalds,应将其视为函数。我同意。在这里阅读他的理论:lkml.org/lkml/2012/7/11/103
– SO臭味
3月17日下午14:55
为什么要省略括号以使其更具可读性? sizeof myArray / sizeof * myArray;可能意味着sizeof(myArray / sizeof * myArray);例如。我知道这没有任何意义,但是最好还是使用明确的恕我直言。
–埃里克·杜米尼尔(Eric Duminil)
11月28日12:24
#5 楼
int size = (&arr)[1] - arr;
查看此链接以获取解释
评论
小nitpick:指针减法的结果类型为ptrdiff_t。 (通常在64位系统上,此类型将比int大)。即使在此代码中将int更改为ptrdiff_t,如果arr占用了一半以上的地址空间,它仍然存在一个错误。
– M.M
14-10-6在2:37
@ M.M另一个小问题:根据您的系统体系结构,地址空间不如大多数系统上的指针大小大。例如,Windows将64位应用程序的地址空间限制为8TB或44位。因此,例如,即使您的数组的地址空间大于4.1TB的一半,也不会有问题。仅当您的地址空间在这些系统上超过63位时,才有可能遇到此类错误。通常,不用担心。
– Aidiakapi
16年1月8日在17:00
在32位x86 Linux上或在具有/ 3G选项的Windows上,@Aidiakapi具有3G / 1G用户/内核拆分功能,这使您可以将阵列大小最大为地址空间大小的75%。
–俄罗斯
18年1月10日在12:26
考虑foo buf1 [80]; foo buf2 [sizeof buf1 / sizeof buf1 [0]]; foo buf3 [(&buf1)[1]-buf1];作为全局变量。 buf3 []声明失败,因为(&buf1)[1]-buf1不是常数。
–chux-恢复莫妮卡
18年5月21日在16:01
这是技术上未定义的行为,因为标准明确禁止取消引用数组的末尾(即使您不尝试读取存储的值)
– M.M
2月16日10:57
#6 楼
您可以使用sizeof运算符,但不适用于函数,因为它将使用指针的引用您可以执行以下操作找到数组的长度:
len = sizeof(arr)/sizeof(arr[0])
最初在此处找到的代码:
C程序查找数组中元素的数量
#7 楼
如果您知道数组的数据类型,则可以使用类似以下内容的方法: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
(数组名称)都是一个指针。评论
int noofele = sizeof(arr)/ sizeof(int);仅比int noofele = 9;编码好一半。如果数组大小发生变化,使用sizeof(arr)可以保持灵活性。但是,如果arr []的类型发生更改,sizeof(int)需要更新。即使类型众所周知,最好使用sizeof(arr)/ sizeof(arr [0])。不清楚为什么将inof用于noofele与size_t(由sizeof()返回的类型)进行比较。
–chux-恢复莫妮卡
16年5月20日在20:50
#8 楼
每个人都在使用的宏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
最终将成为指针类型,并使整个宏无效(就像您试图在带有指针参数的函数中使用该宏一样)。最后,在这种情况下,错误实际上并不重要(因此,我只是在浪费每个人的时间;烦死了!),因为您没有带有“数组”类型的表达式。但实际上,我认为关于预处理程序评估的要点很微妙。
评论
感谢您的解释。原始版本会导致编译时错误。 Clang报告“下标的值不是数组,指针或向量”。在这种情况下,这似乎是可取的行为,尽管您对宏中评估顺序的评论已被很好地接受。
–马克·哈里森(Mark Harrison)
2014年2月28日在2:30
我没有想到将编译器投诉视为错误类型的自动通知。谢谢!
–user2379628
2014年2月28日在2:46
有没有理由不使用(sizeof(x)/ sizeof(* x))?
–seriousdev
17 Mar 28 '17 at 13:40
#9 楼
对于多维数组,这有点复杂。人们通常会定义显式宏常量,即#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])
等,无限制。
#10 楼
我建议不要使用sizeof
(即使可以使用它)来获取数组的两个不同大小中的任何一个,无论是元素数量还是字节数,这是我在这里显示的最后两种情况。对于这两种大小,可以使用下面显示的宏使其更安全。原因是使代码的意图明显地体现给维护者,乍一看,sizeof(ptr)
与sizeof(arr)
的区别(这种写法并不明显),因此对于每个阅读代码的人来说,错误都是显而易见的。; DR:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof(arr) + must_be_array(arr))
#define ARRAY_SBYTES(arr) ((ssize_t)ARRAY_BYTES(arr))
must_be_array(arr)
(定义如下)是必需的,因为-Wsizeof-pointer-div
越野车(截至2020年4月):#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(arr) (!is_same_type((arr), &(arr)[0]))
#define must_be(e, ...) ( \
0 * (int)sizeof( \
struct { \
_Static_assert((e) __VA_OPT__(,) __VA_ARGS__);\
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
#define must_be_array(arr) must_be(is_array(arr), "Not a `[]` !")
有是与此主题相关的重要错误: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_SIZE
和size_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_BYTES的结果与返回
ssize_t
的函数的输出进行比较,最好定义此宏的带符号变体:#define ARRAY_SBYTES(arr) ((ssize_t)ARRAY_BYTES(arr))
它的工作原理非常简单:它消除了
ARRAY_SIZE
的除法运算,因此在数学上的取消之后,您最终只得到一个sizeof(arr)
,但又增加了ARRAY_SIZE
结构的安全性。 memset()
需要将此值作为第三个参数。和以前一样,如果将数组作为参数(指针)接收,则它将无法编译,因此我们必须将宏调用替换为值:
void foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
更新(23 / apr / 2020):
-Wsizeof-pointer-div
有错误:今天我发现新的警告出现在只有在宏不是在系统头中定义的宏中,GCC才起作用。如果您在系统中安装的标头(通常是
/usr/local/include/
或/usr/include/
)(#include <foo.h>
)中定义宏,则编译器将不会发出警告(我尝试了GCC 9.3.0)。所以我们有
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
并想要使其安全。我们将需要C11 _Static_assert()
和一些GCC扩展:表达式中的语句和声明,__ builtin_types_compatible_p:void foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
现在
ARRAY_SIZE()
是完全安全的,因此其所有派生形式都将是安全的。更新:libbsd提供
__arraycount()
:Libbsd在
__arraycount()
中提供了宏<sys/cdefs.h>
,这是不安全的,因为它缺少一对圆括号,但是我们可以自己添加这些圆括号,因此我们甚至不需要在标头中写入除法(为什么我们要复制已经存在的代码存在吗?)。该宏是在系统头文件中定义的,因此如果使用它,则必须使用上面的宏。#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(arr) (!is_same_type((arr), &(arr)[0]))
#define Static_assert_array(arr) _Static_assert(is_array(arr), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
sizeof(arr) / sizeof((arr)[0]); \
} \
)
有些系统在
nitems()
中提供<sys/param.h>
,有些系统同时提供了两者。您应该检查系统,并使用现有的系统,并可能使用一些预处理器条件来实现可移植性,并同时支持两者。更新:允许宏在文件范围内使用:
不幸的是,则不能在文件范围内使用
({})
gcc扩展名。要能够在文件范围内使用宏,静态声明必须在
sizeof(struct {})
内部。然后,将其乘以0
不会影响结果。强制转换为(int)
可能是不错的,它可以模拟返回(int)0
的函数(在这种情况下没有必要,但随后它可重用于其他用途)。另外,
#include <stddef.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(arr) (!is_same_type((arr), &(arr)[0]))
#define Static_assert_array(arr) _Static_assert(is_array(arr), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
__arraycount((arr)); \
} \
)
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
#define ARRAY_SBYTES(arr) ((ssize_t)ARRAY_BYTES(arr))
注意:
此代码利用以下扩展,这些扩展是完全必要的,并且它们的存在对于确保安全是绝对必要的。如果您的编译器没有它们,或类似的东西,那么您就无法达到此安全级别。
ARRAY_BYTES()
__builtin_types_compatible_p()
我也做了使用以下C11功能。但是,可以使用一些肮脏的技巧来克服由于使用较旧的标准而导致的缺失(例如,参见:C代码中的“:-!!”是什么?)。
typeof()
我也使用以下扩展名,但是有一种标准的C方法可以执行相同的操作。
_Static_assert()
评论
您介意解释为什么投票否决吗?这显示了一种针对不安全且通用的构造(sizeof(arr))的解决方案,该构造未在其他地方显示:ARRAY_BYTES(arr)。
– alx
19年8月17日在15:25
ARRAY_SIZE足够通用,可以自由使用,并且ARRAY_BYTES的名称非常明确,应该在ARRAY_SIZE旁边定义,以便用户可以轻松查看两者,以及其用法,我认为阅读代码的人不会怀疑是的。我的意思是不要使用简单的sizeof,而应使用此构造。如果您想每次都编写这些构造,则可能会犯一个错误(如果复制粘贴,这很常见,并且每次编写它们也很常见,因为它们都有很多括号)...
– alx
19年8月17日在15:39
...,所以我站在主要结论上:单一的sizeof显然是不安全的(原因在于答案),并且不使用宏而是每次使用我提供的构造都是更加不安全的,因此唯一的方法是go是宏。
– alx
19年8月17日在15:40
@MarkHarrison我确实知道指针和数组之间的区别。但是有时候我有一个函数,后来我将其重构为小函数,首先是一个数组,然后是一个指针,这就是如果您忘记更改sizeof并拧紧它的地方,很容易看不到其中一个。
– alx
19年8月18日在9:11
@hyde另外,我知道这种区别并不意味着每个人都知道这种区别,为什么不使用基本上可以消除100%这些错误的东西呢?这个错误几乎使它进入了Linux。他说,它到达了Linus,这意味着它经过了很多审查,也意味着有可能同一错误已将其引入内核另一部分的Linux中。
– alx
19年8月18日在9:16
#11 楼
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
评论
奇怪的是,该代码使用size_t size_of_element却使用int的int n = sizeof(a)/ sizeof(a [0]);而不是size_t n = sizeof(a)/ sizeof(a [0]);
–chux-恢复莫妮卡
16年5月20日在21:02
嗨,@ Yogeesh H T,您能回答对chux的疑问吗?我也很好奇知道int n = sizeof(a)/ sizeof(a [0])如何给出数组的长度以及为什么我们不使用size_t作为数组的长度。有人可以回答吗?
–脑
17年7月21日在19:55
@Brain sizeof(a)给出数组中所有元素的sizeof,sizeof(a [0])给出第1个元素的sizeof。假设a = {1,2,3,4,5}; sizeof(a)= 20个字节(如果sizeof(int)= 4个字节乘以5),sizeof(a [0])= 4个字节,因此20/4 = 5,即没有元素
– Yooeshesh H T
17年7月24日在11:28
@YogeeshHT对于非常大的数组,例如char a [INT_MAX + 1u] ;,用于int的int n = sizeof(a)/ sizeof(a [0]);不足(UB)。使用size_t n = sizeof(a)/ sizeof(a [0]);不会引起此问题。
–chux-恢复莫妮卡
18年5月21日在16:10
#12 楼
sizeof(array) / sizeof(array[0])
评论
根据数组的类型,如果array是char,unsigned char或signed char的数组,则不需要使用sizeof(array)/ sizeof(array [0])-引用C18,6.5.3.4 / 4: “将sizeof应用于具有char,unsigned char或signed char类型(或其限定版本)的操作数时,结果为1。”在这种情况下,您可以按照我的专用答案中的说明简单地执行sizeof(array)。
– RobertS支持Monica Cellio
3月6日13:52
#13 楼
“您已经介绍了一种用脚射击自己的微妙方法”C'native'数组不存储其大小。因此,建议将数组的长度保存在单独的变量/常量中,并在每次传递数组时将其传递,即:
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
您应始终避免使用本机数组(除非您不能这样做,否则请放心)。如果您正在编写C ++,请使用STL的“向量”容器。 “与数组相比,它们提供几乎相同的性能”,并且它们的作用要大得多!
// 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 /
评论
我读过在C中声明整数常量的正确方法是使用枚举声明。
–拉菲·哈特查杜安(Raffi Khatchadourian)
13年8月3日在23:08
问题是关于C,而不是C ++。所以没有STL。
– alx
4月23日9:26
#14 楼
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
评论
请注意,这仅适用于实际数组,不适用于指向数组的指针。
– David Schwartz
17年1月7日在20:18
#15 楼
如果您真的想通过数组来传递数据,那么我建议您实现一个结构,以存储指向您想要的数组类型的指针和一个表示数组大小的整数。然后,您可以将其传递给函数。只需将数组变量值(指向第一个元素的指针)分配给该指针。然后可以使用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;
}
评论
无法更新执行strcpy(d.name,name)的代码;没有溢出的处理。
–chux-恢复莫妮卡
16年5月20日在20:58
#16 楼
最好的方法是将这些信息保存在一个结构中,例如:typedef struct {
int *array;
int elements;
} list_s;
实现所有必要的功能,例如创建,销毁,检查相等性以及其他所有功能需要。作为参数传递更容易。
评论
int元素vs. size_t元素有什么原因吗?
–chux-恢复莫妮卡
16年5月20日21:00
#17 楼
函数sizeof
返回您的数组在内存中使用的字节数。如果要计算数组中元素的数量,则应将该数量除以数组的sizeof
变量类型。假设是int array[10];
,如果您计算机中的变量类型整数为32位(或4字节),则要获取数组的大小,应执行以下操作:int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
#18 楼
您可以使用&
运算符。这是源代码:#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
评论
我没有投票,但这就像用砖头砸钉子一样,因为您没有注意到旁边有锤子。而且,人们倾向于不使用未初始化的变量...但是我想在这里它可以很好地满足您的目的。
–德米特里
2014年9月11日下午21:18
@Dmitri此处未访问未初始化的变量
– M.M
2014年10月6日在2:39
嗯指针减法导致ptrdiff_t。 sizeof()导致size_t。 C没有定义哪个等级更大或更高级/相同。因此,商的类型((char *)(&a + 1)-(char *)a)/(sizeof(a [0]))不一定是size_t,因此用z打印可以导致UB。只需使用printf(“数组a的大小为%zu \ n”,sizeof a / sizeof a [0]);足够了。
–chux-恢复莫妮卡
16年5月20日在21:10
(char *)(&a + 1)-(char *)a不是常数,即使在大小为a [10]的情况下也可以在运行时进行计算。在这种情况下,sizeof(a)/ sizeof(a [0])在编译时是不变的。
–chux-恢复莫妮卡
18年5月21日在16:17
#19 楼
最简单的答案:#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 楼
更优雅的解决方案是size_t size = sizeof(a) / sizeof(*a);
#21 楼
除了已经提供的答案外,我想通过使用sizeof(a) / sizeof (a[0])
指出一种特殊情况,如果
a
是char
,unsigned char
的数组或signed char
不需要使用sizeof
,因为带有这些类型的一个操作数的sizeof
表达式始终会产生1
。C18,6.5.3.4 / 4的引用:
“将
sizeof
应用于类型为char
,unsigned char
或signed char
(或其限定版本)的操作数时,结果为1
。” 因此,如果
sizeof(a) / sizeof (a[0])
是NUMBER OF ARRAY ELEMENTS / 1
,a
或char
类型的数组,则unsigned char
将等效于signed char
。除以1是多余的。在这种情况下,您可以简单地缩写并执行:
sizeof(a)
例如:
char a[10];
size_t length = sizeof(a);
如果您想证明,这里是GodBolt的链接。
但是,如果类型发生明显变化,该部门仍将保持安全。 (尽管这些情况很少见。)
评论
您可能仍希望对除法仍然应用宏,因为该类型将来可能会更改(尽管可能不太可能),并且该除法在编译时就已知道,因此编译器会对其进行优化(如果不进行更改,请更改)您的编译器)。
– alx
4月23日9:09
@CacahueteFrito是的,与此同时,我也考虑过这一点。我把它作为答案的补充说明。谢谢。
– RobertS支持Monica Cellio
4月23日9:22
我建议永远不要偷偷摸摸。它甚至不会增加任何性能改进,因为划分是在编译时完成的。
– alx
7月20日14:07
#22 楼
注意:这可以给您MM在注释中指出的未定义行为。int a[10];
int size = (*(&a+1)-a) ;
有关更多详细信息,请参见
此处
以及此处。
评论
这在技术上是不确定的行为; *运算符可能不适用于过去的指针
– M.M
18年8月28日在0:45
“未定义的行为”表示C标准未定义行为。如果您在程序中尝试,那么任何事情都会发生
– M.M
18年8月28日在22:09
@ M.M是在说*(&a + 1)-a;与(&a)[1]不同-a;上面,*(&a + 1)和(&a)[1]都算不算1吗?
– QuentinUK
2月16日下午1:58
@QuentinUK您的两个表达式都相同,x [y]定义为*(x +(y))
– M.M
2月16日2:00
@ M.M我是这样认为的。但是另一个答案是Arjun Sreedharan,它有38个向上箭头,而这个数字是-1。 Arjun Sreedharan的答案没有提及不确定的行为。
– QuentinUK
2月16日上午9:30
评论
有关类型安全性,请参见stackoverflow.com/questions/19452971/array-size-macro-that-rejects-pointers