I been working in a project for my Data Networks class and they ask me to concatenate a header like this:
struct ip
{
unsigned long a;
unsigned long b;
unsigned int l;
} IP;
And a message which it's a char* let's say "Hello".
So, I use this method to concatenate those two in a single char*:
memcpy(sendBuf, (void*)&sendHeader, sizeof(sendHeader));
memcpy(&sendBuf[sizeof(sendHeader)], readMessage, lengthMessage);
With lengthMessage being the number of characters of the message +1 which is the null termination character.
So, sendBuf it's defined like this:
char sendBuf[BUFLEN + 1] // BUF_LEN = 128
And then I put this char* in a queue defined like this:
concurrency::concurrent_queue<char*> IP_in_queue;
So, I want to check if the information it's correct, so I just check everything:
char* s;
IP_in_queue.try_pop(s);
numbytes = sizeof(s);
// Copy from buf to the header
memcpy( (void*)&readHeader, s, sizeof( IP_PACKET_HEADER_T));
// Copy message part
memcpy( sendedString, &s[sizeof(IP_PACKET_HEADER_T)], numbytes - sizeof(IP_PACKET_HEADER_T));
// Append \0 to the end
sendedString[numbytes - sizeof(IP_PACKET_HEADER_T)] = '\0';
So, before I queue my char*, we know that the size of sendBuf is 129, but when I check the number of bytes after I dequeue it's way too different, the value of number of bytes it's 4, but even in that way I get the information right, so I don't understand that, maybe I missing some important things, but the variable numbytes shouldn't be at least more?
I hope I made myself clear and maybe someone can explain me this a little bit better.
Thanks
sizeof does not tell you the length of the string - it tells you the size of the type char*, which on a 32-bit machine is 4 bytes. You want strlen, the number of bytes in the string.
But even that isn't what you want. Your structure IP can have nulls in it, so even strlen won't give you a correct answer. If you put your string first instead of last you can fix that, but I'd consider that kind of a hack. You should add the size explicitly to the start of your message.
Related
I'm required to save data, which happens to be a char array of 4096 characters tops, in a specified memory address.
So here i get the memory address from a uint32_t into the void* ptrAddress
uint32_t number = 1268;
void* ptrAddress = &number;
and here i try to copy the array of As, which works! but not really, because i get some garbage in the middle
char tryArray[4096];
for(int i = 0; i < 4095; i++ ){
tryArray[i] = 'A';
}
//EDIT: added the null terminator (forgot to do that)
tryArray[4095] = '\0';
char* copy = strcpy(ptrAddress, (char*)tryArray);
printf("lets see: %s\n", copy);
output (imagine 4096 As and 'garbage' as some garbage character):
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'garbage''garbage''garbage'AAAAAAAAAAAAAAAAA
And after that i get a seg fault
What am i doing wrong? If there's anything more you need to know from the code or my intentions with it, please tell me!
You have a couple of problems.
First, this code:
uint32_t number = 1268;
void* ptrAddress = &number;
Doesn't make a pointer to memory address 1268, like you seem to indicate you want it to. It makes a pointer to the integer where that 1268 is stored. You then overrun that storage by a lot, causing undefined behaviour, so after that it's game over.
If you want a pointer to a specific memory address:
void *ptrAddress = (void *)0x1268;
Make sure that address is legit in your environment/address space, though!
Second, strcpy works on null-terminated strings. You should probably use memcpy if you plan to work with a 4096 byte (non-null terminated) buffer. Note that means you can't print using printf (at least the way you're trying).
printf("%-4096s");
Should do it though.
I have a struct carrying multiple members with different type. I want to copy this struct to a buffer, then concatenate a message for later use (separate them and read the struct and message, which I didn't do it here). Here is my code.
#define DAT "d"
#define ACK "a"
#define SYN "s"
#define FIN "f"
#define RST "r"
typedef struct Headers { //total 20 bytes
unsigned char _magic_[7];
unsigned char _type_[1];
union {
unsigned int _seq_; //4 bytes
unsigned int _ack_; //4 bytes
} no;
unsigned int _length_; //4 bytes
unsigned short _size_; //2 bytes
} Header;
int main() {
Header receiver_header;
char buffer[1024];
strcpy(receiver_header._magic_, "ABCDEF");
strcpy(receiver_header._type_, DAT);
receiver_header.no._ack_ = 0;
receiver_header._length_ = 900;
receiver_header._size_ = 10240;
char foo[] = "A random message";
memcpy(buffer, &receiver_header, sizeof(Header));
strcat(buffer, foo);
printf("%s\n", buffer);
}
And the output is
ABCDEFA random message
My questions are
Do you need to cast the members to same type in order to copy them into the buffer?
Why is the rest of the members disappeared in the buffer even I have declared the correct pointer of the source and length of it?
The first member of your Header, _magic_, holds 7 chars. You copied 6 chars ("ABCDEF") followed by a null character. strcat copies the source string into the destination string at the first null character it encounters. Therefore, it appends "A random message" right after the first six bytes of the Header. If you want to append the message after the entire struct, you need to specify an offset to copy to, like so.
strcpy(buffer + sizeof(Header), foo);
However, it won't print the entire struct since the null character is still right after "ABCDEF", even though foo has been appended at the correct offset. If you want to print everything in your struct, just print out each member explicitly, like so.
printf("%s %c %u %u %hu %s",
receiver_header._magic_,
receiver_header._type[0],
reveiver_header.no._ack_,
receiver_header._length_,
receiver_header._size_,
foo);
Do you need to cast the members to same type in order to copy them into the buffer?
No. memcpy() can copy the whole representation of any object. But you do have some other apparent misconceptions and strangeness:
If Header._magic_ is meant to hold a string then its element type should be char, not unsigned char. On the other hand, if it's meant to hold binary data then you should not use strcpy() to copy data into it.
Header._type_ has space for a single byte, but you strcpy() a one-character string into it. The string requires two bytes when you count the terminator; these don't both fit into _type_. Probably you should perform an ordinary assignment of a single (unsigned) char instead.
The struct representation that you copy into the buffer is not collectively the contents of a C string, if only on account of having internal null bytes. Therefore, you cannot safely append to it with strcat(). More generally, you ought not be manipulating general data with string functions.
It is also unreasonable to try to print the structure representation as if it were a string. Even if there were no internal null bytes, but there were a terminating null byte, your struct has numeric fields. Their representation is binary, not textual, and printing them as if they were textual will not produce anything useful.
Why is the rest of the members disappeared in the buffer even I have declared the correct pointer of the source and length of it?
Because you overwrote them when you strcat()ed the message onto the buffer.
I have a thread which parses incomming characters/bytes one by one.
I would like to store the sequence of bytes in a byte pointer, and in the end when the sequence of "\r\n" is found it should print the full message out.
unsigned char byte;
unsigned char *bytes = NULL;
while (true){ // thread which is running on the side
byte = get(); // gets 1 byte from I/O
bytes = byte; //
*bytes++;
if (byte == 'x'){ // for now instead of "\r\n" i use the char 'x'
printf( "Your message: %s", bytes);
bytes = NULL; // or {0}?
}
}
You should define bytes as array with size of max message length not a pointer.
unsigned char byte, i;
unsigned char arr[10]; // 10 for example
i=0;
while (true){
byte = get();
arr[i] = byte;
i++;
if (byte == 'x'){
printf( "Your message: %s", arr);
}
}
When you define bytes as a pointer, it points to nothing and writing to it may erase other data in your program, you can make it array or allocate space for it in run time using malloc
Your Code
unsigned char byte;
unsigned char *bytes = NULL;
while (true){
Nothing wrong here, but some things must be cleared:
Did you alloc memory for your bytes buffer? That is, using malloc() family functions?
If so, did you check malloc() return and made sure the pointer is ok?
Did you include stdbool.h to use true and false?
Moving on...
byte = get();
bytes = byte;
*bytes++;
I'm assuming get() returns an unsigned char, since you didn't give the code.
Problem: bytes = byte. You're assigning an unsigned char to an unsigned char *. That's bad because unsigned char * is expecting a memory address (aka pointer) and you're giving it a character (which translates into a really bad memory address, cause you're giving addresses up to 255, which your program isn't allowed to access), and your compiler certainly complained about that assignment...
*byte++ has two "problems" (not being really problems): one, you don't need the * (dereferencing) operator to just increment the pointer reference, you could've done byte++; two, it was shorter and easier to understand if you switched this line and the previous one (bytes = byte) to *bytes++ = byte. If you don't know what this statement does, I suggest reading up on operator precedence and assignment operators.
Then we have...
if (byte == 'x'){
printf( "Your message: %s", bytes);
bytes = NULL;
}
if's alright.
printf() is messed up because you've been incrementing your bytes pointer the whole time while you were get()ting those characters. This means that the current location pointed by bytes is the end of your string (or message). To correct this, you can do one of two things: one, have a counter on the number of bytes read and then use that to decrement the bytes pointer and get the correct address; or two, use a secondary auxiliary pointer (which I prefer, cause it's easier to understand).
bytes = NULL. If you did malloc() for your bytes buffer, here you're destroying that reference, because you're making an assignment that effectively changes the address to which the pointer points to to NULL. Anyway, what you need to clear that buffer is memset(). Read more about it in the manual.
Another subtle (but serious) problem is the end of string character, which you forgot to put in that string altogether. Without it, printf() will start printing really weired things past your message until a Segmentation Fault or the like happens. To do that, you can use your already incremented bytes pointer and do *bytes = 0x0 or *bytes = '\0'. The NULL terminating byte is used in a string so that functions know where the string ends. Without it, it would be really hard to manipulate strings.
Code
unsigned char byte;
unsigned char *bytes = NULL;
unsigned char *bytes_aux;
bytes = malloc(500);
if (!bytes) return;
bytes_aux = bytes;
while (true) { /* could use while(1)... */
byte = get();
*bytes++ = byte;
if (byte == 'x') {
*(bytes - 1) = 0x0;
bytes = bytes_aux;
printf("Your message: %s\n", bytes);
memset(bytes, 0, 500);
}
}
if ((*bytes++ = get()) == 'x') is a compound version of the three byte = get(); *bytes++ = byte; if (byte == 'x'). Refer to that assignment link I told you about! This is a neat way of writing it and will make you look super cool at parties!
*(bytes - 1) = 0x0; The -1 bit is to exclude the x character which was saved in the string. With one step we exclude the x and set the NULL terminating byte.
bytes = bytes_aux; This restores bytes default state - now it correctly points to the beginning of the message.
memset(bytes, 0, 500) The function I told you about to reset your string.
Using memset is not necessary in this particular case. Every loop repetition we're saving characters from the beginning of the bytes buffer forward. Then, we set a NULL terminating byte and restore it's original position, effectively overwriting all other data. The NULL byte will take care of preventing printf() from printing whatever lies after the end of the current message. So the memset() part can be skipped and precious CPU time saved!
Somewhere when you get out of that loop (if you do), remember to free() the bytes pointer! You don't want that memory leaking...
I am trying to copy certain parts of a string into other, new strings, but when i try to do it and print the results it gives me weird output.. I really hope someone can help. I have a feeling that it is something about missing pointers.. Here is my source;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getData(char code[], char ware[], char prod[], char qual[])
{
printf("Bar code: %s\n", code);
/* Copy warehouse name from barcode */
strncpy(ware, &code[0], 3);
ware[4] = "\0";
strncpy(prod, &code[3], 4);
prod[5] = "\0";
strncpy(qual, &code[7], 3);
qual[4] = "\0";
}
int main(){
/* allocate and initialize strings */
char barcode[] = "ATL1203S14";
char warehouse[4];
char product[5];
char qualifier[4];
getData(&barcode, &warehouse, &product, &qualifier);
/* print it */
printf("Warehouse: %s\nID: %s\nQualifier: %s", warehouse, product, qualifier);
return 0;
}
EDIT:
The wierd output is:
Bar code: ATL1203S14
Warehouse: ATL
ID: ♫203(♫>
Qualifier: S14u♫203(♫>
I think you meant '\0' instead of "\0" and 3 instead of 4:
ware[4] = "\0";
Try:
ware[3] = 0;
Also the & in getData(&barcode, &warehouse...) are useless. Just use getData(barcode, warehouse...);.
You're writing past the end of the chars in your getData() function. You've defined char product[5], which allocates 5 bytes of memory. That gives you array indexes 0,1,2,3,4. In getData, you write the product's null terminator to index 5, which is past the end of product, and will overwrite the next var's first character.
The same applies for barecode, warehouse, and qualifier.
Arrays in C and C++ are zero-based. The last index is one less than the length. You're setting a value in the memory after the array, for each of the arrays ware, prod and qual.
For example, instead of
char warehouse[4];
ware[4] = "\0";
you'd want:
char warehouse[4];
ware[3] = "\0";
getData(&barcode, &warehouse, &product, &qualifier);
This is not the way you should call getData. getData takes pointers, arrays are automatically converted to pointers, so theres no need to use the address-of operator &.
You should use
getData(barcode, warehouse, product, qualifier);
The sizes of the strings inside main() don't include a place for the sentinel.
You need to have:
char warehouse[5];
char product[6];
char qualifier[5];
Also, You are assigning a pointer to the string "\0" into a character, where you should be assigning the character '\0' itself.
I think I'd do things a bit differently. In particular, strncpy is almost never really useful (I'm reasonably certain it was invented for file names in the original Unix FS, and while it fits their specific requirements quite nicely, those requirements are sufficiently unusual that it's rarely good for much of anything else).
Instead, I'd use sscanf: sscanf(code, "%4c%5c%4c", ware, prod, qual);
Your question does not make it clear whether this is really correct. As others have pointed out, you're writing past the ends of the space you've allocated. Above, I've assumed you specified the number of characters you want to copy, so you'd have to expand each of the allocations by one character to make room for the terminator. Alternative, if you've already left room for the terminator and want one fewer character copied, you'd have to reduce each of the lengths above by one so the format string would be "%3c%4c%3c".
I radically re-edited the question to explain better my application, as the xample I made up wasn't correct in many ways as you pointed out:
I have one pointer to char and I want to copy it to another pointer and then add a NULL character at the end (in my real application, the first string is a const, so I cannot jsut modify it, that's why I need to copy it).
I have this function, "MLSLSerialWriteBurst" which I have to fill with some code adapt to my microcontroller.
tMLError MLSLSerialWriteBurst( unsigned char slaveAddr,
unsigned char registerAddr,
unsigned short length,
const unsigned char *data )
{
unsigned char *tmp_data;
tmp_data = data;
*(tmp_data+length) = NULL;
// this function takes a tmp_data which is a char* terminated with a NULL character ('\0')
if(EEPageWrite2(slaveAddr,registerAddr,tmp_data)==0)
return ML_SUCCESS;
else
return ML_ERROR;
}
I see there's a problem here: tha fact that I do not initialize tmp_data, but I cannot know it's length.
For starters, you are missing a bunch of declarations in your code. For example, what is lungh? Also, I'm assuming you initialized your two pointers so they point to memory you can use. However, maybe that's not a safe assumption.
Beyond that, you failed to terminate your from string. So getting the length of the string will not work.
There seems to be numerous errors here. It's hard to know where to start. Is this really what your actual code looks like? I don't think it would even compile.
Finally, there seems to be a bit of confusion in your terminology. Copying a pointer is different from copying the memory being pointed to. A pointer is a memory address. If you simply copy the pointer, then both pointers will refer to the same address.
I would create a copy of a string using code similar to this:
char *from_string = "ciao";
char *to_string;
int len;
len = strlen(from_string);
to_string = (char *)malloc(len + 1);
if (to_string != NULL)
strcpy(to_string, from_string);
Be fully aware that you do not want to copy a pointer. You want to copy the memory that is pointed to by the pointer. It does sound like you should learn more about pointers and the memory environment of your system before proceeding too much farther.
When you say tmp_data = data, you are pointing tmp_data to the same memory pointed to by data. Instead, you need to allocate a new block of memory and copy the memory from data into it.
The standard way to do this is with malloc. If you do not have malloc, your libraries may have some other way of acquiring a pointer to usable memory.
unsigned char * tmp_data = malloc(length + 1);
if(tmp_data != 0) {
memcpy(tmp_data, data, length);
tmp_data[length] = 0;
// ...
free(tmp_data);
}
You could also use a fixed-size array on the stack:
unsigned char tmp_data[256];
if(length >= sizeof(tmp_data)) length = sizeof(tmp_data) - 1;
memcpy(tmp_data, data, length); // or equivalent routine
tmp_data[length] = 0;
C99 introduced variable-length arrays, which may be what you seek here, if your compiler supports them:
unsigned char tmp_data[length];
memcpy(tmp_data, data, length); // or equivalent routine
tmp_data[length] = 0;