Let's say you have this structure:
struct MMFS_IDENTIFICATION
{
char *szVendor;
char *szControllerModel;
char *szRevision;
char *szId;
char *szExecutive;
char *szKarelRevision;
char *szProcessName;
char *szCommRevision;
char *szRobotModel;
};
Is there any easy way to do something like this?
MMFS_IDENTIFICATION mmfsId;
for( int i = 0; i < 9; i++ )
{
int len = buf[pos++];
mmfsId[i] = malloc(len);
memcpy( mmfsId[i], buf[pos], len );
pos += len;
}
The only thing I know to do is copy and paste the code nine times. But I really don't want to do that because in the real program I'm using this concept for, calculating len is not as simple as I made it in this example.
Since your structure contains 9 different pointers with different names, the only standard way to access them is with 9 different pieces of code. You might try to cheat and rely on the internal representation of the structure, and you might even get away with it, but it isn't advised.
Use a function to turn each piece into a single one-liner.
void CopyString(char * & string_ptr, char * buf, int & pos)
{
int len = buf[pos++];
string_ptr = new char[len];
memcpy( string_ptr, buf[pos], len );
pos += len;
}
CopyString(mmfsId.szVendor, buf, pos);
CopyString(mmfsId.szControllerModel, buf, pos);
CopyString(mmfsId.szRevision, buf, pos);
CopyString(mmfsId.szId, buf, pos);
CopyString(mmfsId.szExecutive, buf, pos);
CopyString(mmfsId.szKarelRevision, buf, pos);
CopyString(mmfsId.szProcessName, buf, pos);
CopyString(mmfsId.szCommRevision, buf, pos);
CopyString(mmfsId.szRobotModel, buf, pos);
Since all of the structure members are char* pointers, you could do something like this:
#include <pshpack1.h>
struct MMFS_IDENTIFICATION
{
char *szVendor;
char *szControllerModel;
char *szRevision;
char *szId;
char *szExecutive;
char *szKarelRevision;
char *szProcessName;
char *szCommRevision;
char *szRobotModel;
};
#include <poppack.h>
MMFS_IDENTIFICATION mmfsId;
char** pmmfsId = (char**) &mmfsId;
for( int i = 0; i < 9; ++i )
{
int len = buf[pos++];
pmmfsId[i] = malloc(len+1);
memcpy( pmmfsId[i], buf[pos], len );
}
For the moment, I've made the members std::string instead of char *, for the sake of slightly simpler demo code, but the general idea should work the same with with char * instead1.
#include <stddef.h>
#include <iostream>
#include <string.h>
#include <sstream>
struct MMFS_IDENTIFICATION
{
std::string Vendor;
std::string ControllerModel;
std::string Revision;
std::string Id;
std::string Executive;
std::string KarelRevision;
std::string ProcessName;
std::string CommRevision;
std::string RobotModel;
};
int main() {
MMFS_IDENTIFICATION s;
// We need a char *, because we need to add byte-wise offsets:
char *base = (char *)&s;
typedef std::string *ptr;
ptr fields[9];
// Set up our `fields` array with the addresses of the fields.
// Note the parens to force pointer arithmetic on `char *`, *then* conversion
// to `std::string *`.
fields[0] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, Vendor));
fields[1] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, ControllerModel));
fields[2] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, Revision));
fields[3] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, Id));
fields[4] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, Executive));
fields[5] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, KarelRevision));
fields[6] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, ProcessName));
fields[7] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, CommRevision));
fields[8] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, RobotModel));
// Initialize the field contents to some recognizable values:
for (int i=0; i<9; i++) {
std::ostringstream buffer;
buffer << "Field " << i;
*fields[i] = buffer.str();
}
// print out some spot results to show we've written to the fields in the struct:
std::cout << "printing by field names:\n";
std::cout << "Vendor = " << s.Vendor << "\n";
std::cout << "Id = " << s.Id << "\n";
std::cout << "CommRevision = " << s.CommRevision << "\n";
return 0;
}
Another possibility would be to use std/tr1/boost tuples. These won't let you use run-time iteration like I have above, but they will give you access to fields by number at compile time. With some case, you can probably use this to eliminate duplication at the source code level, even though it may remain in the object code.
Technically, you can only use offsetof in a POD struct (at least under C++98/03), so it's not required to work at all with them being std::string. At least with most typical compilers (e.g., VC++, g++) I've yet to see it fail for non-POD types, at least as long as the parent struct has no virtual functions, etc., of its own.
Related
So I have this function that XORes a string and then it turns it into a format like this:
\x55\x1\x53\x21...
But the problem is that the function firstly returned negative values, but I fixed that by making it from a CHAR into a UCHAR, but now it starts giving me values that are too big and the compiler doesn't let me compile because of it. Any thoughts of why this would happen? Couldn't find anything about it online.
__inline char* EncryptString(const char* String, const char* Key)
{
char* szEncrypted = new char[lstrlenA(String) + 1];
memcpy(szEncrypted, String, lstrlenA(String) + 1);
for (int32_t i = 0; i < lstrlenA(String); ++i)
szEncrypted[i] = String[i] ^ Key[i % (lstrlenA(Key))];
std::stringstream lpStream;
for (int32_t i = 0; i < lstrlenA(szEncrypted); ++i)
{
char cCharInd = szEncrypted[i];
UINT nCharNum = UINT(cCharInd);
lpStream << "\\x" << std::hex << nCharNum;
}
std::string sHexEscaped = lpStream.str();
lpStream.clear();
delete[] szEncrypted;
char* szReturn = new char[sHexEscaped.length() + 1];
memcpy(szReturn, sHexEscaped.c_str(), sHexEscaped.length() + 1);
return szReturn;
}
The problem is the type char can be signed or unsinged (depends on compiler). I think the following code helps you:
const unsigned char uc = static_cast<unsigned char>( szEncrypted[i] );
const unsigned int code = uc;
lpStream << "\\x" << std::hex << code;
P.S. Looks like you actually don't need to use temporary buffer szEncrypted.
UPDATE:
I tried to demonstrate how such encryption may works in code below (the source file encoding is Windows-1251). You also have to know that encrypted string may contain \0 bytes, so, to calculate the length of encrypted string you would probably use something like this: const char rawString[] = "\xf\x55\x0\x1e\x22\x98\x20\x1e\x2b\x4b\x12"; const int rawSize = sizeof( raw ) - 1;
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
string EncryptString( const char* String, const char* Key )
{
std::stringstream lpStream;
const int keyLength = strlen( Key );
for( int i = 0; String[i] != '\0'; i++ ) {
char ec = String[i] ^ Key[i % keyLength];
unsigned char uc = static_cast<unsigned char>( ec );
lpStream << "\\x" << std::hex << static_cast<unsigned int>( uc );
}
return lpStream.str();
}
void DecryptString( string& String, const char* Key )
{
const int keyLength = strlen( Key );
for( string::size_type i = 0; i < String.length(); i++ ) {
String[i] ^= Key[i % keyLength];
}
}
int main()
{
system( "ChCp 1251" );
const char* key = "Пётр";
cout << EncryptString( "Антон Тодуа", key ) << endl;
const char raw[] = "\xf\x55\x0\x1e\x22\x98\x20\x1e\x2b\x4b\x12";
string data( raw, sizeof( raw ) - 1 );
DecryptString( data, key );
cout << data << endl;
return 0;
}
I'm trying to create a custom string class similar to std::string.
And I'm having a trouble implementing 'find_first_not_of'.
Here's my test code
#include <iostream>
class String {
private:
char *m_data;
int m_length;
char *alloc(int size);
int length() const {return m_length;}
int size() const {return m_length;}
const char *c_str() const {return m_data;}
public:
String(const char *str=0);
int find_first_not_of(const char *str);
static const int npos;
};
const int String::npos = -1;
char * String::alloc(int size)
{
char * str = new char[size+1];
return str;
}
String::String(const char *str)
{
if (!str) str = "";
m_length = static_cast<int>(strlen(str));
m_data = alloc(m_length);
strcpy(m_data, str);
}
int String::find_first_not_of(const char *str)
{
size_t len = strspn(c_str(), str);
if (len == 0)
return -1;
else
return len;
}
int main(int argc, const char * argv[]) {
String A = "123";
std::string B = "123";
if (A.find_first_not_of("0123456789") == -1)
std::cout << "A is digit" << std::endl;
else
std::cout << "A is not digit" << std::endl;
if (B.find_first_not_of("0123456789") == -1)
std::cout << "B is digit" << std::endl;
else
std::cout << "B is not digit" << std::endl;
return 0;
}
And this is the result I see if I run the code.
A is not digit
B is digit
Program ended with exit code: 0
Can someone please point me what I'm missing?
Thanks!
You are confusing your String::find_first_not_of with std::string::find_first_not_of. They are different functions that have different functionality.
I really don't understand what String::find_first_not_of needs to do, but here is what each of them returns (one the length of the string and the other one the position):
std::string::find_first_if_not (from here):
The position of the first character that does not match.
If no such characters are found, the function returns string::npos.
strspn (from here):
The length of the initial portion of str1 containing only characters that appear in str2.
Therefore, if all of the characters in str1 are in str2, the function returns the length of the entire str1 string, and if the first character in str1 is not in str2, the function returns zero.
So even the inner working of the functions are different.
You should be able to follow based on this info.
This one worked just like std::string's find_first_not_of.
int String::find_first_not_of(const char *str, int pos)
{
const int len = static_cast<int>(strspn(c_str() + pos, str));
if (len + pos == m_length)
return -1; //npos
else
return len + pos;
}
#Garmekain's explanation was really helpful. Thank you.
Hi I'm trying to copy char * to std::string, the char * variable allocated with malloc, after the copy I want to free char * cause I'm pretty sure std::string won't free it. I want to do that without affecting the newly created std::string.
typedef struct {
std::string name;
} st;
st fst;
name = (char *) malloc(len + 1);
for (i = 0; i<len; i++)
name[i] = name_orig[offset + i]; //name_orig is const unsigned char *
name[i] = 0;
fst.name.assign(name,len);
free(name);
cout << fst.name << endl; // prints "wiped"
The malloc'd string and the copy are unnecessary. You can just do
typedef struct {
std::string name;
} st;
st fst;
fst.name.assign(reinterpret_cast<const char*>(&name_orig[offset]), len);
I am open to using intermediary C++ code, though C code is the preference.
I have code like the following:
char *fileName1 = "graph";
char *extension1 = ".eps";
I want to create a new char* variable called fileName1WithExtension1 which would correspond to "graph.eps", formed from the two char* variables given above. How can this be done?
If you use C++, have those as std::string strings:
std::string fileName1 = "graph";
std::string extension1 = ".eps";
And then simply
std::string fileName1WithExtension1 = filename1 + extension1;
If you then need to pass that to a C library function expecting a C string, get char pointer with fileName1WithExtension1.c_str()
There really is no reason to muck about with plain C strings in C++ code. It is so error-prone and tedious, that it should be actively avoided.
char *new_string;
new_string = malloc(strlen(fileName1) + strlen(extension1) + 1);
sprintf(new_string, "%s%s", fileName1, extension1);
...
free(new_string)
You can use the asprintf() function
char *buffer;
asprintf (&buffer, "%s%s", fileName1, extension1);
When the buffer variable become useless in your code, you have to free the memory allocated for buffer by asprintf with
free(buffer);
char *joined;
joined = (char*)malloc(strlen(fileName1) + strlen(extension1) + 1);
strcpy(joined, fileName1)
strcat(joined, extension1)
For a small performance increase, if the compiler is smart enough at optimizing, change the last line to
strcpy(joined+strlen(fileName1), extension1)
Even better, store the length of fileName1 in a variable the first time you determine it, and use it in the final strcpy().
If you want to go REALLY low-level, with ugly loops and such, you can do this: (Tested, it compiles and gives the expected and desired results)
char* filename1 = "graph";
char* extension1 = ".eps";
char* filename1WithExtension1 = combine(filename1, extension1);
where:
char* combine(char* str1, char* str2)
{
int str1len = 0, str2len = 0;
while(str1[str1len] != '\0') {
str1len++;
}
while(str2[str2len] != '\0') {
str2len++;
}
int outputlen = str1len + str2len + 1;
char* output = new char[outputlen];
for(int i = 0; i < str1len; i++)
{
output[i] = str1[i];
}
for(int i = str1len; i < outputlen; i++)
{
output[i] = str2[i - str1len];
}
return output;
}
I did a bit of C brush-up for fun, here's an alternative (C90 and C++ compatible code) for joining an array of C strings with separator. It should be very efficient with any decently optimizing compiler, too:
#include <string.h>
#include <stdlib.h>
/* **parts are strings to join, a NULL-terminated array of char*
* sep is separator string, use "" for no separator, must not be NULL
* returns malloc-allocated buffer which must be freed
* if len_out!=NULL, sets *len_out to strlen of result string */
char *astrjoin(int *len_out, const char *sep, char **parts) {
int part_count;
int parts_total_len = 0;
for(part_count = 0; parts[part_count]; ++part_count) {
parts_total_len += strlen(parts[part_count]);
}
if (part_count > 0) {
int malloc_size = (part_count - 1) * strlen(sep) + parts_total_len + 1;
char *result = (char*)malloc(malloc_size);
char *dest = result;
for(;;) {
const char *src;
for(src=*parts; *src; ++src) *dest++ = *src;
if (!*++parts) break;
for(src=sep ; *src; ++src) *dest++ = *src;
}
*dest = 0;
if (len_out) *len_out = malloc_size - 1;
return result;
} else {
if (len_out) *len_out = 0;
return strdup("");
}
}
Example usage:
int main(int argc, char *argv[]) {
/* argv is NULL-terminated array of char pointers */
char *commandline = astrjoin(NULL, " ", argv);
printf("argc: %d\nargv: %s\n", argc, commandline);
free(commandline);
return 0;
}
To call that in context of your question, it could be something like:
char *tmparr[] = { fileName1, exteansion1, NULL };
char *fileName1WithExtension1 = astrjoin(NULL, "", tmparr);
It would be trivial to create a version with sep and/or len_out dropped, or a version supporting "varargs", with signature looking something like:
char *astrjoin_va(int *len_out, const char *sep, ...);
Which would be nicer to call in context of your question:
char *fileName1WithExtension1 = astrjoin_va(NULL, "", fileName1, extension1, NULL);
So I am working on a tool that dereferences the values of some addresses, it is in both C and C++, and although I am not familiar with C++ I figured out I can maybe take advantage of the string type offered by C++.
What I have is this:
unsigned char contents_address = 0;
unsigned char * address = (unsigned char *) add.addr;
int i;
for(i = 0; i < bytesize; i++){ //bytesize can be anything from 1 to whatever
if(add.num == 3){
contents_address = *(address + i);
//printf("%02x ", contents_address);
}
}
As you can see what I am trying to do is dereference the unsigned char pointer. What I want to do is have a string variable and concatenate all of the dereferenced values into it and by the end instead of having to go through a for case for getting each one of the elements (by having an array of characters or by just going through the pointers) to have a string variable with everything inside.
NOTE: I need to do this because the string variable is going to a MySQL database and it would be a pain to insert an array into a table...
Try this that I borrowed from this link:
http://www.corsix.org/content/algorithmic-stdstring-creation
#include <sstream>
#include <iomanip>
std::string hexifyChar(int c)
{
std::stringstream ss;
ss << std::hex << std::setw(2) << std::setfill('0') << c;
return ss.str();
}
std::string hexify(const char* base, size_t len)
{
std::stringstream ss;
for(size_t i = 0; i < len; ++i)
ss << hexifyChar(base[i]);
return ss.str();
}
I didn't quite understand what you want to do here (why do you assign a dereferenced value to a variable called ..._address)?.
But maybe what you're looking for is a stringstream.
Here's a relatively efficient version that performs only one allocation and no additional function calls:
#include <string>
std::string hexify(unsigned char buf, unsigned int len)
{
std::string result;
result.reserve(2 * len);
static char const alphabet[] = "0123456789ABCDEF";
for (unsigned int i = 0; i != len)
{
result.push_back(alphabet[buf[i] / 16]);
result.push_back(alphabet[buf[i] % 16]);
{
return result;
}
This should be rather more efficient than using iostreams. You can also modify this trivially to write into a given output buffer, if you prefer a C version which leaves allocation to the consumer.