I want to pass a string (char *) to a function inside a dll to overwrite it with another string.
File dll.cpp
__declspec(dllexport) void getString(char *name, char *buffer, int len) {
std::string str = getString(); // buffer should be overwritten with this string
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
strncpy(buffer, cstr, len);
}
File main.cpp
char *buffer;
getString("z", buffer, 128);
printf("%s", buffer);
I dont know how to correctly pass the buffer to overwrite it.
It's pretty clear you're confused about pointers. It looks like your use of cstr is at attempt to give buffer some memory, but that won't work and cstr is unnecessary.
Here's the correct code, buffer is allocated in main, and cstr is eliminated.
char *buffer = new char[128];
getString("z", buffer, 128);
printf("%s", buffer);
__declspec(dllexport) void getString(char *name, char *buffer, int len)
{
std::string str = getString();
strncpy(buffer, str.c_str(), len);
}
Note that strncpy is a dangerous function to use as it doesn't guarantee that the output is nul terminated. I would prefer to see code like this
__declspec(dllexport) void getString(char *name, char *buffer, int len)
{
if (len == 0)
{
// some kind of error handling
}
std::string str = getString();
strncpy(buffer, str.c_str(), len - 1);
buffer[len - 1] = '\0';
}
Related
I have the following code to append a buffer using vsnprintf().
#include <stdio.h>
#include <stdarg.h>
using namespace std;
void MyPrintFunc(char *buffer, size_t sizeOfBuffer, const char* format, ...)
{
va_list arg;
va_start(arg, format);
vsnprintf(buffer, sizeOfBuffer, format, arg);
va_end(arg);
}
int main()
{
char buffer[1000] = { 0 };
const char* abc = "abc";
const char* def = "def";
MyPrintFunc(buffer, 1000, "%s", abc);
MyPrintFunc(buffer, 1000, "%s%s", buffer, def);
printf("%s\n", buffer);
return 0;
}
It gave different output on both Windows and Linux.
On Windows (using msvc-14.0 compiler), it give desired output of abcdef.
But on Linux (using gcc-5.4), it only print output of def.
How can I get the correct output?
Don't use the same buffer as both an output and input to vsnprintf.
Thanks everyone for the input.
My solution to this is to create a copy of the buffer if user of the MyPrintFunc() used it to append buffer:
void MyPrintFunc(char *buffer, size_t sizeOfBuffer, const char* format, ...)
{
va_list arg;
va_list arg_copy;
va_start(arg, format);
va_copy(arg_copy, arg);
if (buffer == va_arg(arg, char*))
{
char temp[strlen(buffer)];
strcpy(temp, buffer);
MyPrintFunc(buffer, sizeOfBuffer, format, temp, va_arg(arg,char*));
}
else
{
vsnprintf(buffer, sizeOfBuffer, format, arg_copy);
}
va_end(arg);
va_end(arg_copy);
}
#define printm(X) handleVarArgs X
void writeFile(std::string & s)
{
FILE *fp;
fopen("test.txt","w");
fputs( s.c_str(), fp );
fclose(fp);
}
void handleVarArgs( char* format, ...)
{
std::string s;
va_list args;
va_start (args, format);
vsprintf (const_cast<char *>(s.c_str()),format, args);
va_end (args);
writeFile(s);
}
const char * func() {
std::string errorLog("Kiev");
return errorLog.c_str();
}
int main()
{
printm(("My Name is %s and surname is %s and age is %d",func(),"john",25));
return 0;
}
I am getting segmentation fault if i call writeFile() function. But no segmentation fault when i remove writeFile()
What is the relationship between Files and Var Args?
You are writing directly in a string.c_str(), simply by removing its constness with a const_cast. This is bad and invoke undefined behaviour. So what happens next is simply undefined ...
The correct approach for handleVarArgs would be :
allocate a bunch of memory from the heap (with malloc or new[])
use vsnprintf to try to write there
if the return value (say sz) is greater or equal to the allocated size, then free it and realloc a bunch of size sz+1 and iterate
then you can safely create a std::string from that char array and use it
do not forger to call free (or delete[]) when finished with the malloc'ed array
Something like :
void handleVarArgs( char* format, ...)
{
#define DEF_SZ 256
int sz = DEF_SZ;
std::string s;
while(1) {
char * buf = new char[sz];
va_list args;
va_start (args, format);
int l = vsnprintf (buf , sz, format, args);
va_end (args);
if (l < sz) {
s = buf;
writeFile(s);
delete[] buf;
return;
}
sz = l + 1;
delete[] buf;
}
}
What is the value of fp after opening a file?
How does it relate to the value from before opening a file?
The debugger is Your best friend.
It should read: FILE *fp = fopen("test.txt","w");
Not mentioning that You should check wether the fopen succeeded.
I stumbled across a weird behaviour in MSVC (2013) recently which I wanted to clarify concerning variable arguments.
It appears having more than one parameter before the '...)' causes unexpected behaviour
int formatString(const char* msg, char* buffer, int bufferLength, ...)
{
int length = 0;
if (msg != nullptr) {
va_list args;
va_start(args, msg);
length = vsnprintf_s(buffer, bufferLength, bufferLength, msg, args);
va_end(args);
}
return length;
}
Calling this function like so
const char* message = "A word: %s and a number %d";
const int bufferLength = 1024;
char buffer[bufferLength];
int formattedMsgLen = formatString(message, buffer, bufferLength, "cheese", 4);
Will immediately cause the program to crash. If I memset the buffer to 0 before
memset(buffer, 0, 1024); // We know sizeof(char) == 1
This is written to the buffer:
"A word: A word: and a number 1024".
Which is completely wrong...
If however, I change the function to take a struct with the first three arguments combined
struct Message
{
const char* msg;
char* buffer;
int bufferLength;
};
int formatString(Message msg, ...)
{
int length = 0;
if (msg.msg != nullptr) {
va_list args;
va_start(args, msg);
length = vsnprintf_s(msg.buffer, msg.bufferLength, msg.bufferLength, msg.msg, args);
va_end(args);
}
return length;
}
When calling the new function like so:
const int bufferLength = 1024;
char buffer[bufferLength];
Message msg;
msg.buffer = buffer;
msg.msg = "A word: %s and a number %d";
msg.bufferLength = bufferLength;
int formattedMsgLen = formatString(msg, "cheese", 4);
This is written to the buffer:
"A word: cheese and a number 4"
Which is correct and this is what I would expect. Am I right in thinking you are only able to use vaargs with a function with only one parameter before? I don't think this is the case as the functions below have more than one first parameter
int fprintf(FILE *, const char *fmt, ...);
int sprintf(char *s, const char *fmt, ...);
Could this potentially be a bug in the compiler? However unlikely....
It probably isn't and I've done something stupid but I am definitely confused by what is happening. If anyone can shed some light on this I would be very grateful.
Thanks!
va_start() must be called with the name of the last parameter before the variable argument list:
int formatString(const char* msg, char* buffer, int bufferLength, ...)
{
// ...
va_list args;
// va_start(args, msg); <-- WRONG!
va_start(args, bufferLength);
// ...
}
the best way to keep a pointer in main changes reflected inside the class?
static unsigned char tmp[][20] = {"hello world", "bye world"};
class X {
unsigned char ** buffer;
public:
X(unsigned char* buff)
{
buffer = &buff;
}
void printThis()
{
DBG_MSG_FORMATED(".......> %s", *buffer);
}
};
int main (int argc, char * const argv[]) {
unsigned char * buff = new unsigned char[20];
memcpy(buff, tmp[0], 12);
X x(buff);
x.printThis();
memcpy(buff, tmp[1], 12);
x.printThis();
delete [] buff;
return EXIT_SUCCESS;
}
this works, but when I do the follow
buff = tmp[0];
x.printThis();
the printout doesnt print hello world again??? how to fix that
You'll need to use a pointer to pointer in your class (gulp!):
class X {
unsigned char ** buffer;
public:
X(unsigned char** buff)
{
buffer = buff;
}
void printThis()
{
DBG_MSG_FORMATED(".......> %s", *buffer);
}
};
And then pass in the address of the pointer during construction:
X x(&buff);
int main (int argc, char * const argv[]) {
unsigned char * buff = new unsigned char[20];
memcpy(buff, tmp[0], 12);
X x(buff);
x.printThis();
delete [] buff;
buff = tmp[1];
x.printThis();
return EXIT_SUCCESS;
}
After you have done delete buff;, your pointer buffer in the class is pointing at memory that has been deleted, which is very bad news.
If you want to store the actual address of buff, you would need to pass the address of buff and store that, like this:
char **buffer;
X(unsigned char** buff)
{
buffer = buff;
}
void printThis()
{
DBG_MSG_FORMATED(".......> %s", *buffer);
}
...
X x(&buff);
Or you could make buffer a reference to buff:
char*& buffer;
X(unsigned char*& buff) : buffer(buff) {}
(No other changes needed in class or other code - but note that you can't do buffer = some_other_buffer; at a later stage - that will change the value of buff to some_other_buffer, which is probably not what you expected).
You can do something thing as bellow (using a pointer to a pointer), but sincerally, this more a problem than a solution because you are unable to delete tmp without a good care with the pointer in class X
#include <cstdio>
#include <cstring>
static unsigned char tmp[][20] = {"hello world", "bye world"};
class X {
unsigned char ** buffer;
public:
X(unsigned char** buff)
{
buffer = buff;
}
void printThis()
{
printf(".......> %s", *buffer);
}
};
int main (int argc, char * const argv[]) {
unsigned char * buff = new unsigned char[20];
memcpy(buff, tmp[0], 12);
X x(&buff);
x.printThis();
buff = NULL;
buff = tmp[1];
x.printThis();
}
I want to receive bytes into conbuf.buffer. either of test 1 or test2 is ok. I am not seeing any value in printf statement. Am I passing in the pointer correctly? How do I allocate memory to a char pointer inside a struct.
typedef struct cBuf
{
int size;
char *buffer;
} cbuf;
class A
{
cbuf conbuf;
void test();
}
void A::test()
{
int buffersize = 20;
char buf[buffersize];
conbuf.buffer = (char *)malloc(buffersize * sizeof(char *));
// test 1
int n = socket.receivebytes(conbuf.buffer, buffersize);
// test 2
//int n = socket.receivebytes(buf, buffersize);
//strcpy(conbuf.buffer, buf);
printf("conbuf.buffer %s \n", conbuf.buffer);
}
this
conbuf.buffer = (char *)malloc(buffersize * sizeof(char *));
should be
conbuf.buf = (char *)malloc(buffersize * sizeof(char)); //allocate space for char not pointer to char. Your struct only has buf member not "buffer"
Use this:
conbuf.buffer = (char *)calloc( (buffersize * sizeof(char))+1,1);
since printf requires last char of string to be null terminated, this ensures it. But data received from network may already contain NUL in the middle. So instead of using printf you should use fwrite:
fwrite(conbuf.buffer,buffersize , STDOUT);
I'd suggest you to redirect it in a file and do a hex dump to see the output.