unsigned char arr[]= "ksd sjdhkd 08923 jh32jk3 323hkgk \34 \34 \er \fd\3 \3df \34f ";
Delete range from "ksd" to "\34"
and i want the results like below.
unsigned char arr[]= " \34 \er \fd\3 \3df \34f ";
Note:
I don't want to convert it to string.
I dont want to change the dataType of the arr[],
I want it to be stay as unsigned char arr[]
Actually, the type arr[] is arr[64]; so not possible to directly use the same name and change the value. And \3 should be within a raw string .
If the type is not limited, the following works
void test_delete_part_of_an_array()
{
unsigned char arrStore[] = R"(ksd sjdhkd 08923 jh32jk3 323hkgk \34 \34 \er \fd\3 \3df \34f)";
unsigned char* arr = arrStore;
auto result = std::strstr((char*)arrStore, R"(\34)");
if (result)
{
size_t newSize = sizeof(arrStore) - (result - (char*)arrStore);
unsigned char* arr2 = new unsigned char[newSize];
arr2[newSize - 1] = '\0';
std::copy(result, (char*)arrStore + sizeof(arrStore), arr2);
arr = arr2;
//Further process and delete of the pointer.
}
}
If use string_view, much simpler
void test_delete_part_of_an_array2()
{
unsigned char arr[] = R"(ksd sjdhkd 08923 jh32jk3 323hkgk \34 \34 \er \fd\3 \3df \34f)";
std::string_view arrv((char*)arr);
auto found = arrv.find(R"(\34)");
if (found != std::string::npos)
{
std::string_view arr2 = arrv.substr(found);
printf(arr2.data());
//Further process
}
}
If the type is determined to be char[], we may need constexpr string resolver, it requires some library support.
Related
int computeHMACSHA1Hash(const char * unhashedcstr, char * hashedcstr, const char * key, int returncode)
{
string hashed;
size_t unhashlength = strlen(unhashedcstr);
char * nonconstunhashcstr = new char[unhashlength];
strcpy_s(nonconstunhashcstr, unhashlength + 1, unhashedcstr);
unsigned char* pixels = reinterpret_cast<unsigned char*>(nonconstunhashcstr);
returncode = 0;
HMAC_CTX* context = HMAC_CTX_new();
size_t unhashedstrlength = sizeof(unhashedcstr);
if (context != NULL)
{
if (HMAC_Init_ex(context, key, strlen(key), EVP_sha1(), NULL))
{
if (HMAC_Update(context, pixels, unhashedstrlength))
{
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int lengthOfHash = 0;
if (HMAC_Final(context, hash, &lengthOfHash))
{
std::stringstream ss;
for (unsigned int i = 0; i < lengthOfHash; ++i)
{
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
}
hashed = ss.str();
size_t outputSize = hashed.length() + 1; // +1 for null terminator
strcpy_s(hashedcstr, outputSize, hashed.c_str());
returncode = 0;
}
else
{
returncode = 7;
}
}
else
{
returncode = 6;
}
}
else
{
returncode = 5;
}
HMAC_CTX_free(context);
}
else
{
returncode = 4;
}
return returncode;
}
int main()
{
const char * unhashedcstr = "a=services&l=v1&p=open&k=SD58292829&i=20200918125249803&n=2124&t=1600404769&f={\"invoiceCode\": \"11111\",\"invoiceNo\": \"2222\",\"inTaxAmount\": \"\",\"exTaxAmount\": \"\"}";
char * hashedcstr = new char[100];
int returncode = 0;
const char * key = "SD886A11B0EE428F";
int result = computeHMACSHA1Hash(unhashedcstr, hashedcstr, key, returncode);
return 0;
}
I tried the code above to calculating the HMAC SHA1 hash value for a content, but compared the results on https://www.freeformatter.com/hmac-generator.html#before-output
it looks like I didn't do it right. I'm not sure what I have done wrong though. Any help would be appreciated.
It turned out the result was "d916b4c2d277319bbf18076c158f0cbcf6c3bc57", while on the website https://www.freeformatter.com/hmac-generator.html#before-output, the result was "71482b292f2b2a47b3eca6dad5e7350566d60963". Even when I tried using the string "a=services&l=v1&p=open&k=SD58292829&i=20200918125249803&n=2124&t=1600404769&f={"invoiceCode": "11111","invoiceNo": "2222","inTaxAmount": "","exTaxAmount": ""}" which removed the escape characters, the result was "09be98b6129c149e685ed57a1d19651a602cda0d". It didn't match the correct one.
Is there anything wrong with my code?
Your hash is calculated over the bytes a=se, which are the first four bytes of the whole input string. Thus, you get d916b4c2d277319bbf18076c158f0cbcf6c3bc57 instead of the 09be98b6129c149e685ed57a1d19651a602cda0d that would correspond to the whole string.
The reason is this:
size_t unhashedstrlength = sizeof(unhashedcstr);
Here, sizeof(unhashedcstr) is the size of the unhashedcstr pointer itself (which is of type const char*), not the size of the null-terminated C-style string this unhashedcstr pointer is pointing to. You are compiling a 32-bit program, so the size of a pointer is 4 bytes. Thus, unhashedstrlength is 4.
To get the length of the C-style string, you can do this instead:
size_t unhashedstrlength = strlen(unhashedcstr);
But just as a comment, in modern C++, you should avoid using raw pointers (such as const char*, char*, unsigned char*), C functions (like strlen(), strcpy_s()) and manual memory management (new / delete and new[] / delete[]). You should prefer to use std::string and/or std::vector<unsigned char> instead, wherever possible. When you need to pass a buffer's address to an API function, you can use std::string::data(), std::vector::data(), or more generally, std::data().
By the way, you currently leak memory: you dynamically allocate buffers using new[], but you never deallocate those (using delete[]). So that memory is released by the OS only after the program exits. This is called a memory leak.
I have a std::string array which I need to convert to an unsigned char array so that I can use this array with third-party library which only accepts unsigned char array.
let say my array is
std::string array[3];
array[0] = "a105b";
array[1] = "c258e"
array[2] = "ff587";
I need to transfer this array into:
unsigned char cArray[3][5];
I can do hardwire the unsigned char as below:
unsigned char cArray[3][5] = {"a105b", "c258e", "ff587"};
but I was unable to find a way to do it using C++ code to transfer the data from the std::string array to the unsigned char array.
You could make a function that loops through the two arrays and copies from one to the other.
Example:
#include <algorithm>
#include <iostream>
#include <string>
template<size_t R, size_t N>
void foo(const std::string(&src)[R], unsigned char(&dest)[R][N]) {
// both `src` and `dest` must be arrays with `R` rows
// `N` is how many unsigned chars each inner array in `dest` has
for(size_t idx = 0; idx < R; ++idx) {
// Copy from `src[idx]` to `dest[idx]`
// Copy at most `N` chars but no more than the length of the string + 1
// for the null terminator:
std::copy_n(src[idx].c_str(), std::min(N, src[idx].size() + 1), dest[idx]);
// Add the below line if the arrays in cArray are supposed to
// be null terminated strings:
//dest[idx][N - 1] = '\0';
}
}
int main() {
std::string array[3];
array[0] = "a105b";
array[1] = "c258e";
array[2] = "ff587";
unsigned char cArray[3][5];
foo(array, cArray);
}
I can do hardwire the unsigned char as below
unsigned char cArray[3][5] = {"a105b", "c258e", "ff587"};
No, that's not valid in C++. You would have to make the inner array [6] in C++:
unsigned char cArray[3][6] = {"a105b", "c258e", "ff587"};
In code it could look like this:
#include <array>
#include <algorithm>
#include <cstring>
#include <string>
template<typename to_type, size_t buf_size, size_t number_of_strings>
void to_array(const std::array<std::string, number_of_strings>& input,
to_type (&output)[number_of_strings][buf_size])
{
for (std::size_t n = 0; n < number_of_strings; ++n)
{
const auto input_str = input[n].c_str();
// for input string include trailing 0 on input so add one to length
const auto copy_len = std::min(input[n].length()+1, buf_size);
std::memcpy(output[n], input_str, copy_len);
}
}
int main()
{
std::array<std::string, 3> input_array{ "a105b", "c258e", "ff587" };
unsigned char c_array[3][6];
to_array<unsigned char, 6>(input_array, c_array);
return 0;
}
It showed me again that 'c' style arrays are not nice to work with.
You can't return them from a function (like you can with std::array).
So you have to pass the output array as parameter to the conversion function too.
You are not permitted to assign to a plain array. You cannot define your own assignment operator for the plain array, because C++ does not allow overload of the assignment operator except as a non-static member function of a class.
One workaround may be to define an overload for a shift operator, and give a similar syntax to an input stream.
template <unsigned N>
void operator >> (std::string s, unsigned char (&a)[N]) {
auto n = (s.size() < N) ? s.size() + 1 : N;
std::copy_n(s.c_str(), n, a);
}
/*...*/
unsigned char cArray[3][5];
array[0] >> cArray[0];
array[1] >> cArray[1];
array[2] >> cArray[2];
char *readByteArray() {
unsigned char l = readByte (); // reads one byte from the stream
char ret[l + 1]; // this should not be done
ret[0] = l; // or could also define a struct for this like {int length, char *data}
readBytes((char *)&ret + 1, l);
return (char *)&ret;
}
So the problem is, that I want to return an array, and the length of the array is determined by the function.
A better example of this would be the function I use for reading a string:
char *readString () {
unsigned char l = readByte (); // reads one byte from the stream
char ret[l + 1]; // +1 for null byte
readBytes((char *)&ret, l); // reads l bytes from the stream
ret[l] = '\0'; // null byte
return (char *)&ret; // problem
}
If the length of the array would be determined before the function I could allocate the array outside the function and pass it as a parameter, but calling this:
unsigned char l = readByte ();
char ret[l + 1];
readString (&ret, l);
every time I want to read a string would kind of defeat the purpose of the function.
Is there an elegant solution for this on windows AND ATmega328 (STL is not available)?
One of the following options should work:
Return a pointer to an array of char allocated from the heap. Make sure to delete the returned value in the calling function.
char* readByteArray()
{
unsigned char l = readByte();
char *ret = new char[l + 1];
ret[0] = l;
readBytes(ret + 1, l);
return ret;
}
Return a std::vector<char>.
std::vector<char> readByteArray()
{
unsigned char l = readByte();
std::vector<char> ret(l);
readBytes(ret.data(), l);
return ret;
}
I have next problem. I used int memcmp ( const void * ptr1, const void * ptr2, size_t num );
function to compare two void pointers which contain integers. This worked for me very well.
int firstValue = 5;
int secondValue = 3;
void* firstValueVoid;
void* secondValueVoid
firstValueVoid = new int(firstValue);
secondValueVoid = new int(secondValue);
int compare = memcmp(firstValueVoid, secondValueVoid, 4);
cout << compare << endl;
But, if I am trying to to the same for strings, it always shows that first value is less than second one.
string firstValue = "abc";
string secondValue = "a";
int testSize = firstValue.length();
void* firstValueVoid;
void* secondValueVoid
firstValueVoid = new string(firstValue);
secondValueVoid = new string(secondValue);
int compare = memcmp(firstValueVoid, secondValueVoid, testSize);
cout << compare << endl;
So compare value always becomes equal to -1. Even if I am making firstValue = "a"; secondValue = "a";.
Please help someone. I already tried everything I had in my mind to fix this problem.
Thank you in advance!
From cppreference:
int memcmp( const void* lhs, const void* rhs, std::size_t count );
Reinterprets the objects pointed to by lhs and rhs as arrays of unsigned char and compares the first count characters of these arrays. The comparison is done lexicographically.
In your case, you're comparing two std::string objects whose byte sequences differs from the buffer that holds the actual string. You're getting this error because these objects are not naked char arrays but rather actual classes.
Here is the note from the actual page (emphasis mine):
This function reads object representations, not the object values, and is typically meaningful for trivially-copyable objects only. For example, memcmp() between two objects of type std::string or std::vector will not compare their contents.
You should be using an array of char for this:
char abc[] = "abc";
char abd[] = "abd";
int bytes = std::min(sizeof abc, sizeof abd);
int c1 = memcmp(abc, abd, bytes);
int c2 = memcmp(abd, abc, bytes);
If you really need void*s:
void* a = abc;
void* b = abd;
int c1 = memcmp(reinterpret_cast<char*>(a),
reinterpret_cast<char*>(b), bytes);
int c2 = memcmp(reinterpret_cast<char*>(b),
reinterpret_cast<char*>(a), bytes);
Just declare the pointers as char* or char[] (which essentially is the same in this case), and compare them like that. This works fine:
char firstValue[] = "abc";
char secondValue[] = "a";
int testSize = string(firstValue).size();
int compare = memcmp(firstValue, secondValue, testSize);
There's a working example at the C++ reference page too.
If you REALLY need the void pointers use them like this:
int someData1 = 35243242;
int someData2 = 34243251;
void *ptr1, *ptr2;
ptr1 = &someData1;
ptr2 = &someData2;
int testSize = sizeof(int);
int compare = memcmp((char*)ptr1, (char*)ptr2, testSize);
cout << compare << endl;
or with strings:
string someData1 = "sdadsasd";
string someData2 = "sdadsasd";
void *ptr1, *ptr2;
const char *c1, *c2;
c1 = someData1.c_str();
c2 = someData2.c_str();
ptr1 = (char*)c1;
ptr2 = (char*)c2;
int testSize = someData1.size();
int compare = memcmp(ptr1, ptr1, testSize);
How would I manually concatenate two char arrays without using the strncpy function?
Can I just say char1 + char2?
Or would I have to write a for loop to get individual elements and add them like this:
addchar[0] = char1[0];
addchar[1] = char1[1];
etc
etc
addchar[n] = char2[0];
addchar[n+1] = char2[1];
etc
etc
To clarify, if
char1 = "happy"
char2 = "birthday"
I want addchar to = happybirthday
For a C-only solution use strncat:
char destination[80] = "";
char string1[] = "Hello";
char string2[] = " World!";
/* Copy string1 to destination */
strncat(destination, string1, sizeof(destination));
/* Append string2 to destination */
strncat(destination, string2, sizeof(destination) - sizeof(string1));
Note that the strn* family of string functions are safer than the ones without n, because they avoid the possibility of buffer overruns.
For a C++ solution, simply use std::string and operator+ or operator+=:
std::string destination("Hello ");
destination += "World";
destination += '!';
If you consider two trivial loops to be "manual", then yes, without using the standard library this is the only way.
char *append(const char *a, const char *b) {
int i = 0;
size_t na = strlen(a);
size_t nb = strlen(b);
char *r = (char*)calloc(na + nb + 1, 1);
for (i = 0; i < na; i++) {
r[i] = a[i];
}
for (i = 0; i < nb; i++) {
r[na + i] = b[i];
}
return r;
}
Remember to call free.
If you're using c++ just use an std::string. With std::strings, the + operator is supported, so you can do string1+string2.
Without using library functions, here is the procedure:
1. Point to the first character in string1.
2. While the current character at the pointer is not null, increment the pointer.
3. Create a "source" pointer pointing to string2.
4. While the character at the "source" location is not null:
4.1. Copy the character from the "source" location to the location pointed to by the String1 pointer.
4.2. Increment both pointers.
Unless this is homework, use C++ std::string for your text.
If you must use C style strings, use the library functions.
Library functions are optimized and validated, reducing your development time.
Alright, you want something like this:
char1 + char2
First, let's see the insane solution:
C:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length_left = strlen(a_Left);
unsigned int length_right = strlen(a_Right);
unsigned int length = length_left + length_right;
char* result = (char*)malloc(length);
// clear the string
memset(result, 0, length);
// copy the left part to the final string
memcpy(result, a_Left, length_left);
// append the right part the to the final string
memcpy(&result[length_left], a_Right, length_right);
// make sure the string actually ends
result[length] = 0;
return result;
}
C++:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length_left = strlen(a_Left);
unsigned int length_right = strlen(a_Right);
unsigned int length = length_left + length_right;
char* result = new char[length];
// clear the string
memset(result, 0, length);
// copy the left part to the final string
memcpy(result, a_Left, length_left);
// append the right part the to the final string
memcpy(&result[length_left], a_Right, length_right);
// make sure the string actually ends
result[length] = 0;
return result;
}
Now, let's see the sane solution:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length = strlen(a_Left) + strlen(a_Right);
char* result = new char[length];
strcpy(result, a_Left);
strcat(result, a_Right);
return result;
}
So, was this homework? I don't really care.
If it was, ask yourself: what did you learn?