Mar*_*son 1143
执行摘要:
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
Run Code Online (Sandbox Code Playgroud)
要以字节为单位确定数组的大小,可以使用sizeof
运算符:
int a[17];
size_t n = sizeof(a);
Run Code Online (Sandbox Code Playgroud)
在我的计算机上,整数是4个字节长,所以n是68.
要确定数组中元素的数量,我们可以将数组的总大小除以数组元素的大小.您可以使用类型执行此操作,如下所示:
int a[17];
size_t n = sizeof(a) / sizeof(int);
Run Code Online (Sandbox Code Playgroud)
并获得正确的答案(68/4 = 17),但如果a
您改变了类型,
如果您忘记更改它也会有一个讨厌的错误sizeof(int)
.
因此,首选除数是sizeof(a[0])
数组的零齿数的大小.
int a[17];
size_t n = sizeof(a) / sizeof(a[0]);
Run Code Online (Sandbox Code Playgroud)
另一个优点是,您现在可以轻松地在宏中参数化数组名称并获取:
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int a[17];
size_t n = NELEMS(a);
Run Code Online (Sandbox Code Playgroud)
Eli*_*deb 752
该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]) ));
}
Run Code Online (Sandbox Code Playgroud)
输出(在64位Linux操作系统中):
sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2
Run Code Online (Sandbox Code Playgroud)
输出(在32位Windows操作系统中):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
Run Code Online (Sandbox Code Playgroud)
Mag*_*off 127
值得注意的是,sizeof
在处理已经衰减到指针的数组值时没有帮助:即使它指向数组的开头,对于编译器它也与指向该数组的单个元素的指针相同.指针不会"记住"用于初始化它的数组的任何其他内容.
int a[10];
int* p = a;
assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
Run Code Online (Sandbox Code Playgroud)
unw*_*ind 47
"技巧"的大小是我所知道的最好的方式,其中一个很小但是(对我来说,这是一个主要的烦恼)括号使用的重要变化.
正如维基百科条目所表明的那样,C sizeof
不是一个功能; 这是一个运营商.因此,除了参数是类型名称之外,它不需要围绕其参数使用括号.这很容易记住,因为它使参数看起来像一个转换表达式,它也使用括号.
所以:如果你有以下内容:
int myArray[10];
Run Code Online (Sandbox Code Playgroud)
您可以使用以下代码找到元素的数量:
size_t n = sizeof myArray / sizeof *myArray;
Run Code Online (Sandbox Code Playgroud)
对我来说,这比使用括号的替代方案更容易阅读.我也赞成在分区的右侧使用星号,因为它比索引更简洁.
当然,这也是编译时间,因此无需担心影响程序性能的划分.所以尽可能使用此表单.
当你有一个而不是一个类型时,最好在实际对象上使用sizeof,因为那时你不需要担心发出错误并说明错误的类型.
例如,假设您有一个函数可以将一些数据作为字节流输出,例如通过网络输出.让我们调用该函数send()
,并将其作为参数作为指向要发送的对象的指针,以及对象中的字节数.所以,原型变成:
void send(const void *object, size_t size);
Run Code Online (Sandbox Code Playgroud)
然后你需要发送一个整数,所以你这样编码:
int foo = 4711;
send(&foo, sizeof (int));
Run Code Online (Sandbox Code Playgroud)
现在,通过指定foo
两个地方的类型,你已经介绍了一种微妙的射击方式.如果一个更改但另一个没有,则代码中断.因此,总是这样做:
send(&foo, sizeof foo);
Run Code Online (Sandbox Code Playgroud)
现在你受到了保护.当然,您复制变量的名称,但如果您更改它,则很可能以编译器可以检测到的方式中断.
Arj*_*ran 37
int size = (&arr)[1] - arr;
Run Code Online (Sandbox Code Playgroud)
请查看此链接以获取解释
Cac*_*ito 28
我建议永远不要使用sizeof
(即使可以使用)来获取数组的两种不同大小中的任何一种,无论是元素数量还是字节,这是我在这里展示的最后两种情况。对于这两种尺寸中的每一种,都可以使用下面显示的宏来使其更安全。究其原因是为了使代码维护者的明显意图,差异sizeof(ptr)
从sizeof(arr)
第一眼(其中这样写的不是很明显),这样的错误是再为大家读码明显。
特尔;博士:
#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))
Run Code Online (Sandbox Code Playgroud)
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 `[]` !")
Run Code Online (Sandbox Code Playgroud)
有关于这个主题的重要错误: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);
}
Run Code Online (Sandbox Code Playgroud)
qsort()
需要这个值作为它的第三个参数。
对于其他两个大小,这是问题的主题,我们要确保我们正在处理一个数组,如果不是,则中断编译,因为如果我们正在处理一个指针,我们将得到错误的值. 当编译被破坏时,我们将能够很容易地看到我们不是在处理数组,而是在处理一个指针,我们只需要用一个变量或一个宏来编写代码来存储数组的大小指针后面的数组。
这是最常见的,许多答案为您提供了典型的宏ARRAY_SIZE
:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
Run Code Online (Sandbox Code Playgroud)
鉴于 的结果ARRAY_SIZE
通常与 type 的有符号变量一起使用ptrdiff_t
,最好定义此宏的有符号变体:
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
Run Code Online (Sandbox Code Playgroud)
具有多个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;
}
Run Code Online (Sandbox Code Playgroud)
如果这些函数不使用数组,而是将它们作为参数,则之前的代码将无法编译,因此不可能有错误(考虑到使用了最新的编译器版本,或者使用了其他一些技巧) ,我们需要用值替换宏调用:
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;
}
Run Code Online (Sandbox Code Playgroud)
ARRAY_SIZE
通常用作前一种情况的解决方案,但这种情况很少安全地编写,可能是因为它不太常见。
获取此值的常用方法是使用sizeof(arr)
. 问题:和上一个一样;如果你有一个指针而不是一个数组,你的程序就会发疯。
该问题的解决方案涉及使用与之前相同的宏,我们知道这是安全的(如果将其应用于指针,则会破坏编译):
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
Run Code Online (Sandbox Code Playgroud)
鉴于有时将 ARRAY_BYTES 的结果与 return 的函数的输出进行比较ssize_t
,最好定义此宏的有符号变体:
#define ARRAY_SBYTES(arr) ((ssize_t)ARRAY_BYTES(arr))
Run Code Online (Sandbox Code Playgroud)
它的工作原理非常简单:它ARRAY_SIZE
取消了除法,所以在数学取消之后,你最终只有一个sizeof(arr)
,但增加了ARRAY_SIZE
构造的安全性。
用法示例:
void foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
Run Code Online (Sandbox Code Playgroud)
memset()
需要这个值作为它的第三个参数。
和以前一样,如果数组作为参数(指针)被接收,它不会编译,我们将不得不用值替换宏调用:
void foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
Run Code Online (Sandbox Code Playgroud)
-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:
#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]); \
} \
)
Run Code Online (Sandbox Code Playgroud)
NowARRAY_SIZE()
是完全安全的,因此它的所有衍生物都是安全的。
__arraycount()
:Libbsd提供了__arraycount()
in宏<sys/cdefs.h>
,它不安全,因为它缺少一对括号,但是我们可以自己添加这些括号,因此我们甚至不需要在我们的头中写除法(为什么我们要复制已经存在的代码? )。该宏定义在系统头文件中,因此如果我们使用它,我们将被迫使用上面的宏。
#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))
Run Code Online (Sandbox Code Playgroud)
有些系统提供nitems()
in<sys/param.h>
代替,有些系统同时提供。您应该检查您的系统,并使用您拥有的系统,并且可能使用一些预处理器条件来实现可移植性并支持两者。
不幸的是,({})
gcc 扩展名不能在文件范围内使用。为了能够在文件范围内使用宏,静态断言必须在sizeof(struct {})
. 然后,乘以0
不影响结果。转换 to(int)
可能很好地模拟一个返回的函数(int)0
(在这种情况下它不是必需的,但它可以重用于其他事情)。
另外, 的定义ARRAY_BYTES()
可以简化一些。
#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 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 `[]` !")
#define ARRAY_SIZE(arr) (__arraycount((arr)) + 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))
Run Code Online (Sandbox Code Playgroud)
此代码使用以下扩展,这些扩展是完全必要的,它们的存在对于实现安全是绝对必要的。如果您的编译器没有它们或一些类似的,那么您就无法达到这种安全级别。
我还使用了以下 C11 功能。但是,可以使用一些肮脏的技巧来克服使用旧标准的缺失(参见例如:C 代码中的“:-!!”是什么?)。
我也使用以下扩展名,但有一种标准的 C 方法可以做同样的事情。
Moh*_*bli 25
您可以使用sizeof运算符,但它不适用于函数,因为它将采用指针的引用,您可以执行以下操作来查找数组的长度:
len = sizeof(arr)/sizeof(arr[0])
Run Code Online (Sandbox Code Playgroud)
代码最初在这里找到: C程序查找数组中的元素数
Abh*_*tri 20
如果您知道数组的数据类型,则可以使用以下内容:
int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};
int noofele = sizeof(arr)/sizeof(int);
Run Code Online (Sandbox Code Playgroud)
或者,如果您不知道数组的数据类型,可以使用以下内容:
noofele = sizeof(arr)/sizeof(arr[0]);
Run Code Online (Sandbox Code Playgroud)
注意:只有在运行时未定义数组(如malloc)且数组未在函数中传递时,此方法才有效.在这两种情况下,arr
(数组名称)都是指针.
小智 17
ARRAYELEMENTCOUNT(x)
每个人都在使用的宏评估错误.实际上,这只是一个敏感问题,因为您不能拥有导致"数组"类型的表达式.
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))
ARRAYELEMENTCOUNT(p + 1);
Run Code Online (Sandbox Code Playgroud)
实际上评估为:
(sizeof (p + 1) / sizeof (p + 1[0]));
Run Code Online (Sandbox Code Playgroud)
而
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])
ARRAYELEMENTCOUNT(p + 1);
Run Code Online (Sandbox Code Playgroud)
它正确评估为:
(sizeof (p + 1) / sizeof (p + 1)[0]);
Run Code Online (Sandbox Code Playgroud)
这显然与数组的大小没有太大关系.我刚刚注意到很多错误都没有真正观察C预处理器的工作原理.您总是包装宏参数,而不是可能涉及的表达式.
这是对的; 我的例子很糟糕.但这实际上应该是应该发生的事情.正如我之前提到的那样,p + 1
最终将作为指针类型并使整个宏无效(就像你试图在带有指针参数的函数中使用宏一样).
在一天结束时,在这个特定的例子中,错误并不重要(所以我只是浪费每个人的时间; huzzah!),因为你没有带有'array'类型的表达式.但我认为关于预处理器评估小数的真正意义重大.
And*_*ler 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", " " },
};
Run Code Online (Sandbox Code Playgroud)
但是这些常量也可以在编译时使用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);
Run Code Online (Sandbox Code Playgroud)
请注意,此代码适用于C和C++.对于具有两个以上维度的数组使用
sizeof(name[0][0][0])
sizeof(name[0][0][0][0])
Run Code Online (Sandbox Code Playgroud)
无限的,无限的.
Yog*_*H T 14
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
Run Code Online (Sandbox Code Playgroud)
"你已经介绍了一种在脚下射击自己的微妙方式"
C'原生'数组不存储它们的大小.因此,建议将数组的长度保存在单独的变量/ const中,并在每次传递数组时传递它,即:
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
Run Code Online (Sandbox Code Playgroud)
你应该总是避免使用原生数组(除非你不能,在这种情况下,请注意你的脚).如果您正在编写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();
Run Code Online (Sandbox Code Playgroud)
请参阅:http: //www.cplusplus.com/reference/stl/vector/
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Run Code Online (Sandbox Code Playgroud)
小智 6
最好的方法是保存此信息,例如,在结构中:
typedef struct {
int *array;
int elements;
} list_s;
Run Code Online (Sandbox Code Playgroud)
实现所有必要的功能,例如创建、销毁、检查相等性以及您需要的所有其他功能。作为参数传递更容易。
该函数sizeof
返回数组在内存中使用的字节数。如果要计算数组中的元素数量,应将该数字除以sizeof
数组的变量类型。假设int array[10];
,如果您计算机中的变量类型整数是 32 位(或 4 个字节),为了获取数组的大小,您应该执行以下操作:
int array[10];
size_t sizeOfArray = sizeof(array)/sizeof(int);
Run Code Online (Sandbox Code Playgroud)
如果你真的想这样做来传递你的数组,我建议实现一个结构来存储一个指向你想要数组的类型的指针和一个表示数组大小的整数。然后你可以将它传递给你的函数。只需将数组变量值(指向第一个元素的指针)分配给该指针。然后你可以去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;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1825056 次 |
最近记录: |