I've got function, that saves values that takes in the argument. And I have to implement two ways, to accept the input - as a char* and then via strncpy.
Ie: a . Add("123456/7890", "John", "Doe", "2000-01-01", "Main street", "Seattle");
It works allright, untill I use strncpy:
bool status;
char lID[12], lDate[12], lName[50], lSurname[50], lStreet[50], lCity[50];
strncpy(lID, "123456/7890", sizeof ( lID));
strncpy(lName, "John", sizeof ( lName));
strncpy(lSurname, "Doe", sizeof ( lSurname));
strncpy(lDate, "2000-01-01", sizeof ( lDate));
strncpy(lStreet, "Main street", sizeof ( lStreet));
strncpy(lCity, "Seattle", sizeof ( lCity));
status = c . Add(lID, lName, lSurname, lDate, lStreet, lCity);
//is true
strncpy(lID, "987654/3210", sizeof ( lID));
strncpy(lName, "Freddy", sizeof ( lName));
strncpy(lSurname, "Kruger", sizeof ( lSurname));
strncpy(lDate, "2001-02-03", sizeof ( lDate));
strncpy(lStreet, "Elm street", sizeof ( lStreet));
strncpy(lCity, "Sacramento", sizeof ( lCity));
// notice, that I don't even save it at this point
strncpy(lID, "123456/7890", sizeof ( lID));
strncpy(lDate, "2002-12-05", sizeof ( lDate));
strncpy(lStreet, "Sunset boulevard", sizeof ( lStreet));
strncpy(lCity, "Los Angeles", sizeof ( lCity));
status = c . Resettle(lID, lDate, lStreet, lCity);
status = c . Print(cout, "123456/7890");
//is true
At this point I want to print out values for ID 123456/7890... so Name:John, Surname:Doe etc.
Neverthless It prints out values, that were saved as the last ones:
123456/7890 Freddy Kruger
2002-12-05 Sunset boulevard Los Angeles
2002-12-05 Sunset boulevard Los Angeles
My Add is declared as:
bool Add(const char * id,
const char * name,
const char * surname,
const char * date,
const char * street,
const char * city);
Resettle function is delared similar to Add, it just doesn't take name and surname arguments.
All values are saved to char ** arrays.
Could you please advice me, how to handle this situation, to be able to accept properly both inputs?
Ps: for char* input whole program works allright, so I don't expect any bug there..
Pps: pls don't advice me to use strings or any other constructions I don't use here - I'm very limited on imports, thus I use char* and other stuff...
I don't think you should be using sizeof here. strncpy needs the length of the string(number of chars to be copy from destination string to source string).
sizeof is the size of the pointer (e.g sizrof(IID) = address size, om my system its 4).
I think you need strlen(). Also, this needs to be called on the source pointer, not the destination pointer.
strncpy(lID, "987654/3210", strlen ("987654/3210"));
Be sure that IID is enough long to copy string, otherwise buffer overflow can be problem
read char * strncpy ( char * destination, const char * source, size_t num );, and
Copy characters from string
Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
Thanks to #JonathanLeffler: (The strlen() means the data won't be null-terminated. That's bad. At least copy strlen() + 1 bytes to get the null-terminator)
Note: No null-character is implicitly appended at the end of destination if source is longer than num (thus, in this case, destination may not be a null terminated C string).
Also read about: size_t strlen ( const char * str );
The problem is not in the strncpy() operations. It is in the material you've not shown us:
c.Add()
c.Resettle()
c.Print()
One or more of those has problems, but since we can't yet see them, we can't help you debug them.
Demonstration of strncpy()
There's a discussion of the behaviour of strncpy() in the comments to voodoogiant's answer. Here's a demonstration that:
strncpy(target, "string", strlen("string"));
does not null-terminate the output:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[32];
memset(buffer, 'X', sizeof(buffer));
printf("Before: %.*s\n", (int)sizeof(buffer), buffer);
strncpy(buffer, "123456/7890", strlen("123456/7890"));
printf("After: %.*s\n", (int)sizeof(buffer), buffer);
return(0);
}
Output:
Before: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
After: 123456/7890XXXXXXXXXXXXXXXXXXXXX
(Yes, I'm quite aware that the memset() does not null-terminate the buffer; it doesn't need to for this example because the printing is done carefully.)
As we do not know the datatype of lID et al. and hence the sizeof it is difficult to comment. Besides why not use the string container from STL
Related
I have a string like,
string str="aaa\0bbb";
and I want to copy the value of this string to a char* variable. I tried the following methods but none of them worked.
char *c=new char[7];
memcpy(c,&str[0],7); // c="aaa"
memcpy(c,str.data(),7); // c="aaa"
strcpy(c,str.data()); // c="aaa"
str.copy(c,7); // c="aaa"
How can I copy that string to a char* variable without loosing any data?.
You can do it the following way
#include <iostream>
#include <string>
#include <cstring>
int main()
{
std::string s( "aaa\0bbb", 7 );
char *p = new char[s.size() + 1];
std::memcpy( p, s.c_str(), s.size() );
p[s.size()] = '\0';
size_t n = std::strlen( p );
std::cout << p << std::endl;
std::cout << p + n + 1 << std::endl;
}
The program output is
aaa
bbb
You need to keep somewhere in the program the allocated memory size for the character array equal to s.size() + 1.
If there is no need to keep the "second part" of the object as a string then you may allocate memory of the size s.size() and not append it with the terminating zero.
In fact these methods used by you
memcpy(c,&str[0],7); // c="aaa"
memcpy(c,str.data(),7); // c="aaa"
str.copy(c,7); // c="aaa"
are correct. They copy exactly 7 characters provided that you are not going to append the resulted array with the terminating zero. The problem is that you are trying to output the resulted character array as a string and the used operators output only the characters before the embedded zero character.
Your string consists of 3 characters. You may try to use
using namespace std::literals;
string str="aaa\0bbb"s;
to create string with \0 inside, it will consist of 7 characters
It's still won't help if you will use it as c-string ((const) char*). c-strings can't contain zero character.
There are two things to consider: (1) make sure that str already contains the complete literal (the constructor taking only a char* parameter might truncate at the string terminator char). (2) Provided that str actually contains the complete literal, statement memcpy(c,str.data(),7) should work. The only thing then is how you "view" the result, because if you pass c to printf or cout, then they will stop printing once the first string terminating character is reached.
So: To make sure that your string literal "aaa\0bbb" gets completely copied into str, use std::string str("aaa\0bbb",7); Then, try to print the contents of c in a loop, for example:
std::string str("aaa\0bbb",7);
const char *c = str.data();
for (int i=0; i<7; i++) {
printf("%c", c[i] ? c[i] : '0');
}
You already did (not really, see edit below). The problem however, is that whatever you are using to print the string (printf?), is using the c string convention of ending strings with a '\0'. So it starts reading your data, but when it gets to the 0 it will assume it is done (because it has no other way).
If you want to simply write the buffer to the output, you will have to do this with something like
write(stdout, c, 7);
Now write has information about where the data ends, so it can write all of it.
Note however that your terminal cannot really show a \0 character, so it might show some weird symbol or nothing at all. If you are on linux you can pipe into hexdump to see what the binary output is.
EDIT:
Just realized, that your string also initalizes from const char* by reading until the zero. So you will also have to use a constructor to tell it to read past the zero:
std::string("data\0afterzero", 14);
(there are prettier solutions probably)
I have a char array called names[50]
Basically, I use
strncpy(this->names, names, sizeof(names))
however this will only truncate characters at the end.
How do I truncate characters from the start?
For example, BillSteveLinusMikeGeorgeBillSteveLinusMikeGeorgeGeorge should be teveLinusMikeGeorgeBillSteveLinusMikeGeorgeGeorge
If I have understood correctly then using the string you showed as an example you have to write
strncpy( this->names, names + 5, sizeof(names) - 5 );
You can change the source address for strncpy:
strncpy(this->names, &(names[10]), num_of_chars_to_copy);
Notice that no null-character is implicitly appended at the end of the destination string if the source string is longer than num.
You need to be clear what you want to do... is names[] variable in length from call to call? Is this->names a fixed length? Note that the length for the number of bytes to copy should be the number of bytes available in this->names... Otherwise you run the risk of overflowing the memory.
I designed for you this simple function, You can use it as reference code for more complex issue:
void BackStrCopy(char* src, char* dest, int srcsize, int destsize)
{
if(srcsize >= destsize )
{
do
dest[destsize--] = src[srcsize--];
while( destsize + 1 );
}
}
int main()
{
char* src = "BillSteveLinusMikeGeorgeBillSteveLinusMikeGeorgeGeorge";
char dest[50];
BackStrCopy(src, dest, strlen(src), 25);
}
I tested it end work.
I thing that the function code does not require any comment:)
If my solution help you, please remember to check it as answered.
Ciao
I'm having a string is not null terminated error, though I'm not entirely sure why. The usage of std::string in the second part of the code is one of my attempt to fix this problem, although it still doesn't work.
My initial codes was just using the buffer and copy everything into client_id[]. The error than occurred. If the error is correct, that means I've got either client_ id OR theBuffer does not have a null terminator. I'm pretty sure client_id is fine, since I can see it in debug mode. Strange thing is buffer also has a null terminator. No idea what is wrong.
char * next_token1 = NULL;
char * theWholeMessage = &(inStream[3]);
theTarget = strtok_s(theWholeMessage, " ",&next_token1);
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));
Inside sendTalkPackets is. I'm getting a string is not null terminated at the last line.
void ServerGame::sendTalkPackets(char * buffer, unsigned int buffersize, unsigned int theSender, unsigned int theReceiver)
{
std::string theMessage(buffer);
theMessage += "0";
const unsigned int packet_size = sizeof(Packet);
char packet_data[packet_size];
Packet packet;
packet.packet_type = TALK;
char client_id[MAX_MESSAGE_SIZE];
char theBuffer[MAX_MESSAGE_SIZE];
strcpy_s(theBuffer, theMessage.c_str());
//Quick hot fix for error "string not null terminated"
const char * test = theMessage.c_str();
sprintf_s(client_id, "User %s whispered: ", Usernames.find(theSender)->second.c_str());
printf("This is it %s ", buffer);
strcat_s(client_id, buffersize , theBuffer);
Methinks that problem lies in this line:
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));
sizeof(next_token1)+1 will always gives 5 (on 32 bit platform) because it return size of pointer not size of char array.
One thing which could be causing this (or other problems): As
buffersize, you pass sizeof(next_token1) + 1. next_token1 is
a pointer, which will have a constant size of (typically) 4 or 8. You
almost certainly want strlen(next_token1) + 1. (Or maybe without the
+ 1; conventions for passing sizes like this generally only include
the '\0' if it is an output buffer. There are a couple of other
places where you're using sizeof, which may have similar problems.
But it would probably be better to redo the whole logic to use
std::string everywhere, rather than all of these C routines. No
worries about buffer sizes and '\0' terminators. (For protocol
buffers, I've also found std::vector<char> or std::vector<unsigned char>
quite useful. This was before the memory in std::string was
guaranteed to be contiguous, but even today, it seems to correspond more
closely to the abstraction I'm dealing with.)
You can't just do
std::string theMessage(buffer);
theMessage += "0";
This fails on two fronts:
The std::string constructor doesn't know where buffer ends, if buffer is not 0-terminated. So theMessage will potentially be garbage and include random stuff until some zero byte was found in the memory beyond the buffer.
Appending string "0" to theMessage doesn't help. What you want is to put a zero byte somewhere, not value 0x30 (which is the ascii code for displaying a zero).
The right way to approach this, is to poke a literal zero byte buffersize slots beyond the start of the buffer. You can't do that in buffer itself, because buffer may not be large enough to accomodate that extra zero byte. A possibility is:
char *newbuffer = malloc(buffersize + 1);
strncpy(newbuffer, buffer, buffersize);
newbuffer[buffersize] = 0; // literal zero value
Or you can construct a std::string, whichever you prefer.
I wrote a dll application that is hooked into a process. It works but it ONLY shows the FIRST letter.
I wanted to get the whole string. The string could vary from 2 letters to 32 letters.
//READING MEMORY
HANDLE ExeBaseAddress = GetModuleHandleA(0);
char uNameAddr = *(char*)((char*)ExeBaseAddress + 0x34F01C);
printf("%c \n", uNameAddr);
I also wanted to understand the parts:
*(char*)((char*) //<-- what this is for.
And if it is possible to use this if using multilevel pointers:
char multipoint = *(char*)((char*)ExeBaseAddress + 0x34F01C + 0x123 + 0x321 + 0x20);
UPDATE
I guess something is wrong here:
if(uNameAddr == "omnicient")
cout << "YOU ARE OMNI" << endl;
I used the username name omnicient but it did not cout YOU ARE OMNI. I guess my compare is wrong?
%c displays chars (single characters), %s displays NULL-terminated char*s (strings):
HANDLE ExeBaseAddress = GetModuleHandleA(0);
char *uNameAddr = (char*) ExeBaseAddress + 0x34F01C;
printf("%s \n", uNameAddr);
Notice that I also tidied up the pointer casting, but the important thing is I got rid of the final dereference (* at the front) and assigned it to a char* (pointer) instead of a char.
If your string isn't NULL-terminated (unlikely), you will need to use %.*s and pass the length of your string too.
As for the second part of your question:
*(char*)((char*) ExeBaseAddress + 0x34F01C)
let's break it down. Inside the brackets (therefore the first thing to be evaluated) is this:
(char *) ExeBaseAddress + 0x34F01C
Well that's a C cast (casting the HANDLE to a char*) followed by an addition. In other words, it says "Treat this thing as if it is a pointer to some memory, then look ahead by 0x34F01C bytes of memory" (char is always 1 byte). It is now a pointer to a new position in memory.
Then we get out of the brackets and cast to char* again... needlessly. It could have been:
*((char*) ExeBaseAddress + 0x34F01C)
and finally we dereference (the * at the front), which says "Now tell me what the bit of memory you're pointing to is". But in this case you don't want that, because you want the whole string, not just the first letter (inside printf, it loops along the memory you send it printing each character until it finds a 0, aka \0 aka NULL).
char uNameAddr is a character, you need a list of chars (or char*)
try this instead:
char* name= (char*)((char*)ExeBaseAddress + 0x34F01C);
printf("%s \n", name);
What does *(char*)((char*) mean?
(char*)ExeBaseAddress treat ExeBaseAddress as a pointer to some data of type char
((char*)ExeBaseAddress + 0x34F01C) means add 0x34F01C to the above pointer to offset it by 0x34F01C chars
(char*)((char*)ExeBaseAddress + 0x34F01C) means treat this new address as pointer to some chars
*(char*)((char*)ExeBaseAddress + 0x34F01C) take the contents of the first char at that location
char uNameAddr = *(char*)((char*)ExeBaseAddress + 0x34F01C); means put that character into the char sized variable called uNameAddr.
So basically you had a pointer, you offset it, and then took the first character and printed it.
In the example I gave note how I don't take the firat character, and I put it a pointer variable.
Then I used %s in the printf to make it print out all the chars potnted to by name.
So my assignment is:
Using the strncpy and strncat functions in #include<cstring>,
implement a function
void concat(const char a[ ], const char b[ ], char result[ ],
int result_maxlength)
that concatenates the strings a and b to the buffer result. Be sure
not to overrun the result. It can hold result_maxlength characters,
not counting the \0 terminator. (That is, the buffer has
buffer_maxlength + 1 bytes available.) Be sure to provide a ‘\0’
terminator.
My solution (thus far) is below but I don't know what I'm doing wrong. Not only do I get a run-time check failure 2 error when I actually run the program, but I'm unsure where I should be adding the \0 terminator or even if I should be using strncat rather than strncpy. Hopefully someone can lead me in the right direction. And yes this is hw. That's why I said just lead me in the right direction so that I can try to figure it out :p
#include <iostream>
#include <cstring>
using namespace std;
void concat(const char a[ ], const char b[ ], char result[ ], int result_maxlength);
int main()
{
char a[] = "Woozle";
char b[] = "Heffalump";
char c[5];
char d[10];
char e[20];
concat(a, b, c, 5);
concat(a, b, d, 10);
concat(a, b, e, 20);
cout << c << "\n";
cout << d << "\n";
cout << e << "\n";
return 0;
}
void concat(const char a[ ], const char b[ ], char result[ ], int result_maxlength)
{
strncat(result, a, result_maxlength);
strncat(result, b, result_maxlength);
}
At the very least your result is uninitialized before the first strncat in concat.
EDIT: And yes, as Michael Burr points out your result size is supposed to be changing as you progress and calculated from the very start. Actually, it is misleading name you picked, because it is the max size of source, not destination.
The last argument to strncat() represents the remaining space available in the buffer - not the full size of the buffer.
Also note that that argument includes the spot that the terminating null character will need, so you'll need to account for that since the spec for concat() is otherwise.
Finally, according to the concat() spec, the result placed in the buffer should not be concatenated to the existing contents of the buffer (those contents should be replaced). Also, make sure you test that your function properly handles a zero length result_maxlength argument being passed in.
strncpy from a to result (whatever is smaller, lenght of a or result_maxlength)
strncat from b to remaining of result (whatever is smaller, lenght of b or result_maxlength- lenght of a)
before every return just put a \0 at last position result[result_maxlength-1] ='\0';
It's actually not specified WHAT to do if result is too short, should you add trailing 0 or not. I guess you'd better terminate that string.
tip : remaining of result is result+strlen(a)