Returning the address of a char* variable - c++

I'm currently developing a project and in one of my functions, I need to return the address of a char* variable.
Or maybe it's better to return the address of my string, but I don't know how to do this.
This is my code:
const char* rogner(){
int tableauXY[2];
tableauXY[0]=5;
tableauXY[1]=8;
string valeurs=to_string(tableauXY[0])+";"+to_string(tableauXY[1]);
const char* val1=valeurs.c_str();
return val1;
}

There are several ways to export string from extern "C" function:
1) Provide the second method to free release memory allocated:
extern "C" const char* getStr(...)
{
auto result = new char[N];
...
return result;
}
extern "C" void freeStr(const char* str)
{
delete[] const_cast<char*>(str);
}
2) Use OS allocator, e.g. in case of Windows:
// Client must call SysFreeString later
extern "C" const char* getStr(...)
{
auto result = SysAllocString(N);
...
return result;
}
3) Use client-provided buffer (there are a lot of variations how to tell the client what size buffer should have).
extern "C" int getStr(char* buffer, int bufSize, ...){}

There are many answers to your question. But one thing you can't do is return the address of a local variable. Returning the address of a local variable is undefined behavior, so forget about that option completely.
Since you stated that the function is part of a DLL, then it is better to use the "standard" ways to handle strings between a DLL and the client application.
One usual and widely used method is to have the client create the char buffer, and have the char buffer passed to you. Your function then fills in the user-supplied buffer with the information. Optional items such as size of the buffer can also be passed.
The above method is used by most functions in the Windows API that requires passing and returning strings.
Here is a small example:
#include <algorithm>
//...
char *rogner(char *buffer, int buflen)
{
int tableauXY[2];
tableauXY[0]=5;
tableauXY[1]=8;
string valeurs=to_string(tableauXY[0])+";"+to_string(tableauXY[1]);
// get length of buffer and make sure we copy the correct
// number of characters
size_t minSize = std::min(buflen, valeurs.length());
const char* val1=valeurs.c_str();
memcpy(buffer, val1, minSize);
// return the user's buffer back to them.
return buffer;
}
There are variations to the above code, such as
returning the number of characters copied instead of the original buffer.
If buflen==0, only return the total number of characters that would be copied. This allows the client to call your function to get the number of characters, and then call it a second time with
the buffer of the appropriate size.

Thanks for all, it works
I've used the PaulMcKenzie's method and it's good!
I have not tried the Nikerboker's solution so maybe it works too.
Thanks

Related

Why does a `char *` allocated through malloc prints out gibberish after the function allocating it returns?

