Recommendations for handling variable size arrays in c / C ++?

If I have an array of a fixed size depending on how it is defined and used, I usually use one of two ways to reference it.

Array type 1: since this is a fixed size based on a definition, I just use this definition in all of my loops that reference it.

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

Array type 2: since this array can grow as elements are added to it, I use sizeof to count the number of records in it. The size will be converted to constant by the compiler, so there should be no penalty for execution during the execution of this method.

 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 } 

Is there a more elegant solution for handling array processing without going past the end or stopping too early. Thoughts? Comments?

+4
source share
9 answers

This will work for both of your cases, regardless of the type of array element:

 #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] */ } 
+7
source

In C ++, just use a vector class.

If for some reason you cannot, that is, a macro-realization of what you want. See this answer for a set of macros from winnt.h that work in C and even more safely in C ++:

Can this macro be converted to a function?

+5
source

Use the _countof macro for stdlib.h

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 } 
+5
source

It is generally accepted that C code is similar to

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

Often you can find at least one field that will never be 0 / NULL for regular elements, and if not, you can use another special END value.

In the code that I write, everything related to arrays of sizes made using compiletime is done using a macro like ARRAY_COUNT from the ARRAY_COUNT 's answer, and arrays of runtime size always have a size counter in the structure with the array.

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

The length field makes it easy to resize the packet.

+2
source

For C, I suggest realloc to dynamically introduce new variables. If you are doing something statically, I would suggest saving #define. I'm not sure what I would call this best practice, but today it is the way I would practice it.

C ++ best practice is to use stl :: vector. Link here

+1
source

I almost always use a wrapper class (MFC CArray, stl vector, etc.) unless there is a specific reason. There is not much overhead, you get a lot of debugging checks, you can dynamically size, get the size easily, etc.

+1
source

For C ++ using std :: vector

It makes no sense to use a C array. std :: vector has (almost) the same performance as the C array, and it will:

  • grow as needed
  • know its size
  • make sure you really get access to the correct memory (i.e. it may throw an exception if you go beyond it)

And this is not even a consideration of the general algorithm associated with std :: vector.

Now using c

You can write a little better in at least two ways. First, replacing the definition with a true constant variable:

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

Using a true variable will offer you a slightly safer type and will not pollute the global realm. To minimize dependency, you can even declare variables in the header and define them in the source:

 /* 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 } 

Thus, you can resize the array in one source without requiring recompilation of all sources that use it. The downside is that MAXPLAYERS are no longer known at compile time (but, is this really a downside?)

Please note that your second type of array cannot grow dynamically. Sizeof (at least in C ++) is evaluated at compile time. For growing arrays, malloc / realloc / free is the way to switch to C, and std :: vector (or any other common STL container) is the way to switch to C ++.

+1
source

Be sure to read the answers to this question - there are many solutions to the problem with the size of the array that are portable.

I especially like _countof (see Brian R. Bondi's answer) - Pulitzer for the inventor of this name!

+1
source

Addition to the answers so far, if you use T [] arrays in C ++: Use the output of the template argument to output the size of the array. This is much safer:

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

Your expression sizeof(mystruct)/sizeof(MYSTRUCT_DEF) stops working quite quietly if you change mystruct to malloc'ed / new'ed MYSTRUCT_DEF* . sizeof(mystruct) then becomes sizeof(MYSTRUCT_DEF*) , which is often smaller than sizeof(MYSTRUCT_DEF) , and you will have a cycle of 0. It would seem that the code just does not execute, which can be very confusing. Declaring the template above will give you a clear compiler error ("mystruct is not an array")

0
source

Source: https://habr.com/ru/post/1277639/


All Articles