代码之家  ›  专栏  ›  技术社区  ›  KPexEA

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

  •  4
  • KPexEA  · 技术社区  · 16 年前

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

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

    #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
     }
    

    是否有一种更优雅的解决方案来处理数组的处理,而不会超过末尾或过早停止。思想?评论?

    9 回复  |  直到 16 年前
        1
  •  7
  •   Alex B    16 年前

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

    #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] */
    }
    
        2
  •  5
  •   Community CDub    8 年前

    在C++中,只需使用vector类。

    如果你因为某种原因不能,那么你想要的东西有宏实现。 查看winnt.h中的一组宏,这些宏在C中工作,在C++中更安全:

    Can this macro be converted to a function?

        3
  •  5
  •   Brian R. Bondy    16 年前

    使用stdlib的_countof宏。英语字母表的第8个字母

    From this MSDN article :

    // 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 bytes\n", sizeof(arr) );
       printf( "_countof(arr) = %d elements\n", _countof(arr) );
       // In C++, the following line would generate a compile-time error:
       // printf( "%d\n", _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
    }
    
        4
  •  2
  •   ephemient    16 年前

    常见的C代码如下

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

    通常,你可以找到至少一个永远不会出现的字段 0 / NULL 对于普通元素,如果不是,可以使用其他特殊的END值。

    在我编写的代码中,任何涉及编译时大小的数组的操作都是通过类似这样的宏完成的 ARRAY_COUNT 根据Checkers的回答,运行时大小的数组总是带有一个大小计数器,在数组的结构中。

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

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

        5
  •  1
  •   Paul Nathan    16 年前

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

    C++的最佳实践是使用stl::vector。 A reference here

        6
  •  1
  •   Nick    16 年前

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

        7
  •  1
  •   paercebal    16 年前

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

    使用C数组没有真正的意义。std::vector具有(几乎)与C数组相同的性能,它将:

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

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

    现在,使用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++中的选择。

        8
  •  1
  •   Community CDub    8 年前

    请确保也阅读 this question's answers -阵列大小问题的许多解决方案 便携式。

    我特别喜欢 _countof (布莱恩·R·邦迪的回答)——普利策奖颁给了这个名字的发明者!

        9
  •  0
  •   MSalters    16 年前

    除了到目前为止的答案之外,如果你在C++中使用T[]数组: 使用模板参数推导来推断数组大小。它更安全:

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

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

    推荐文章