Copy array of structs in one go

Discussion in 'C Programming' started by dude.jimbo, Apr 15, 2014.

  1. dude.jimbo

    dude.jimbo Guest

    I want to copy an array of structs (fixed size array and struct). What I "have" now (yes, this is indeed a non-compilable extract, and yes, "BOOL" is a big no-no, and no, I obviously don't have two globals that should contain the exact same thing):

    struct arrayStruct
    {
    int a;
    int b;
    BOOL c;
    }

    struct arrayStruct dest[ARR_SIZE];
    struct arrayStruct source[ARR_SIZE];

    void SomeCode(void)
    {
    /* ... */
    for (i=0; i<ARR_SIZE; i++)
    {
    dest.a = source.a;
    dest.b = source.b;
    dest.c = source.c;
    }
    }

    This can't be right.

    Well, that is to say, technically, it ~is~ right, but surely it can be faster
    (not to mention that the real example has plenty more members in the struct).

    You'd think I could do something along the lines of:

    for (i=0; i<ARR_SIZE; i++)
    {
    dest = source;
    }

    Or, even better:

    dest = source;

    OK, OK, *you* don't think you could do that. But *I* think I should be able to
    do something ~like~ that. So I tried, and obviously, it failed.

    No, in reality, ~I~ failed. But my fragile ego doesn't like to see it spelled
    out like that.

    ("*dest = *source" sort of worked, but only for the first entry in the arrays)

    Can someone help me out with *working* syntax? And yes, I should hang my head in
    shame. Apart from the fact that I don't normally program in C. In fact, I don't
    normally program at all. Oh the joys of looking smart whilst seated in front of
    a PC...

    Jimbo
     
    dude.jimbo, Apr 15, 2014
    #1
    1. Advertisements

  2. dude.jimbo

    BartC Guest



    Try:

    memcpy(dest,source,sizeof(dest));

    Note this will copy any padding too.
     
    BartC, Apr 15, 2014
    #2
    1. Advertisements

  3. dude.jimbo

    Stefan Ram Guest

    #include <stdio.h> /* printf */

    struct s { struct { int a; int b; }a[ 3 ]; };

    int main()
    { struct s const s0 = { { { 1, 2 }, { 4, 3 }, { 9, 7 } } };
    struct s s1; s1 = s0; printf( "%d (9)\n", s1.a[ 2 ].a ); }
     
    Stefan Ram, Apr 15, 2014
    #3
  4. dude.jimbo

    dude.jimbo Guest

    Op dinsdag 15 april 2014 16:42:11 UTC+2 schreef :
     
    dude.jimbo, Apr 15, 2014
    #4
  5. dude.jimbo

    dude.jimbo Guest

    Try:
    Well for <insert-entity-here> <insert-foul-language-here>!!1!!

    <keep-going-for-a-while>!!!1!el3ven!

    That - obviously - worked.

    Of course, not only being an idiot but a stubborn know-it-all too,
    I just ~had to~ change it to:

    memcpy(dest, source, sizeof(struct arrayStruct));
    /* (Note. The. Spaces. I'd fit right in into any dev-team; if I could develop,
    * that is) */

    which worked too, and looks prettier. No, really, it does. Not only because
    I came up with it (*), but also because "dest" in reality looks something like
    "someHorriblyNamedPointer_withRandomUnderScorezzzPtr_p->el.thisBeMember_here.OfSomethingElsE.dest",
    if you catch my drift. Well, you probably *don't* catch my drift (nor do I wish
    it upon you), but that's because I'm mentally defective when it comes to these
    things.

    In fact, I'm mentally defective about a lot of other things too, but
    that's off-topic. Although my shrink does say that talking about it helps.
    It doesn't, apart from the fact that he keeps being paid, so I guess he
    has some sort of point. And a villa and an Aston and a mistress, but I'm
    drifting off-topic again...

    Also, padding is good. It must be, because they've lined my bedroom with it.

    I tried reading that, but that had me grabbing for the Dafalgan.
    I then tried to ~understand~ what you were trying to show, but that had me
    grabbing for the bottle of Whisky, to swallow down even more Dafalgan. It
    might have been whiskey too, but I wasn't paying attention since I was in
    the process of passing out. Yes, more bills for another doctor. Who'd have
    thought that working would cost so much money?

    Anyway, are you saying that "dest = source" should have worked, provided
    I first perform what looks like magic on the arrayStruct definition?

    Not being the scary kind (thanks to medication), I tried your snippet,
    which led to some explosions nearby (you weren't trying to be funny,
    were you?), but beyond that s1 did indeed contain a copy of s0,
    after 's1 = s0'.

    So back to my code, and why it didn't work there.

    Not being the lazy kind (thanks to being overlooked behind my back), I tried to
    "purify" your convoluted snippet - it must be convoluted, because why else
    can't I understand it? - to the following:

    struct s {
    int a;
    int b;
    };

    struct s s0[3] = { { 1, 2 }, { 4, 3 }, { 9, 7 } };
    struct s s1[3];

    int main(void)
    {
    s1 = s0;
    printf( "%d (9)\n", s1.a[ 2 ]);
    }

    which had me back to square one with "incompatible types in assignment s1=s0".

    Besides which, I don't think I'm at liberty to change arrayStruct with
    magic. Even if it is functional magic. A bit like Copperfield scoring that
    German chick. I mean really, it can't have been his looks. But I'm
    drifting again...

    Agrh, so many problems, so little whisk(e)y...

    Jimbo.


    (*) OK, OK, I saw it in a manual.
     
    dude.jimbo, Apr 15, 2014
    #5
  6. dude.jimbo

    David Brown Guest

    Note - it helps if you reply to replies, keeping sense of the threads
    and branches in the conversation, rather than making one big reply with
    other things mixed in. That way we can see who wrote what.

    The spacing is good (better than Bart's) - the sizeof part is not good.
    This should be the size of everything you want to copy - i.e.,
    sizeof(dest) or sizeof(source) - not the size of one element of the array.
    Just remember what memcpy does. It takes two pointer parameters and a
    byte count parameter, and copies from the source to the destination. If
    you have complicated parameters here, be careful to get the parts correct.

    memcpy may be more efficient if it knows about alignments. Standard
    memcpy is byte-by-byte, which will be slow, but most toolchains can get
    you a more optimised memcpy if you have enabled optimisation, built-in
    functions, etc. Check this if speed is important.
    Basically, I think what Stefan is trying to say is that assignment
    between structures is allowed. Assignment between arrays is not
    allowed. So you could have written:

    void SomeCode(void) {
    for (int i = 0; i < ARR_SIZE; i++) {
    dest = source;
    }
    }

    This may or may not copy the padding, but it should use quite efficient
    transfer sizes.
     
    David Brown, Apr 15, 2014
    #6
  7. dude.jimbo

    dude.jimbo Guest

    Op dinsdag 15 april 2014 18:07:42 UTC+2 schreef David Brown:
    I know. No really, I do, but I'm doing this through the Google I/F.

    And apparently, Google is paid per line-feed. Or something. So I tried
    to somewhat fake the layout, which of course is only worse but it does
    make me feel good about myself, taking it up to the Big Evil Corp.

    That's my excuse anyway and I'm sticking to it.

    (In reality, I also have no idea how to respond to two posts/points at once,
    and multiple replies ~really~ look sloppy to me)
     
    dude.jimbo, Apr 15, 2014
    #7
  8. Why is BOOL a "big no-no"? If your implementation supports it, it's


    That should work. Did you actually try it?
    Unfortunately, you can't assign arrays in C. But you can assign
    structures.

    But memcpy() is probably a better solution anyway.

    [...]
     
    Keith Thompson, Apr 15, 2014
    #8
  9. [...]

    The point of writing "sizeof(dest)", or "sizeof dest" (the , is that you don't
    have to refer to
    "someHorriblyNamedPointer_withRandomUnderScorezzzPtr_p...".

    And it also has the considerable virtue of being correct. Your "struct
    arrayStruct" (which isn't, and doesn't contain, an array, so you might
    want to pick a better name) is a single element of your "dest" array.
    If you only wanted to copy a single element, you might as well use an
    assignment.

    Your dest array is defined as:

    struct arrayStruct dest[ARR_SIZE];

    so if you insist on using a type name in your sizeof expression,
    it would have to be "sizeof (struct arrayStruct[ARR_SIZE])" --
    which would become invalid if you ever change the type of "dest".
    Using "sizeof dest" is simpler and immune to that particular problem.

    Or you could write:

    memcpy(dest, source, ARR_SIZE * sizeof(struct arrayStruct));

    but then you're repeating even more information that's already available
    in the definition of "dest".

    (And, IMHO, "sizeof dest" is prettier.)
     
    Keith Thompson, Apr 15, 2014
    #9
  10. dude.jimbo

    dude.jimbo Guest

    Op dinsdag 15 april 2014 18:07:42 UTC+2 schreef David Brown:
    You are, of course, quite right, but it was my mistake in mixing up my
    dumbed down example from the top, with the actual code I was trying ~this
    time round~.

    And that actually looked more like (yet another dumbed down example):

    struct arrayStruct
    {
    int a;
    int b;
    bool c;
    }

    struct arrayPlaceHolder
    {
    int a;
    bool b;
    char c[10];
    struct arrayStruct arrayBeHere[ARR_SIZE];
    }

    struct arrayPlaceHolder dest;
    struct arrayPlaceHolder source;

    someCode()
    {
    memcpy(dest, source, sizeof(struct arrayPlaceHolder));
    }

    In which case the sizeof ~is~ correct. And prettier. Well, I dont know
    if it really is correct, I just saw it working without explosions.

    But now I hear you thinking (yes, I'm seeking professional help for the
    voices in my head too):

    "Ohhhhh-Kay.... but then 'dest = source' really would have worked"

    And you'd be right again. But that's because I've been dumbing down
    too much. Or been having too much scotch with Dafalgan. The conclusive
    part of the analysis is that I was mixing two completely different pieces
    of dumbed down code, leading to my above error.

    Anyway, now I'm just rambling (while realising that nobody will
    spot a difference with how it was before).

    This is the key, in essence: """what Stefan is trying to say is that assignment
    between structures is allowed. Assignment between arrays is not"""

    Jimbo.
     
    dude.jimbo, Apr 15, 2014
    #10
  11. dude.jimbo

    dude.jimbo Guest

    Op dinsdag 15 april 2014 18:26:02 UTC+2 schreef Keith Thompson:
    Of course BOOL is not really a big NO-NO (it is, in fact, a char, in my case)

    But I've heard plenty of "booleans-in-C" discussions around the coffee-
    machine - whilst fantasizing about poking out the eyes of the people involved
    by using a rusty spoon - so I thought I'd tried to be funny.

    Obviously, I'm as good at that as I am at writing C.

    Jimbo
     
    dude.jimbo, Apr 15, 2014
    #11
  12. dude.jimbo

    Sjouke Burry Guest


    Or switch to fortran.
    there you can do : dest = source
     
    Sjouke Burry, Apr 15, 2014
    #12
  13. dude.jimbo

    dude.jimbo Guest

    Op dinsdag 15 april 2014 19:08:31 UTC+2 schreef Sjouke Burry:


    Now ~that~ is funny!
     
    dude.jimbo, Apr 15, 2014
    #13
  14. (snip, someone wrote)

    Fortran allows array expressions, which C doesn't.

    PL/I allows both array and structure expressions, or both at
    the same time.

    Adding array expressions to C is complicated by the way C does
    pointers, but structure expressions don't have that problem.

    Seems to me that one could allow:

    struct somestruct a, b, c;

    /* put some values in a and b */

    c = a + b;

    without breaking too much.


    -- glen
     
    glen herrmannsfeldt, Apr 15, 2014
    #14
  15. dude.jimbo

    Stefan Ram Guest

    Welcome to the wonderful world of C++!

    struct somestruct
    { somestruct & operator=( somestruct const & ){ return *this; } }
    a, b, c;

    somestruct operator+( somestruct & a, somestruct const & ){ return a; }

    int main(){ c = a + b; }
     
    Stefan Ram, Apr 15, 2014
    #15
  16. (snip, I wrote)
    Some time ago, I thought about writing all such to do complex
    arithmetic in C++.

    Note that you also have to include the (scaler)+(struct) and
    (struct)+(scalar) for all available scalar types.

    You also need all operators and all library functions.

    I suppose you write a program to generate them all, given the
    structure of the struct in question.

    DCL (x, y, z) 1 somestruct,
    2 a fixed binary(31,0),
    2 b fixed decimal(15,0),
    2 c float binary(53),
    2 d float decimal(10),
    2 e char(100);

    x=3;
    y='4';
    y=y+3.0e1;
    z=x+2*y+sqrt(x-y)*sin(x/3)**'2.5';
    put skip list(x, y, z);

    -- glen
     
    glen herrmannsfeldt, Apr 16, 2014
    #16
  17. dude.jimbo

    James Kuyper Guest

    If you're going to bring C++ into the discussion, std::valarray<T> seems
    like it would be a more relevant example.

    Adding enough C++ features to make anything like that useful would erase
    most of the fundamental distinctions between C and C++. Keeping things
    simple is C's main advantage over C++; removing that distinction would
    remove most of reasons why people still bother using C rather than C++.
     
    James Kuyper, Apr 16, 2014
    #17
  18. dude.jimbo

    Stefan Ram Guest

    »valarray« was intended for vector processors AFAIK,
    but it was never really used for its intended purpose.
    Possibly, because those processors are not that widely
    used today.

    Those who really do vector math with C++ AFAIK use
    third-party libraries like »Blitz++« today.

    But do not despair, help is on the way:

    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3851.pdf

    . Disclaimer: There might not be arithmetic operators for
    vectors and matrices mentioned in that draft, but this seems
    to be a new attempt at multidimensional array support.
    Something that also was intended for »valarray«.

    I wonder if maybe one day someone will write a valarray
    implementation that exploits modern graphic cards as
    vector processors, but I do not know if this is possible.

    C++ can copy ::std::array instances using »=«, but this is
    no surprise, since in the end, AFAIK, this just wraps a C array
    in a struct, so it is the same technique we also can use in C.
     
    Stefan Ram, Apr 16, 2014
    #18
  19. dude.jimbo

    David Brown Guest

    Get a real newsreader - there are plenty of good newsreader programs.
    And there are plenty of free newsservers. I don't want to start a "my
    newsreader is better than your newsreader" thread, but there is almost
    universal agreement that Google's Usenet interface is the worst choice.
    I use Thunderbird and news.external-september.org. Some people might
    prefer other newsreaders and news servers, but that should get you started.
    So you think Google is evil, and therefore try to use their service -
    without them charging you - in such a way as to minimise /their/ income.
    That's a pretty hypocritical definition of "evil". If you want to take
    advantage of Google's services, you should be happy that they have an
    income (within reason) so that they can give you those services.
    It doesn't matter if multiple replies "look sloppy" to you - this is
    Usenet, it has its rules and conventions, and it all works far better if
    people follow them. /Nothing/ looks worse than someone who thinks
    /their/ way of quoting or posting is better than the method used by
    everyone else.

    So get yourself a real newsreader and newsserver, and when you want to
    reply to a post press the "follow up" button on that post. Then we can
    all go back to talking about C :)
     
    David Brown, Apr 16, 2014
    #19
  20. dude.jimbo

    David Brown Guest

    Sometimes people in this group have limited auto-detect in their sense
    of humour. You have to /earn/ the right to make jokes like that, by
    proving over the years that you understand all the pros and cons of
    different types of C booleans (and also when and how to use all-caps
    identifiers). Otherwise the assumption is just that you have
    misunderstood something (that is not an unreasonable assumption, of course).

    Best to add a smiley to avoid confusion :)
     
    David Brown, Apr 16, 2014
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.