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?
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, "EM#AI.L");
strcpy (f.entry.home_address, "ADDR");
strcpy (f.entry.full_name, "NA ME");
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);
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.
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.
Related
I am novice on the topic, I have unsinged char *buffer
I am trying to inspect it at 3 bytes at a time
I think maybe this can be solved with a 2 dimensional array.
so I tried this -
unsigned char *bytes[3] = {};
*bytes = buffer;
but I see that's a notation to create array of 3 elements of type unsigned char *
is there any way to achieve this without having to memcpy
any pointers are greatly appreciated.
this approach seems to work
typedef struct utf8 {
unsigned char bytes[3];
};
typedef struct utf8 utf8x;
utf8x *xx = (utf8x *) buffer; //buffer is a return from fread (unsinged char *)
if (xx->bytes[0] == 0xe0) {
printf("scratch");
}
however I am still trying to figure out how to compare all the bytes, I guess if I cast xx->bytes to return 3 bytes it should work.
You want to compare three bytes of a buffer at once. You can do this using memcmp() (which a good compiler will optimize out so there is no actual function call). For example:
utf8x *xx = (utf8x *) buff;
if (memcmp(&xx->bytes[0], "\100\50\10", 3) == 0) {
printf("scratch");
}
That will print scratch if the first three bytes are \100 \50 \10.
struct person
{
char age [3];
char * name;
};
char nameBuf[20];
person Natasha;
person * p_person;
p_person = &Natasha;
Natasha.name = nameBuf;
createPerson (person * resultingPerson, int p_age, const char * p_name)
{
sprintf(resultingPerson->age, "%03d", p_age);
strncpy(resultingPerson->name, p_name, strlen(p_name));
}
createPerson (p_person, 29, "Chelsea");
This code fails at the strncpy call. I can't use dynamically allocated memory. What is the best way to handle this? Why doesn't this work once the name* is pointing to nameBuf[20] a char array and then using strncpy?
Thank you
First off, age is only 3 and you are trying to write 4 bytes 3 digits and a null. Also, normally your length parameter to strncpy is the size of the destination minus 1 so that you have room to add null (if the source string is shorter, strncpy will add the null).
#define NAMEBUFSIZ 20
char namebuf[NAMEBUFSIZ];
typedef struct person
{
char age [3];
char *name;
} person;
person Natasha;
person * p_person;
p_person = &Natasha;
p_person->name = namebuf;
createPerson (person * resultingPerson, int p_age, const char * p_name)
{
char tmpbuf[5];
snprintf(tmpbuf, sizeof(tmpbuf), "%03d", p_age);
memcpy(resultingPerson->age, tmpbuf, sizeof(resultingPerson->age));
resultingPerson->name[NAMEBUFSIZ-1] = '\0';
strncpy(resultingPerson->name, p_name, NAMEBUFSIZ-1);
}
createPerson (p_person, 29, "Chelsea");
It's still not clean, though. Can you guarantee the age will be reasonable, and that only short names (19 or fewer characters) are passed?
NOTE: changed sprintf to snprintf as the comment below is correct, sprintf is quite unsafe as your code example demonstrates
#chqrlie - you helped my track down my problem. My problem was that I didn't want a string, only a char array. When I was using sprintf it was clobbering my char * name that I had originally pointed to nameBuf[] by writing the final null char, which I was not expecting. I put it through a debugger and watched the address to the buffer change. I didn't know why that was happening until I read your comment.
I ended up writing my own itoa, without a null char, then ended by using memcpy().
Thank you for your help!
I would like to ask how to add one char to a buffer. For example:
char buffer[50];
char one_symbol;
How to add one_symbol to buffer? I don't know how long the buffer is at the time, so I cant just write, for example buffer[5] = one_symbol;
Thanks.
You need to do something to keep track of the length of the data in the buffer.
You have a couple of choices about how to do that. Strings store data in the buffer (a NUL byte) to signal where there data ends. Another possibility is to store the length externally:
typedef struct {
char data[50];
size_t len;
} buffer;
This latter is particularly preferable when/if you want to allow for data that itself might include NUL bytes. If you don't want your buffer size fixed at 50, you can go a step further:
typedef struct {
size_t allocated;
size_t in_use;
char data[];
};
Note that this uses a flexible array member, which was added in C99, so some older compilers don't support it.
Keep track or the buffers current size. You can do it by adding a new variable for that.
Something like:
char buffer[50];
size_t current_size = 0; /* Buffer is of size zero from the size */
/* ... */
/* Add one character to the buffer */
buffer[current_size++] = 'a';
Edit: I am not sure if this code does what I think it does. Could someone tell me how to test it? I.e. what should the buffer in my main function look like? I am assuming that a buffer has data of two fields in the following order type(16 bits), length(32 bits). I'm assuming that the buffer is read in from a file and each of the fields is separated by a space. The fields are stored in network byte order and when I read them I have to convert them back to host byte order.
I'm expecting that the code will read the contents from the file (which should be in network byte order) and display the contents in host byte order. I'm a bit confused about type conversions and what the network byte order will be inside of a file, so I don't know what values to use to test it. Also, I'm not sure if my code is written correctly, could someone who does this sort of thing or knows a bit more about such conversions tell me if my code is correct?
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printRecords(char *buffer)
{
unsigned int recordType;
unsigned long recordLength;
char *data;
char *index;
if (!buffer)
printf("Empty buffer\n");
while(*buffer)
{
memcpy(&recordType,(const void *) buffer,2);
buffer += 3;
recordType = ntohs(recordType);
printf("Record type normal: %u\n",recordType);
memcpy(&recordLength,(const void *) buffer,4);
buffer += 5;
recordLength = ntohl(recordLength);
printf("Record Length normal: %l\n",recordLength);
break;
}
}
void main()
{
char * buffer = "0000000000000001 00000000000000000000000000000001";
printRecords(buffer);
}
char *buffer = malloc(sizeof(buf));
sizeof means "size of buf's type", ie the size of a pointer to char; you probably want
malloc(strlen(buf) + 1); /* 1 for trailing '\0' */
Then you are mistaking the value of the bytes for their conversion to string:
"256" is byte '2' followed by byte '5' and '6' -- '2' is not equals to 2, '5' is not equals to 5 etc.
The 256 you are talking about is 00000001 00000000 instead (try dumping the bytes to stdout and you'll see).
Also, recordType should be of type uint16_t, not unsigned -- you're never too paranoid.
EDIT: atoi takes a pointer to char, as in
atoi("123")
not a pointer to int!
I have got some data in a buffer and want to put those data in an array.
typedef struct chunk
{
char data[300]; /* the bufferr. */
} CHUNK;
char *buffer, CHUNK c [100];
Assuming I have got data into the buffer, how can I put 300 char per chunk? I'm new to C so please explain me with simple example.
Thanks,
Kevin
The declaration is invalid, but I think you mean:
typedef struct chunk
{
char data[300]; /* the bufferr. */
} CHUNK;
char *buffer;
CHUNK c [100];
If I understand your question correctly (which I'm far from certain that I do), the code would be something like:
int j = 0;
char *bp = buffer;
while (*bp)
{
strncpy (c [j] .data, bp, 300); // copy data into next item
bp += strlen (bp);
++ j;
}
In C, you can copy memory from one area to another using memcpy(). The prototype for memcpy() is:
void *memcpy(void *dst, const void *src, size_t n);
and the description is that it copies n bytes from src to dst, and returns dst.
So, to copy 300 bytes from b to a where both a and b point to something useful, b has at least 300 bytes of data, and a points to at least 300 bytes of space you can write to, you would do:
memcpy(a, b, 300);
Now your task should be something along the lines of:
typedef struct chunk
{
char data[300];
} CHUNK;
char *buffer;
CHUNK c[100];
size_t i;
/* make buffer point to useful data, and then: */
for (i=0; i < 300; ++i)
memcpy(c[i].data, buffer+i*300, 300);
You can use strncpy.
strncpy( data, buffer, 299 ) ;
Leaving the last index for the termination character '\0'. Or make the array size 301 and then use strncpy for 300 elements.