0

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?

8
  • 2
    Why don't you use a struct? Commented Feb 13, 2016 at 12:43
  • I need the padding 0's, not just a struct of strings Commented Feb 13, 2016 at 12:44
  • Your original approach is fine. If there are lot of these things, you might want to create a DSL and generate C code from that. Commented Feb 13, 2016 at 12:46
  • 2
    @susdu about the zero padding: Unlike popular belief, strncpy is for this exactly. It will pad with zeros. Commented Feb 13, 2016 at 12:46
  • 1
    @susdu: There's no such thing as a "string" in C, there are only char arrays. It sounds like a sruct and strncpy is exactly what you need here. Commented Feb 13, 2016 at 12:59

4 Answers 4

3

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");
Sign up to request clarification or add additional context in comments.

3 Comments

You can access whole structure as char[] rather than doing (char*) &f
But the only thing you use full_string for is to memset() the whole structure, and you don't need a cast for that - you can just do memset(&f, 0, sizeof f).
And of course, you don't need memset() at all. Just initialize the whole thing to all zeros with f = {{0}}.
1

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);

1 Comment

The original approach to offset handling was so much better ("advance the pointer each time by the field size"). With your approach adding a new field in the middle or code-reviewing is a PITA.
1

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.