在c/c++中处理可变大小数组的最佳实践

Best practices for handling variable size arrays in c / c++?

本文关键字:数组 小数 最佳 c++ 处理      更新时间:2023-10-16

如果我有一个固定大小的数组,取决于它的定义和使用方式,我通常会使用两种方法之一来引用它。

数组类型1:由于它是基于define的固定大小,所以我只在引用它的所有循环中使用该define

#define MAXPLAYERS 4
int playerscores[MAXPLAYERS];
for(i=0;i<MAXPLAYERS;++i)
{
.... do something with each player
}

数组类型2:由于这个数组可以随着项目的添加而增长,所以我使用sizeof来计算其中的项数。编译器会将其大小转换为常量,因此这样做不会在运行时造成任何损失。

typedef struct
{
    fields....
}MYSTRUCT_DEF;
MYSTRUCT_DEF mystruct[]={
   {entry 1},
   {entry 2},
   {entry 3...n}
   };
 for(i=0;i<(sizeof(mystruct)/sizeof(MYSTRUCT_DEF));++i)
 {
 ..... do something with each entry
 }

有没有一种更优雅的解决方案可以在不超过末尾或过早停止的情况下处理数组。想法?评论?

无论数组元素类型如何,这两种情况都适用:

#define ARRAY_COUNT(x) (sizeof(x)/sizeof((x)[0]))
...
struct foo arr[100];
...
for (i = 0; i < ARRAY_COUNT(arr); ++i) {
    /* do stuff to arr[i] */
}

在C++中,只需使用向量类。

如果由于某种原因无法实现,那么就有您想要的宏实现。关于winnt.h中的一组宏,请参阅以下答案,这些宏在C中工作,在C++中甚至更安全:

这个宏可以转换成函数吗?

使用stdlib.h 的_countof宏

来自MSDN的这篇文章:

// crt_countof.cpp
#define _UNICODE
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
int main( void )
{
   _TCHAR arr[20], *p;
   printf( "sizeof(arr) = %d bytesn", sizeof(arr) );
   printf( "_countof(arr) = %d elementsn", _countof(arr) );
   // In C++, the following line would generate a compile-time error:
   // printf( "%dn", _countof(p) ); // error C2784 (because p is a pointer)
   _tcscpy_s( arr, _countof(arr), _T("a string") );
   // unlike sizeof, _countof works here for both narrow- and wide-character strings
}

像这样的C代码很常见

struct foo {
    ...  /* fields */
};
struct foo array[] = {
    { ... }, /* item 1 */
    { ... }, /* item 2 */
    ...,
    { 0 } /* terminator */
};
for (i = 0; array[i].some_field; i++) {
    ...
}

通常,对于普通元素,您可以找到至少一个从来不是0/NULL的字段,如果不是,则可以使用其他一些特殊的END值。

在我编写的代码中,任何涉及编译时大小数组的操作都是用Checkers答案中的ARRAY_COUNT这样的宏来完成的,运行时大小的数组总是带有一个大小计数器,位于数组的结构中。

struct array_of_stuff {
    struct stuff *array;
    int count;   /* number of used elements */
    int length;  /* number of elements allocated */
};

length字段允许轻松批量调整大小。

对于C,我建议realloc动态引入新变量。如果您是静态地做某件事,我建议您使用#define。我不确定我是否会称之为最佳实践,但今天,我会这样实践

C++的最佳实践是使用stl::vector。此处的参考

我几乎总是使用包装类(MFC CArray、stl vector等),除非有特定的原因。没有太多的开销,你可以进行大量的调试检查,你可以动态调整大小,获取大小很容易,等等。

对于C++,使用std::vector

使用C数组没有实际意义。std::vector具有(几乎)与C阵列相同的性能,并且它将:

  • 根据需要增长
  • 知道它的大小
  • 验证您是否真的访问了正确的内存(即,如果您超出其范围,它可能会抛出异常)

这甚至没有考虑到与std::向量相关的通用算法。

现在,使用C

你可以写得更好一些,至少有两种方法。首先,将define替换为真正的常量变量:

// #define MAXPLAYERS 4
const unsigned int MAXPLAYERS = 4 ;
int playerscores[MAXPLAYERS];
for(i=0;i<MAXPLAYERS;++i)
{
.... do something with each player
}

使用真正的变量将为您提供更多的类型安全性,并且不会污染全局范围。为了最小化依赖性,您甚至可以在头中声明变量,并在源中定义它们:

/* header.h */
extern const unsigned int MAXPLAYERS ;
extern int playerscores[] ;
/* source.c */
const unsigned int MAXPLAYERS = 4
int playerscores[MAXPLAYERS];
/* another_source.c */
#include "header.h"
for(i=0;i<MAXPLAYERS;++i)
{
.... do something with each player
}

这样,您就可以在一个源中更改数组的大小,而无需重新编译所有使用它的源。缺点是MAXPLAYERS在编译时不再为人所知(但是,这真的是缺点吗?)

请注意,第二种类型的数组不能动态增长。sizeof(至少在C++中)是在编译时计算的。对于不断增长的数组,malloc/realloc/free是在C中的方法,std::vector(或任何其他通用STL容器)是在C++中的方法。

请务必阅读此问题的答案-可移植的数组大小问题的许多解决方案。

我特别喜欢_countof(布莱恩·邦迪的答案)——普利策奖,因为这个名字的发明者!

如果您在C++中使用T[]数组,那么添加到目前为止的答案:使用模板参数推导来推导数组大小。更安全:

template<int N> void for_all_objects(MYSTRUCT_DEF[N] myobjects)

如果将mystruct更改为malloc'ed/new'ed MYSTRUCT_DEF*,则sizeof(mystruct)/sizeof(MYSTRUCT_DEF)表达式将以静默方式失败。然后sizeof(mystruct)变成sizeof(MYSTRUCT_DEF*),它通常小于sizeof(MYSTRUCT_DEF),并且循环计数为0。看起来代码根本没有被执行,这可能非常令人困惑。上面的模板声明会给你一个明显的编译器错误("mystruct不是数组")