Gajendra Bagali
Gajendra Bagali

Reputation: 177

memcpy for copying a fixed length buffer into a structure

I have this sample code:

struct
{
    char a[2];
    char b[2];
} buff;

char buffer1[5] = "ABCD";

To copy the buffer1 to structure members, I am doing like this:

char c[3],d[3];
memcpy(&buff,buffer1,4);
sprintf(c,"%2.2s",buff.a);
sprintf(d,"%2.2s",buff.b);
printf("c=%s,d=%s",c,d);

When I print the variables c and d, I am getting the values in c and d variable properly as: c="AB" and c="CD".

Well my question is, even though I am getting the output properly, will memcpy affect anything related to null character termination or have other unexpected memory-related consequences?

Upvotes: 5

Views: 11986

Answers (4)

gsamaras
gsamaras

Reputation: 73366

buffer1 is null terminated. However, the data members of buff are not, since you don't append a null terminator on them. Moreover, you don't have space for the null terminator!

So, no it won't affect it, since it's not there. You will get unexpected results when you try to use the functions of stdio.h, which expect a null terminated string.


Also, you might want to check my example here, about looping in a struct, that it's somehow relevant. I would suggest you to copy to one data member at a time and not in one go.

Upvotes: 1

Grzegorz Szpetkowski
Grzegorz Szpetkowski

Reputation: 37914

The are two issues here:

1) As mentioned in comments you likely forget to include space for the ending '\0' (i.e. NUL in ASCII) terminator character. The %s format specifier for printf function expects that character string is in valid form. However nothing stops you from printing as sequence of characters, like here:

#include <stdio.h>
#include <string.h>

struct {
    char a[2];
    char b[2];
} buff;

char buffer1[5] = "ABCD";

int main(void)
{
    memcpy(&buff, buffer1, 4);

    printf("First member: %c%c\n", buff.a[0], buff.a[1]);
    printf("Second member: %c%c\n", buff.b[0], buff.b[1]);

    return 0;
}

2) A more serious issue is that compiler may include arbitrary padding between struct members (as well as after last member), so memcpy may not work as expected. Instead of copying like that (as it may put bytes from array into a unused "wholes"). I would suggest individual copies of each member or maybe using offsetof() macro.

From N1570 6.7.2.1/15 Structure and union specifiers:

There may be unnamed padding within a structure object, but not at its beginning.

and 6.7.2.1/17:

There may be unnamed padding at the end of a structure or union.

Hence, you should split your memcpy into two calls, for instance:

memcpy(&buff.a, buffer1, 2); /* or replace 2 with sizeof buff.a */
memcpy(&buff.b, buffer1+2, 2);

Upvotes: 7

too honest for this site
too honest for this site

Reputation: 12263

That might not work as expected. There might be padding bytes between the fields in a structure. These are inserted between fields to have the next field start at a certain address-offset. This is mostly the word-size of the CPU or the bus-size, or a multiple thereof for cache-alignment.

This can be true even for char [], as that would allow to efficiently moves/copy such arrays using word-transfers.

For other types, padding is very likely and additionally you have to care about endianess.

Remember also that memcpy & friends exactly do what their names imply: they operate on a block of memory. The do not care about strings, they do not have an idea about "strings". Inserting any NUL-bytes would render them useless, so they don't.

Note that this approach is similar to casting incompatible pointer types. There are few places you are safe, but most times this is the road to hell (aka undefined behaviour).

Upvotes: 1

rabi shaw
rabi shaw

Reputation: 441

#include<stdio.h>
#include<string.h>

struct
{
        char a[2];
        char b[2];
}buff;

int main ( void )
{

        char buffer1[4] = "ABCD";

        memcpy ( &buff , buffer1 , 4 );

        printf ( "\n%s\n ", buff.a );
        printf ( "\n%s\n ", buff.b );

        return ( 0 );
}

o/p-->
 rabi@rabi-VirtualBox:~/rabi/c$ gcc 16.c 
rabi@rabi-VirtualBox:~/rabi/c$ ./a.out 

ABCD

CD
 rabi@rabi-VirtualBox:~/rabi/c$

 #include<stdio.h>
#include<string.h>

struct
{
        char a[3];
        char b[3];
}buff;

int main ( void )
{
        char buffer1[4] = "ABCD";

        memcpy ( &buff.a , &buffer1[0], 2 );
        buff.a[2]='\0';
        memcpy ( &buff.b , &buffer1[2], 2 );
        buff.b[2]='\0';

        printf ( "\n%s\n ", buff.a );
        printf ( "\n%s\n ", buff.b );

        return ( 0 );
}

o/p--->
 rabi@rabi-VirtualBox:~/rabi/c$ gcc 15.c 
rabi@rabi-VirtualBox:~/rabi/c$ ./a.out 

AB

CD
 rabi@rabi-VirtualBox:~/rabi/c$ 

Upvotes: -1

Related Questions