代码之家  ›  专栏  ›  技术社区  ›  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++中只使用向量类。

    如果出于某种原因不能实现,那么就需要宏实现。 从WiNt.h中查看一组宏的答案,它在C中工作,甚至在C++中更安全:

    Can this macro be converted to a function?

        3
  •  5
  •   Brian R. Bondy    16 年前

    使用stdlib.h的countof宏

    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 对于普通元素,如果不是,可以使用其他一些特殊的结束值。

    在我编写的代码中,任何涉及编译器大小数组的操作都是用类似 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动态引入新变量。如果你在做一些静态的事情,我建议你遵守定义。我不确定我是否会称之为最佳实践,但今天,我就是这样实践的。

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

        6
  •  1
  •   Nick    16 年前

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

        7
  •  1
  •   paercebal    16 年前

    对于C++,使用STD::向量

    使用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++中)在编译时评估的。对于增长的数组,MalCal/RealOc/Field是C的方式,STD::vector(或者任何其他的通用STL容器)是C++中的方式。

        8
  •  1
  •   Community CDub    8 年前

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

    我特别喜欢 _countof (CFR)。布莱恩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不是数组”)。