Returning a fixed size array

Hi,

Is it possible to return a fixed array from a function, like:

    unsigned char* getArray()
    {
        unsigned char help[] = { 3, 4, 5 };
        return help;
   }

I need this to be contained only in a header file (ie. can't use a cpp file), and I can't use any static storage. I know I can return a dynamically allocated array, but then the callee has to worry about freeing the array once it's done.


I ask because I'm using this 3rd party licensing system and have a few different license 'codes', which are defined and used like:

typedef struct CRAZY
{
    unsigned char Secret[32]; // null-terminated string
} _SECRET;

_SECRET g_Secret[] =
{
{0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
{0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
{0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
{0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
};

Each of those secrets is included as a global variable at the start of an application that uses it. Now I have several applications which need the same secret code, and they all have it defined - not good. I wanted to make one header class they could all share that just returns that static string above. I could make a lib that returns it since it can contain static storage, but was hoping to avoid adding yet another library to my project.

Thanks for any suggestions.
DJ_AM_JuiceboxAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

evilrixSenior Software Engineer (Avast)Commented:
Yes, but you must know it's size at compile time.
0
jkrCommented:
>> I wanted to make one header class they could all share that just returns that
>>static string above

I'm not sure what the problem is here. you could just

// secret.h
 
#ifndef SECRET_H
#define SECRET_H
 
typedef struct CRAZY
{
    unsigned char Secret[32]; // null-terminated string
} _SECRET;
 
_SECRET g_Secret[] =
{
{0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
{0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
{0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
{0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
};
 
    unsigned char* getArray()
    {
        
        return (unsigned char*) g_Secret;
   }
 
#endif

Open in new window

0
DJ_AM_JuiceboxAuthor Commented:
@evilrix:
That's no problem, the array is always the same.

@jkr:
When I do that, I'll get g_Secret already defined in blah.obj linking errors.
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

Infinity08Commented:
@jkr's code : better put the array in the .cpp file instead of the header file though.
0
evilrixSenior Software Engineer (Avast)Commented:
>> That's no problem, the array is always the same.
Then...
typedef unsigned char array3_t[3];
 
struct my_array
{
	array3_t data_;
};
 
 
my_array getArray()
{
	my_array help = {{ 1, 2, 3}};
	return help;
}
 
 
int main () {
	my_array array = getArray();
	return 0;
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Infinity08Commented:
>> When I do that, I'll get g_Secret already defined in blah.obj linking errors.

See my previous post ;)
/* ---- secret.h ---- */
 
#ifndef SECRET_H
#define SECRET_H
 
typedef struct CRAZY
{
    unsigned char Secret[32]; // null-terminated string
} _SECRET;
 
_SECRET* getArray();
 
#endif
 
 
/* ---- secret.cpp ---- */
 
#include "secret.h"
 
_SECRET g_Secret[] =
{
{0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
{0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
{0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
{0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
};
 
_SECRET* getArray() {
    return g_Secret;
}

Open in new window

0
DJ_AM_JuiceboxAuthor Commented:
Yeah that's the thing though, wondering if this can be done without use of a cpp file - if I'm forced to do that, I'll have to create a new library to house it so it can be shared between my apps. It would be more convenient if it could al lbe done in a header file.
0
jkrCommented:
>>When I do that, I'll get g_Secret already defined in blah.obj linking errors.

No, not with the header guards. But, to ensure that this will not happen, you can add
#ifndef SECRET_H
#define SECRET_H
 
typedef struct CRAZY
{
    unsigned char Secret[32]; // null-terminated string
} _SECRET;
 
#ifndef SECRET_INITIALIZED
_SECRET g_Secret[] =
{
{0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
{0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
{0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
{0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
};
#define SECRET_INITIALIZED
#else
extern _SECRET g_Secret[];
#endif
    unsigned char* getArray()
    {
        
        return (unsigned char*) g_Secret;
   }
 
#endif

Open in new window

0
Infinity08Commented:
>> When I do that, I'll get g_Secret already defined in blah.obj linking errors.

That's because the header file is included more than once in the project, so if you want to put data or function implementations in the header file, you will have multiple definitions.
0
evilrixSenior Software Engineer (Avast)Commented:
>> wondering if this can be done without use of a cpp file
See http:#20876331

This will work quite happily either with or without .cpp file. Also, since it's all known at compile time the compiler will probably optimize it all away if you make getArray inline (you'll need to if you put its body in the header). This isn't to say the I8's suggestion isn't a good one BTW :)
0
DJ_AM_JuiceboxAuthor Commented:
Yeah checking yours out now evil, seems to work
0
Infinity08Commented:
>> No, not with the header guards.

header guards only work on file level, not on project level. If more than one compilation unit includes the header file, you have a multiple definition.
0
peetmCommented:
Haven't you got to be careful not to return the address of a frame variable here?
0
itsmeandnobodyelseCommented:
>> wondering if this can be done without use of a cpp file

#ifndef SECRET_H
#define SECRET_H
 
struct SECRET
{
    unsigned char secret[32]; // null-terminated string

    static SECRET& getSecret()
    {
      static SECRET s_secret[] =
     {
      {0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
      {0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
      {0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
      {0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
    };
    return s_secret;
  }
};
#endif // SECRET_H


A few remarks:

- when making it a static class member you can implement it in the class header without further protections
- when using a static variable in a function you could return a reference only
- if you don't want a static variable (???) you could return it by value.


A pure preprocessor solution (not recommended) would be

#define SECRET_ARR \
     {\
      {0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},\
      {0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},\
      {0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},\
      {0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},\
    }

which could be used locally like

  void anyfunc()
  {
        SECRET secret[] = SECRET_ARR;
        ....

  }


Regards, Alex
0
DJ_AM_JuiceboxAuthor Commented:
The solution evilrx had seems the best for my circumstances - just a few questions on it:

1) The data structure I need actually is a double array, and looks like:

typedef unsigned char array_t[4][32];
struct my_array
{
    array_t data_;
};
 
my_array getArray()
{
    my_array help = {{ 1, 2, 3}};
    return help;
}

so how can I initialize it on the one line as shown in "my_array help = {{ 1, 2, 3}};" ? I keep trying standard 2d array initialization like help = { {1,2,3), {4,5,6} } but the compiler keep complaining about too many initializers.


Also, is just returning an instance of the structure safe, I mean its memory won't go out of scope once I return it from that function right?

Thanks
0
evilrixSenior Software Engineer (Avast)Commented:
>> The data structure I need actually is a double array, and looks like
See below

>> Also, is just returning an instance of the structure safe, I mean its memory won't go out of scope once I return it from that function right?
Perfectly safe. It is returned by copy. A struct, like a class, has an implicitly defined copy constructor. Also, the changes are the copy won't even happen (even if not inline) since it'll use NRVO (named return value optimization) to avoid this.

http://msdn2.microsoft.com/en-us/library/ms364057(VS.80).aspx
typedef unsigned char array3_t[4][3];
 
struct my_array
{
	array3_t data_;
};
 
 
my_array getArray()
{
	my_array help = {{ {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}}};
	return help;
}
 
 
int main () {
	my_array a = getArray();
	return 0;
}

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.