I try to write a function which converts a char* to a wchar_t* to simplify multiple steps in my program.
wchar_t* ConvertToWString(char* str)
{
size_t newStrSize = strlen(str) + 1;
wchar_t* newWStr = new wchar_t[newStrSize];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, newWStr , newStrSize, str, _TRUNCATE);
return newWStr; // I know i need to call "delete[] newWStr;" but then I can't return the converted string...
}
The function works but it is obviously memory leaking. Does someone know another way how to convert a char* to a wchar_t*?
My issue is that the function needs to handle different string lengths.
Right now I am using a workaround with a fixed buffer but that can't be the only solution:
wchar_t* ConvertToWStringUgly(char* str)
{
wchar_t buffer[1024]; // fixed array for 1023 wchars
size_t newStrSize = strlen(str) + 1;
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, buffer, newStrSize, str, _TRUNCATE);
return buffer; // This is working but not really a good way
}
Classic. Use the C++ power ! ... Destructors freeing allocated memory
Instead of your
wchar_t buffer [1024];
why not declare and use a Wstr class, looking approximately like this (maybe malloc and free to used instead of new and delete ?):
class Wstr {
public :
Wstr () : val_ ((wchar_t*) NULL), size_ (0) {}
~Wstr () {
if (val_ != (wchar_t*)NULL) {
delete[] val_;
val_ = (wchar_t*)NULL;
}
}
Wstr& operator = (const char*& str) {
size_ = strlen(str) + 1;
if (val_ != (wchar_t*) NULL) {
delete [] val_;
val_ = (wchar_t*) NULL;
}
size_t newStrSize = strlen(str) + 1;
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, val_, newStrSize, str, _TRUNCATE);
size_ = newStrSize;
return *this;
}
//.. copy cons, op =, op ==, op != to be written
wchar_t* val_;
size_t size_;
};
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.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class MyString
{
char* str;
int size;
public:
MyString()
{
str = '\0';
size = 1;
}
MyString(const char* const s)
: str(new char[strlen(s)])
{
size = strlen(s) + 1;
strcpy(str, s);
}
MyString(const MyString& another)
: str(new char[another.size])
{
size = another.size;
for (int i = 0; i < size; i++)
str[i] = another.str[i];
}
~MyString()
{
delete[] str;
}
void set(const char* st)
{
size = (int)strlen(st) + 1;
str = new char[size];
for (int i = 0; i < size; i++)
str[i] = st[i];
}
bool isEqual(const MyString& other) const
{
if (size != other.size)
return false;
if (strcmp(str, other.str) == 0)
return true;
else
return false;
}
void print() const
{
for (unsigned int i = 0; i < size; i++)
cout << str[i];
cout << endl;
}
};
int main() {
MyString strs[] = {
MyString("C"),
MyString(),
MyString("Java")
};
strs[1].set("C++");
const int arraySize = sizeof(strs) / sizeof(MyString);
const MyString target("Java");
for (int i = 0; i < arraySize; i++) {
const MyString str(strs[i]); // copy constructor
if (str.isEqual(target)) {
cout << "[" << i << "]: ";
str.print();
break;
}
}
for (const MyString& str : strs) {
str.print();
}
}
In dev c++ it's working and there was no caution, but in visual studio 2019, catution like "heap corruption detected after normal block crt detected that the application" is occured. I don't what is problem.
When I debuged my code, it successfully worked befor the main fuction finished. When destructor worked, the caution was appeared.
Please help me :)
Your default constructor should not compile with recent GCC compilers, you can only assign NULL or nullptr to pointer
MyString() {
str = nullptr;
size = 0;
}
This constructor needs one extra 1 byte to allocate memory, then the buffer overflow can be avoided.
MyString(const char* const s) : str(new char[strlen(s) + 1]) {
size = strlen(s) + 1;
strncpy(str, s, size);
}
strncpy is a safer replacement for strcpy, I suggest you use this one.
You also need to add implementation for operator=, or the compiler-generated one will cause a memory leak once you use operator= to copy an object.
MyString& operator=(const MyString& another) {
if (&another == this) return *this;
delete[] str;
str = new char[another.size];
size = another.size;
// better to use strncpy here
for (int i = 0; i < size; i++) str[i] = another.str[i];
return *this;
}
A similar string implementation is discussed in this question, you may also reference the code there.
Demo
One problem is the initialization of the members in the default constructor:
str = '\0';
size = 1;
The character literal '\0 is equal to zero, which is equal to a null pointer. That assignment is equivalent to:
str = nullptr;
And yet you still say that the size of the string is 1, which is wrong since there is no string and the size should be zero.
Another (and the likely culprint of your problem) problem is that in your constructor MyString(const char* const s) you use strlen to get the length of a C-style null-terminated string for the allocation, but you forget that strlen doesn't count the null-terminator.
This means the allocation will be too small, and when you use strcpy to copy the string it will write the null-terminator out of bounds of your allocated memory.
Furthermore, you in other places count with the null-terminator, and actually set the size to include the null-terminator (even in the MyString(const char* const s) constructor). This goes against the normal C++ semantics of strings where the size doesn't include the terminator.
This could then lead to further problems, like in your print function where you actually print the null-terminator.
Writing a simple string copier and testing it in the main() fucntion. What's odd is that sometimes the program returns
"HelloHello"
like it should, but maybe every third time I run it, the program prints out:
"Hello!Hello!▌▌▌▌▌▌▌▌▌▌▒"UòB╚"
Why is the tail of garbage data only sometimes being added to the end of my second string?
#include <iostream>
using namespace std;
int strlength(const char* c)
{
int size = 0;
while (*c) {
++c;
++size;
}
return size;
}
char* mystrdup(const char* c)
{
int size = strlength(c);
char* result = new char;
copy(c, c + size, result);
return result;
}
void print_array(const char* c)
{
int size = strlength(c);
while (*c) {
cout << *c;
++c;
}
}
int main()
{
char test[] = "Hello!";
char* res = mystrdup(test);
print_array(test);
print_array(res);
}
The program has undefined behavior because you are allocating not enough memory for the result string.
char* mystrdup(const char* c)
{
int size = strlength(c);
char* result = new char;
^^^^^^^^^^^^^^^^^^^^^^^
copy(c, c + size, result);
return result;
}
Moreover you are not copying the terminating zero to the result string.
At least the two functions strlength and mystrdup can look the following way
size_t strlength( const char *s )
{
size_t size = 0;
while ( s[size] ) ++size;
return size;
}
char * mystrdup( const char *s )
{
size_t size = strlength( s ) + 1;
char *result = new char[size];
copy( s, s + size, result );
return result;
}
Of course instead of the standard algorithm std::copy you could use the standard C function strcpy declared in the header <cstring>.
strcpy( result, s );
And do not forget to delete the allocated array.
char* res = mystrdup(test);
//…
delete [] res;
Pay attention to that the function print_array does not use the variable size. There is no need to output a C-string character by character.
The function could be defined like
std::ostream & print_array( const char *s, std::ostream &os = std::cout )
{
return os << s;
}
And at last the identifier c is usually used with single objects of the type char. If you deal with a string then it is better to use the identifier s.
You have multiple bugs in your code. You allocate wrong memory (char instead of char array). You don't delete the memory. Stop using C-string and use std::string
#include <iostream>
#include <string>
using std::cout;
void print_array(const char* c)
{
while (*c) {
cout << *c;
++c;
}
}
int main()
{
std::string = "Hello!";
std::string res = test;
print_array(test.c_str());
print_array(res.c_str());
}
In strcpy you need to create a char size.
char* mystrdup(const char* c)
{
int size = strlength(c);
char* result = new char[size];
copy(c, c + size, result);
return result;
}
This code works:
char* CFichierTrace::ConvertBSTRToString(BSTR* str)
{
if ( str == NULL )
{
char* buf = new char[2];
sprintf_s(buf, 2, "%s", "");
return buf;
}
else
return _com_util::ConvertBSTRToString(*str);
}
But I am trying to avoid multiple returns, bad programming I have been told. However it just wont work:
char* CFichierTrace::ConvertBSTRToString(BSTR* str)
{
// char* result = new char[1]; (attempt #1, produces garbage as output)
char* result = (char*) malloc(1 *sizeof(char)); (attempt #2, more garbage as output)
if ( str == NULL )
{
char* buf = new char[2];
sprintf_s(buf, 2, "%s", "");
result = buf;
}
else
result = _com_util::ConvertBSTRToString((BSTR) str);
return result;
}
There is an article about returning the string as a char** in argument (by ref), but I don't understand why a char* from the heap cannot be returned ?
char* CFichierTrace::ConvertBSTRToString(BSTR* str)
{
char* ret;
if ( str == NULL )
{
ret = new char[1];
ret[0] = 0;
}
else
ret = _com_util::ConvertBSTRToString(*str);
return ret;
}
And btw, you should not mix C++ new with C malloc.
Also, it is arguable that multiple return points is a bad practice. There are many situations when the code is more readable when you have multiple return points.
You'd do this:
char* CFichierTrace::ConvertBSTRToString(BSTR* str)
{
char* buf;
if ( str == NULL )
{
buf = new char[2];
sprintf_s(buf, 2, "%s", "");
}
else
buf = _com_util::ConvertBSTRToString(*str);
return buf;
}
I just suppose you know why you pass a pointer to a BSTR, instead of a BSTR.
char* CFichierTrace::ConvertBSTRToString(BSTR* str) {
return _com_util::ConvertBSTRToString(*str);
}
Due to BSTR-semantics, this is the proper implementation.
To clarify, all proper BSTR-functions treat NULL identical to a 0-length BSTR.
Anyway, use multiple return points wherever they make sense, unless you have a broken coding-standard disallowing such.
I have input strings that contain only digits (just the plain Latin ones, 0-9, so for example "0123"), stored as std::wstring, and I need each as a char*. What's the best way for me to do this? This is my initial approach:
void type::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
outputString = new char[outputSize];
size_t charsConverted = 0;
const wchar_t * inputW = input.c_str();
wcstombs_s(&charsConverted, outputString, sizeof(outputString), inputW, input.length());
}
EDIT: The code below works. Thanks all!
void type::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
size_t outputSize = input.length() + 1; // +1 for null terminator
outputString = new char[outputSize];
size_t charsConverted = 0;
const wchar_t * inputW = input.c_str();
wcstombs_s(&charsConverted, outputString, outputSize, inputW, input.length());
}
You are not allocating enough memory for your buffer:
char * outputString = new char[input.length()];
Should be
char * outputString = new char[input.length() + 1];
because of terminating NUL-character.
Oh, and also, as per pm100's comment: sizeof(outputString) is giving you the size of the pointer. You should use input.length() + 1, as that is the size of the buffer.
There are a couple of errors in your code. First, you're not allocating enough space in your destination buffer for the NULL character. You must allocate at least input.length() + 1 chars for the function to succeed.
Second, you're not passing in the correct size of the output buffer to the function. sizeof(outputString) returns the size of outputString itself, a char *, and not the number of bytes pointed to by that pointer.
So your function should look like this:
void CoverageTileManager::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
size_t outputSize = input.length() + 1;
outputString = new char[outputSize];
size_t charsConverted = 0;
wcstombs_s(&charsConverted, outputString, outputSize, input.c_str(), input.length());
// TODO verify charsConverted = outputSize
}
In C++ I would never use pure pointers: use vector if a char array needed in heap! Do you want to copy the source string? If not, const reference should be used for input. wcstombs_s is used only in Windows, so why doesn't use simply WideCharToMultiByte? Was the conversion success? Return value.
bool CoverageTileManager::convertWStringToCharPtr(const std::wstring& input, std::vector<char>& outputString )
{
if ( input.empty() ) {
return false;
}
int size = WideCharToMultiByte(CP_ACP,0,input.c_str(),input.size(),NULL,0,NULL,NULL);
if ( size <= 0 ) {
return false;
}
outputString.resize(size+1);
if ( WideCharToMultiByte(CP_ACP,0,input.c_str(),input.size(),&outputString[0],size,NULL,NULL) <= 0 ) {
outputString.clear();
return false;
}
outputString[size] = '\0';
return true;
}
Use vector to external C++ lib:
extern void call( const char*, size_t);
std::vector<char> buffer;
std::wstring input;
...
if ( convertWStringToCharPtr(input,buffer) ) {
call(&buffer[0],buffer.size());
}