I'm trying to write a function to parse and extract the components of a URL. Moreover, I need the components (e.g. hostname) to have the type char * since I intend to pass them to C APIs.
My current approach is to save the components in the parse_url function to the heap by calling malloc. But for some reason, the following code is printing gibberish. I'm confused by this behavior because I thought memory allocated on the heap will persist even after the function allocating it returns.
I'm new to C/C++, so please let me know what I did wrong and how to achieve what I wanted. Thank you.
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
void cast_to_cstyle(string source, char *target)
{
target = (char *)malloc(source.size() + 1);
memcpy(target, source.c_str(), source.size() + 1);
}
void parse_url(string url, char *protocol_cstyle, char *hostname_cstyle, char *port_cstyle, char *path_cstyle)
{
size_t found = url.find_first_of(":");
string protocol = url.substr(0, found);
string url_new = url.substr(found + 3); // `url_new` is the url excluding the "http//" part
size_t found1 = url_new.find_first_of(":");
string hostname = url_new.substr(0, found1);
size_t found2 = url_new.find_first_of("/");
string port = url_new.substr(found1 + 1, found2 - found1 - 1);
string path = url_new.substr(found2);
cast_to_cstyle(protocol, protocol_cstyle);
cast_to_cstyle(hostname, hostname_cstyle);
cast_to_cstyle(port, port_cstyle);
cast_to_cstyle(path, path_cstyle);
}
int main() {
char *protocol;
char *hostname;
char *port;
char *path;
parse_url("http://www.example.com:80/file.txt", protocol, hostname, port, path);
printf("%s, %s, %s, %s\n", (protocol), (hostname), (port), (path));
return 0;
}
The problem is that arguments are passed by value, so the newly created string never leaves the function (albeit exists until program termination as free is never called on it). You can pass by reference¹ like:
void cast_to_cstyle(string source, char *&target)
or better, pass the source string by (constant) reference too (string is expensive to copy):
void cast_to_cstyle(const string &source, char *&target)
(neither function body nor the call site need to be changed).
But you may not need even that.
If the API doesn’t actually modify the string despite using non-const pointer (pretty common in C AFAIK), you can use const_cast, like const_cast<char *>(source.c_str()).
Even if it may modify the string, &source[0] is suitable (at least since C++11). It may not seem right but it is:
a pointer to s[0] can be passed to functions that expect a pointer to the first element of a null-terminated (since C++11)CharT[] array.
— https://en.cppreference.com/w/cpp/string/basic_string
(and since C++17 data() is the way to go).
However, unlike that obtained from malloc any such pointer becomes invalid when the string is resized or destroyed (be careful “the string” means “that particular copy of the string” if you have several).
¹ Strictly speaking, pass a reference; references aren’t restricted to function arguments in C++.
The problem was as #WeatherVane and #JerryJeremiah mentioned. The pointer returned by malloc and assigned to target was in the local scope of cast_to_cstyle(), which got destroyed after the function returns. So the protocol, hostname, port, path variables declared in main were never assigned, hence it printed out gibberish. I've fixed this by making the cast_to_style() returns a char *.
char *cast_to_cstyle_str(string source)
{
char *target = (char *)malloc(source.size() + 1);
memcpy(target, source.c_str(), source.size() + 1);
return target;
}
Note: I forgot to free up malloc in my question.

Returning char* from dllexported function

