MrSpreadsheet
MrSpreadsheet

Reputation: 58

Passing structs holding static arrays in C++

I was wondering if it was okay to pass around/return structs holding statically allocated arrays in C++. For example:

typedef struct t{
    char name[32];
    int id;
}t;

t foo(char name[]){
    t my_t = {name, 0};
    return my_t;
}

int main(){
    t main_t = foo("a struct");
    printf("%s", main_t.name); //is this safe to access? 
    return 0;
}

When it returns the struct by value, I guess it doesn't copy the array name, only the pointer to it.

Edit: Just to clear up some things. I do know that char *var is equal to char var[] in function arguments. I wrote this code up really quickly without even testing it. I know it is definitely not the best code in the world and I wouldn't advice anybody to use it in real life. Ideally I would allocate the struct dynamically and pass around a pointer, however, I am teaching a person to program in C/C++. It is for a national exam which doesn't require a person to know dynamic allocation or pointers for that matter, that is why * are not really used at all.

The question is really about whether it is okay to return a struct holding a statically allocated array.

Shall we use this piece of code instead:

#include <iostream>

struct t{
    char name[32];
    int id;
};

t foo(int id){
    t my_t;
    my_t.id = id;
    for(char i = 0; i < 31; i++){
        my_t.name[i] = 'a';
    }
    my_t.name[31] = '\0';
    return my_t;
}

int main(){
    t main_t = foo(0);
    std::cout << main_t.name; //is this safe to access? 
    return 0;
}

Upvotes: 0

Views: 362

Answers (4)

M.M
M.M

Reputation: 141554

It's OK to pass around structs that contain arrays. However, this line doesn't do what you think it does:

t my_t = {name, 0};

Using designated initializer syntax, it would be equivalent to:

t my_t = {  .name[0] = name;  .name[1] = 0; };

The first member of t is an array with 32 elements, so the first 32 initializers are applied to those 32 chars. Unless you use some more braces, but you still need one initializer per element, there's no magic way to get a strcpy out of brace-enclosed initializers.

You should get a compiler error about initializing a char with a pointer.

Upvotes: 0

barak manos
barak manos

Reputation: 30136

  1. There is no static array in your code.

  2. When you return a t instance by value, it will copy the contents of the array.

  3. The problem is with how you're initializing the t instance, not with how you're returning it.


Change this:

t my_t = {name,0};

To this:

t my_t = {0};
strncpy(my_t.name,name,sizeof(my_t.name)-1);

Or to this, if you want to avoid the use of library functions:

int i;
t my_t;
for (i=0; i<sizeof(my_t.name)-1 && name[i]!=0; i++)
    my_t.name[i] = name[i];
my_t.name[i] = 0;
my_t.id = 0;

Upvotes: 1

xtofl
xtofl

Reputation: 41509

It can be done.

But it shouldn't be done: alternatives are std::string and std::array. You get your copy, allocation, deallocation etc... for free!

struct t {
    std::string name;
    int id;
    std::array<int, 10> integers;
};

...

t main_t = {"a struct"};
main_t.integers[5] = 5;
t copy = main_t;
assert( copy.name == "a struct" );
assert( copy.id == 0 );
assert( copy.integers[5] == 5 );

Upvotes: 2

legends2k
legends2k

Reputation: 32884

You've an error in your program; you're trying to copy a pointer to an array, instead you should copy the contents pointed to by the pointer into the array. It should be like this

#include <algorithm>
#include <cstring>

struct t
{
    char name[32];
    int id;
};

t foo(const char *name)
{
    t my_t = {};
    const size_t len = std::strlen(name);
    const size_t max_len = sizeof(t::name) / sizeof(t::name[0]) - 1u;
    std::copy(name, name + std::min(len, max_len), my_t.name);
    return my_t;
}

int main()
{
    t main_t = foo("a struct");
    printf("%s", main_t.name);
}

As for your question

I was wondering if it was okay to pass around/return structs holding static arrays in C++

Yes, it's ok, the whole struct will get copied (or moved, depending on the type) to the variable at the calling end.

Upvotes: 0

Related Questions