susdu
susdu

Reputation: 862

How to create a multiple null-terminated char array?

I have a char array and I want it to have a certain format, for example:

(first 4 bytes) block type
(next 4 bytes) error code
(next 32 bytes) email address
(next 64 bytes) home address
(next 32 bytes) Full Name

and so forth. About 45 different fields that are padded with 0's to field size. I can use memcpy and advance the pointer each time by the field size but it seems like a tedious task and an ugly code. Maybe a more clever and elegant way to create such a format?

Upvotes: 0

Views: 553

Answers (4)

Gilbert
Gilbert

Reputation: 3776

To add to Nick's response, in C, but not C++, you can skip the union and directly zero the structure:

struct format_entry
{
    char block_type[BLOCK_TYPE_SIZE];
    char error_code[ERROR_CODE_SIZE];
    char email_address[EMAIL_ADDRESS_SIZE];
    char home_address[HOME_ADDRESS_SIZE];
    char full_name[FULL_NAME_SIZE];
};
struct format_entry data;

memset( &data, 0, sizeof data );   /* zero-fill structure */

If you need to update just some of the fields later on you might also consider making your own fill routine that assures zero fill.

char *strncpy0( char *target, const char *source, size_t s )
{
    memset( target, 0, s );
    strncpy( target, source, s );
    return target;
}

While the above code is safer for early users of C, to be more efficient you could calculate the number of bytes at the end of target that strncpy() will not touch, then just fill those bytes.

Upvotes: 1

nikartix
nikartix

Reputation: 717

You can do such it using union together with struct:

#define BLOCK_TYPE_SIZE    4
#define ERROR_CODE_SIZE    4
#define EMAIL_ADDRESS_SIZE 32
#define HOME_ADDRESS_SIZE  64
#define FULL_NAME_SIZE     32

struct format_entry
{
    char block_type[BLOCK_TYPE_SIZE];
    char error_code[ERROR_CODE_SIZE];
    char email_address[EMAIL_ADDRESS_SIZE];
    char home_address[HOME_ADDRESS_SIZE];
    char full_name[FULL_NAME_SIZE];
};

union format_union
{
    char full_string[sizeof(struct format_entry)];
    struct format_entry entry;
};

And then you can fill it in like these:

union format_union f;
memset (f.full_string, 0, sizeof f.full_string);
strcpy (f.entry.block_type, "TYPE");
strcpy (f.entry.error_code, "CODE");
strcpy (f.entry.email_address, "[email protected]");
strcpy (f.entry.home_address, "ADDR");
strcpy (f.entry.full_name, "NA ME");

Upvotes: 3

pmg
pmg

Reputation: 108986

strncpy(), despite its name, is not a "string" function

char data[136/* maybe add 1 for extra '\0' */] = {0}; // fill array with zeroes
strncpy(data, "block type", 4);
strncpy(data + 4, "error code", 4);
strncpy(data + 8, "email address", 32);
strncpy(data + 40, "home address ...", 64);
strncpy(data + 104, "Full Name even if it is very very long", 32);

Upvotes: 1

Sraw
Sraw

Reputation: 20234

That's truly a tedious task. But it seems there is no better way.

Maybe you could conceal them into functions and never consider the ugly code inside.

Upvotes: 0

Related Questions