I'm creating a DLL which will be used by some external exe file. One of the exposed function is
...
char *current_version = "1.1";
...
extern "C" _declspec(dllexport) char* version(){
return current_version;
}
Because the current version is used in multiple places I created the current_version variable. Will caller of the version function be able to change the content of current_version variable ? (I expect he'll).
If I'll change the code to:
...
const char *current_version = "1.1"; //this is preferable
...
extern "C" _declspec(dllexport) char* version(){
char local_copy[100] = make_local_copy(current_version);
return *local_copy;
}
will the local_copy variable be disposed after execution of the version function finishes (and in this case returned pointer will point at some random data) ? If so, what is the best way to return a pointer to const char* ?
Will caller of the version function be able to change the content of current_version variable ?
This is UB, so the actual behavior depends on implementation. There is a good chance that caller indeed could change this constant. In some implementations, string literals are stored in read-only memory, so attempting to write to it through a non-const pointer will throw a runtime error instead.
will the local_copy variable be disposed after execution of the version function finishes
Yes.
(and in this case returned pointer will point at some random data) ?
It will, in most implementations, point to an area of stack. Writing to it would corrupt program execution flow.
If so, what is the best way to return a pointer to const char* ?
There is no good way to do that in C++.
extern "C" _declspec(dllexport) void version(char* buffer, int* len)
{
if (buffer == NULL || *len <= 0)
{
char local_copy[100] = make_local_copy(current_version);
*len = strlen (local_copy);
return;
}
char local_copy[100] = make_local_copy(current_version);
*len = strlen (local_copy);
strcpy_s(buffer, *len, local_copy);
return;
}
This should be a good starting point. There may be bugs and also I recommend you use wchar instead of char. This is my best guess at a safe function with memory issues. User makes the first call to determine length required. dynamically allocate buffer in calling function and then call this method again. Or allocate memory and assign length if you already know the size of the buffer and the length, you will need to call this function just once.
About the questions, I agree with #Agent_L.
About the solution, I think you can use a static char array as a buffer. Just as follows:
static char local_copy[64];
static char current_version[] = "1.1";
char *version() {
strcpy(local_copy, current_version);
return local_copy;
}
Then you don't need to worry about disposing of local_copy.

Access violation writing location 0x00000000. memset function issues

#include <iostream>
#include <string.h>
using namespace std;
void newBuffer(char* outBuffer, size_t sz) {
outBuffer = new char[sz];
}
int main(void) {
const char* abcd = "ABCD";
char* foo;
foo = NULL;
size_t len = strlen(abcd);
cout<<"Checkpoint 1"<<endl;
newBuffer(foo, len);
cout<<"Checkpoint 2"<<endl;
cout<<"Checkpoint 2-A"<<endl;
memset(foo, '-', len);
cout<<"Checkpoint 3"<<endl;
strncpy(foo, abcd, len);
cout<<"Checkpoint 4"<<endl;
cout << foo << endl;
int hold;
cin>>hold;
return 0;
}
This program crashes between checkpoint 2-1 and 3. What it tries to do is to set the char array foo to the char '-', but it fails because of some access issues. I do not understand why this happens. Thank you very much in advance!
Your newBuffer function should accept the first parameter by reference so that changes made to it inside the function are visible to the caller:
void newBuffer(char*& outBuffer, size_t sz) {
outBuffer = new char[sz];
}
As it is now, you assign the result of new char[sz] to the local variable outBuffer which is only a copy of the caller's foo variable, so when the function returns it's as if nothing ever happened (except you leaked memory).
Also you have a problem in that you are allocating the buffer to the size of the length of ABCD which is 4. That means you can hold up to 3 characters in that buffer because one is reserved for the NUL-terminator at the end. You need to add + 1 to the length somewhere (I would do it in the call to the function, not inside it, because newBuffer shouldn't be specialised for C-strings). strncpy only NUL-terminates the buffer if the source string is short enough, so in this case you are only lucky that there happens to be a 0 in memory after your buffer you allocated.
Also don't forget to delete[] foo in main after you're done with it (although it doesn't really matter for a program this size).
It fails because your newBuffer function doesn't actually work. The easiest way to fix it would be to change the declaration to void newBuffer (char *&outBuffer, size_t sz). As it's written, the address of the newly allocated memory doesn't actually get stored into main's foo because the pointer is passed by value.
You are passing the pointer by value. You would need to pass either a reference to the pointer, or the address of the pointer.
That said, using the return value would be better in my view:
char* newBuffer(size_t sz) {
return new char[sz];
}
When written this way, the newBuffer function doesn't really seem worthwhile. You don't need it. You can use new directly and that would be clearer.
Of course, if you are using C++ then this is all rather pointless. You should be using string, smart pointers etc. You should not have any need to call new directly. Once you fix the bug you are talking about in this question you will come across the problem that your string is not null-terminated and that the buffer is too short to hold the string since you forgot to allocate space for the null-terminator. One of the nice things about C++ is that you can escape the horrors of string handling in C.

Why does windows need the size when calling a function?

I am trying to learn a little c++ and I have a silly question. Consider this code:
TCHAR tempPath[255];
GetTempPath(255, tempPath);
Why does windows need the size of the var tempPath? I see that the GetTempPath is declared something like:
GetTempPath(dword size, buf LPTSTR);
How can windows change the buf value without the & operator? Should not the function be like that?
GetTempPath(buf &LPTSTR);
Can somebody provide a simple GetTempPath implementation sample so I can see how size is used?
EDIT:
Thanks for all your answers, they are all correct and I gave you all +1. But what I meant by "Can somebody provide a simple GetTempPath implementation) is that i have tried to code a function similar to the one windows uses, as follow:
void MyGetTempPath(int size, char* buf)
{
buf = "C:\\test\\";
}
int main(int argc, char *argv[])
{
char* tempPath = new TCHAR[255];
GetTempPathA(255, tempPath);
MessageBoxA(0, tempPath, "test", MB_OK);
return EXIT_SUCCESS;
}
But it does not work. MessageBox displays a "##$' string. How should MyGetTempPath be coded to work properly?
Windows needs the size as a safety precaution. It could crash the application if it copies characters past the end of the buffer. When you supply the length, it can prevent that.
Array variables work like pointers. They point to the data in the array. So there is no need for the & operator.
Not sure what kind of example you are looking for. Like I said, it just needs to verify it doesn't write more characters than there's room for.
An array cannot be passed into functions by-value. Instead, it's converted to a pointer to the first element, and that's passed to the function. Having a (non-const) pointer to data allows modification:
void foo(int* i)
{
if (i) (don't dereference null)
*i = 5; // dereference pointer, modify int
}
Likewise, the function now has a pointer to a TCHAR it can write to. It takes the size, then, so it knows exactly how many TCHAR's exist after that initial one. Otherwise it wouldn't know how large the array is.
GetTempPath() outputs into your "tempPath" character array. If you don't tell it how much space there is allocated in the array (255), it has no way of knowing whether or not it will have enough room to write the path string into tempPath.
Character arrays in C/C++ are pretty much just pointers to locations in memory. They don't contain other information about themselves, like instances of C++ or Java classes might. The meat and potatoes of the Windows API was designed before C++ really had much inertia, I think, so you'll often have to use older C style techniques and built-in data types to work with it.
Following wrapper can be tried, if you want to avoid the size:
template<typename CHAR_TYPE, unsigned int SIZE>
void MyGetTempPath (CHAR_TYPE (&array)[SIZE]) // 'return' value can be your choice
{
GetTempPath(SIZE, array);
}
Now you can use like below:
TCHAR tempPath[255];
MyGetTempPath(tempPath); // No need to pass size, it will count automatically
In your other question, why we do NOT use following:
GetTempPath(buf &LPTSTR);
is because, & is used when you want to pass a data type by reference (not address). I am not aware what buf is typecasted to but it should be some pointer type.
Can somebody provide a simple
GetTempPath implementation sample so I
can see how size is used?
First way (based on MAX_PATH constant):
TCHAR szPath[MAX_PATH];
GetTempPath(MAX_PATH, szPath);
Second way (based on GetTempPath description):
DWORD size;
LPTSTR lpszPath;
size = GetTempPath(0, NULL);
lpszPath = new TCHAR[size];
GetTempPath(size, lpszPath);
/* some code here */
delete[] lpszPath;
How can windows change the buf value without the & operator?
& operator is not needed because array name is the pointer to first array element (or to all array). Try next code to demonstrate this:
TCHAR sz[1];
if ((void*)sz == (void*)&sz) _tprintf(TEXT("sz equals to &sz \n"));
if ((void*)sz == (void*)&(sz[0])) _tprintf(TEXT("sz equals to &(sz[0]) \n"));
As requested, a very simple implementation.
bool MyGetTempPath(size_t size, char* buf)
{
const char* path = "C:\\test\\";
size_t len = strlen(path);
if(buf == NULL)
return false;
if(size < len + 1)
return false;
strncpy(buf, path, size);
return true;
}
An example call to the new function:
char buffer[256];
bool success = MyGetTempPath(256, buffer);
from http://msdn.microsoft.com/en-us/library/aa364992(v=vs.85).aspx
DWORD WINAPI GetTempPath(
__in DWORD nBufferLength,
__out LPTSTR lpBuffer
);
so GetTempPath is defined something like
GetTempPath(DWORD nBufferLength, LPTSTR& lpBuffer);
What mean, that compiler passes the value lpBuffer by referenece.

Can I measure the necessary buffer for sprintf in Microsoft C++?

I'm writing a small proof-of-concept console program with Visual Studio 2008 and I wanted it to output colored text for readability. For ease of coding I also wanted to make a quick printf-replacement, something where I could write like this:
MyPrintf(L"Some text \1[bright red]goes here\1[default]. %d", 21);
This will be useful because I also build and pass strings around in some places so my strings will be able to contain formatting info.
However I hit a wall against wsprintf because I can't find a function that would allow me to find out the required buffer size before passing it to the function. I could, of course, allocate 1MB just-to-be-sure, but that wouldn't be pretty and I'd rather leave that as a backup solution if I can't find a better way.
Also, alternatively I'm considering using std::wstring (I'm actually more of a C guy with little C++ experience so I find plain-old-char-arrays easier for now), but that doesn't have anything like wsprintf where you could build a string with values replaced in them.
So... what should I do?
Your question is tagged C++, in which case I'd say std::wstringstream is the way to go. Example:
#include <sstream>
void func()
{
// ...
std::wstringstream ss; // the string stream
// like cout, you can add strings and numbers by operator<<
ss << L"Some text \1[bright red]goes here\1[default]. " << 21;
// function takes a C-style const wchar_t* string
some_c_function(ss.str().c_str()); // convert to std::wstring then const wchar_t*
// note: lifetime of the returned pointer probably temporary
// you may need a permanent std::wstring to return the c_str() from
// if you need it for longer.
// ...
}
You want _snwprintf. That function takes a buffer size, and if the buffer isn't big enough, just double the size of the buffer and try again. To keep from having to do multiple _snwprintf calls each time, keep track of what the buffer size was that you ended up using last time, and always start there. You'll make a few excess calls here and there, and you'll waste a bit of ram now and then, but it works great, and can't over-run anything.
I'd go for a C++ stringstream. It's not as compact as sprintf but it will give you the functionality you want.
If you can afford using boost, you could consider boost::format. It would give you the flexibility of std::strings, and formatting features of sprintf. It is fairly different from C-style, but is also fairly easy to use. Here's an example.
_scprintf, _scprintf_l, _scwprintf, _scwprintf_l
This functions will return the number of characters in the formatted string.
Using std::wstring seems like a good solution if you plan on passing strings between your objects - it handles the size and has a nice c_str method that will give you the array of wide chars.
The additional benefit is that you can pass it by reference instead of by pointer.
When you need the actuall string just use c_str method:
wprintf(L"string %s recieved!", myWString.c_str());
This answer is an expansion of the answer from #mheyman that uses vswprintf().
I also struggled with the same problem. The Microsoft documentation is weak, but this page was helpful: https://en.cppreference.com/w/c/io/vfwprintf
CppRef Description: If bufsz is greater than zero, writes the results to a wide string buffer. At most bufsz-1 wide characters are written followed by null wide character. If bufsz is zero, nothing is written (and buffer may be a null pointer).
CppRef Return value: Number of wide characters written (not counting the terminating null wide character) if successful or negative value if an encoding error occurred or if the number of characters to be generated was equal or greater than size (including when size is zero).
Roughly:
Measure required buffer size by calling vswprintf() with buffer == NULL and bufsz == 0
Call malloc() (or friends) to allocate a buffer.
Again, call vswprintf() with allocated buffer and buffer size + 1
Use result
Call free() on allocated buffer
Your example uses wchar_t: MyPrintf(L"Some text \1[bright red]goes here\1[default]. %d", 21);, so I recommend something like this:
#include <stdio.h> // includes both <wchar.h> and <stdarg.h>
#include <stdlib.h> // calloc()
void MyPrintf(const wchar_t *lpFormatWCharArr,
...)
{
// Ref: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/va-arg-va-copy-va-end-va-start?view=msvc-172
va_list ap;
va_start(ap, lpFormatWCharArr);
// does not include trailing NUL char
const int cch = vswprintf(NULL, // wchar_t *buffer
0, // size_t bufsz
lpFormatWCharArr, // const wchar_t *format
ap); // va_list vlist
va_end(ap);
if (cch < 0)
{
// handle error
}
const size_t NUL_CHAR_LEN = 1;
const size_t buf_len = cch + NUL_CHAR_LEN;
// malloc() is faster, but does not memset() result to zero
wchar_t *buf = calloc(buf_len, // size_t number
sizeof(wchar_t)); // size_t size
if (NULL == buf)
{
// handle error
}
va_list ap2;
va_start(ap2, lpFormatWCharArr);
// does not include trailing NUL char
const int cch2 = vswprintf(buf, // wchar_t *buffer
buf_len, // size_t bufsz
lpFormatWCharArr, // const wchar_t *format
ap2); // va_list vlist
va_end(ap2);
if (cch2 < 0)
{
// handle error
}
if (cch != cch2)
{
// handle error
}
// use 'buf' and 'buf_len'
free(buf);
}
There might be a (code) typo in this answer, but similar code was tested against 64-bit Win 10.