So, I am building a mockup of a licensing-system in C++.
char * LicenseServer::CreateHash (char* key)
{
char* newHash = nullptr;
//Create the hash if new key.
if (key != m_Key)
{
char* macAddr = GetMACAddress ();
size_t seed = 0;
boost::hash_combine (seed, std::string(key));
boost::hash_combine (seed, std::string(macAddr));
if (seed == size_t(0))
return nullptr;
std::stringstream sed;
sed << seed;
std::string seedstr = sed.str();
newHash = new char[seedstr.length() + 1];
strcpy_s (newHash, seedstr.length() + 1, seedstr.c_str ());
}
return newHash;
}
I am coming upon a strange error, though: every time I try to infer the declaration of a new char*, my input parameter "key", changes to an empty string.
It currently happens when I get to the strign-stream. Upon "std::stringstream sed", the key variable becomes "". Not null, but "".
It happened previously in the fucntion GetMACAddress as well, where I had declared
char newthing[4096]
Here it was solved by declaring
char* newthing = new char[4096];
It did not mirror the new content which I then put into newthing, just stayed "".
Why is the input parameter just casually cleared like this?
I am currently building in visual studio 2017, target 15063, on the c++latest tag.
Thank you very much.
EDIT:for a smaller code sample.
Related
I ame trying to get filenames from a directory and put it in a char* array for latter use. But this dont seem to work the way i want to. When printing it only showes the last filename on all spots.
So my question howe can i add the file names in every spot inside the char*[]?
/*Placed outside*/
int i = 0;
char* Files[20] = {};
/*Placed outside*/
while (handle != INVALID_HANDLE_VALUE)
{
char buffer[4100];
sprintf_s(buffer, "%ls", search_data.cFileName);
Files[i] = buffer;
i++;
if (FindNextFile(handle, &search_data) == FALSE)
/*Printing I use ImGui*/
#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR)))
static int listbox_item_current = 1;
ImGui::ListBox("", &listbox_item_current, Files, i, 4);
You could use C++ standard filesystem, but for that I guess you would need C++17 (or atleast VS15), not really sure.
You would have to include:
#include <experimental/filesystem>
#include <filesystem>
using namespace std::experimental::filesystem::v1;
Using it should be simple:
int i = 0;
const char * directoryToSearch = "C:\etc\etc";
for (const auto & file : directory_iterator(directoryToSearch)) {
files[i] = new char[file.path().stem().string().length() + 1];
strcpy(files[i], file.path().stem().string().c_str());
++i;
}
Indeed, you should clean up the array after you're done using it. Don't forget, not many compilers support this at the moment.
When printing it only shows the last filename on all spots. That is just normal: you store the filename on each iteration in the same buffer and just copy the address of the buffer into your array. Unrelated to the question, as buffer is an automatic variable declared inside a loop (block scoped), using it outside of the loop is Undefined Behaviour, so you end with an array of dangling pointers.
The correct way would be to either use a 2D-array char Files[MAX_PATH][20]; and store a file name in each slot, or use dynamic memory allocate by new (or malloc at a lower level). For the second option, you can do it by hand, allocating memory for each file name - and remember to free anything at the end, or you can let the standard library manage it for you by using:
std::vector<std::string> Files;
...
while(...) {
...
File.push_back(search_data.cFileName);
Dear ImGui provides a ListBoxctor that allows to pass an opaque data storage along with an extractor, and it can be used here:
bool string_vector_items_getter(void* data, int idx, const char** out_text) {
std::vector<std::string> *v = reinterpret_cast<std::vector<std::string> >(data);
if (idx < 0 || idx >= v.size()) return false;
*out_text = v[idx].c_str();
return true;
}
and then:
ImGui::ListBox("", &listbox_item_current, &string_vector_items_getter, &Files, i, 4);
(beware: untested code!)
I have created a unit test harness to test my program. I wanted it to be able to randomly test each run but I'm not sure how to go about doing this. Here is what I was think but I get stuck on what to do next, any guidance would be much appreciated.
int main (void)
{
int testNumber = 1; //for testing
char carName[] = "";
double carCost = 0;
carName = carChosen (testNumber);
carCost = assessCost (carName); //assessCost takes in the car name and checks what cost of the car will be (error checking so only certain cars can be chosen)
return 0;
}
"testNumber" would normally be seeded with time to create different number's from 1 - 15, but in this situation it's going to be "1" for testing.
This is next bit that I'm having trouble with. Within this function there would be 15 diffrent car options and it will return one depending on the randomly created number.
char carChosen (int randNum)
{
char carOne[] = "Honda";
char carTwo[] = "Ford";
if (randNum == 1)
{
return carOne; //local variables, not going to work...
}
else if (randNum == 2)
{
return carTwo; // Again, these return's are here to better represent what I'm trying to create but failing to do so..
}
}
I understand you cannot return local variables, what can I do instead?
This
void carChosen (int randNum, char * out)
{
char carOne[] = "Honda";
char carTwo[] = "Ford";
if (randNum == 1)
{
strcpy(out, carOne);
}
else if (randNum == 2)
{
strcpy(out, carTwo);
} //.. handle other cases
}
Call like
char carName[MAX_LEN];
carChosen (testNumber, carName);
Also maybe you are better of using switch instead of nested if..else if you have many conditions to test.
I thought it was C looking at the code, if you use C++, you can just return std::string objects from your function without any issues.
As others have pointed out, your code looks like C code. If you want to use C++, then read up on std::string and use that.
If you want to continue with your approach (which is very much a C-like approach), then you'll need to better understand how C strings work. Namely, how they are stored in memory and how a char is different from a char * is different from a char array[].
Putting most of that aside for now, my first guess based upon your example code is that you won't actually be modifying the contents of the string. You just want the string for its contents, but you won't be changing them. If this is accurate than you can just use regular char * variable to hold a pointer to a char string. You only need one copy of the string hanging around, so you can pass around a pointer to that one copy and everyone can read from that pointer. A quick way to do this is to just use the string literal directly.
const char* carChosen (int randNum)
{
if (randNum == 1)
{
return "Honda";
}
else if (randNum == 2)
{
return "Ford";
}
else
{
return "Audi";
}
}
Note that we are returning a const char *. The const is just indicating that we will not be modifying the string that is pointed to. We definitely do not want to do that because it points to a string literal (which you are not allowed to modify). Once you have the const char * returned by carChosen, you can pass that along to other functions, e.g. assessCost.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I have written this code (Uses V8 library). I went through it a couple of times and this feels like it's the only way I can write something like this. The aim of the function is to replace the JavaScript .split() function; as when using that function with a limit doesn't include the last part of the array in the returning array. EG:
var str = "Test split string with limit";
var out = str.split(' ', 2);
The array out will contain: [Test, split]. I want it to contain: [Test, split, string with limit].
I know there are pure JS ways to do this however I find them hacky and possibly slower(?) than a single C++ bind call.
Here's my function:
/**
* Explodes a string but limits the tokens
* #param input
* #param delim
* #param limit
* #return
*/
void ASEngine::Engine::ASstrtok(const v8::FunctionCallbackInfo<v8::Value>& args)
{
Assert(3, args);
Isolate* isolate = args.GetIsolate();
/* Get args */
String::Utf8Value a1(args[0]);
String::Utf8Value a2(args[1]);
Local<Uint32> a3 = args[2]->ToUint32();
std::string input = std::string(*a1);
std::string delim = std::string(*a2);
unsigned int limit = a3->Int32Value();
unsigned int inputLen = input.length();
// Declare a temporary array to shove into the return later
std::vector<char*> tmp;
tmp.reserve(limit);
unsigned int delimlen = delim.length();
char* cp = (char*) malloc(inputLen);
char* cursor = cp + inputLen; // Cursor
char* cpp = (char*) cp; // Keep the start of the string
// Copy the haystack into a modifyable char ptr
memset(cp + inputLen, 0x00, 1);
memcpy(cp, input.c_str(), inputLen);
unsigned int arrayIndex = 0;
for(unsigned int i=0;i<limit;i++)
{
if((cursor = strstr(cp, delim.c_str())) == NULL)
{
cursor = (char*) cpp + inputLen;
break;
}
for(int j=0;j<delimlen;j++)
*(cursor+j) = 0x00;
tmp.push_back(cp);
cp = cursor + delimlen;
arrayIndex++;
}
if(*(cp) != '\0')
{
arrayIndex++;
tmp.push_back(cp);
}
Handle<Array> rtn = Array::New(args.GetIsolate(), arrayIndex);
/* Loop through the temporary array and assign
the variables to the V8 array */
for(unsigned int i=0;i<arrayIndex;i++)
{
rtn->Set(i, String::NewFromUtf8(
isolate, tmp[i], String::kNormalString, strlen(tmp[i])
));
}
/* Clean up memory */
delete cpp;
cp = NULL;
cpp = NULL;
cursor = NULL;
isolate = NULL;
/* Set the return */
args.GetReturnValue().Set(rtn);
}
If you are wondering: The variable cpp is there so I can delete the character pointer after I am done (As calling v8's String::NewFromUtf8() function copies the string) and I modify the cp pointer during the process of the function.
Before optimising, I would fix the code so that it is correct.
char* cp = (char*) malloc(inputLen);
...
/* Clean up memory */
delete cpp;
Whilst in some implementations, new and malloc do exactly the same thing, other implementations do not. So, if you allocate with malloc, use free to free the memory, not delete.
If you want to be clever about it, I expect:
tmp.reserve(limit+1);
will ensure that you have space for the remainder of the string without further allocation in the vector.
Since cursor isn't used after the loop, setting it inside the if that breaks the loop makes no sense.
if((cursor = strstr(cp, delim.c_str())) == NULL)
{
cursor = (char*) cpp + inputLen;
break;
}
You are using casts to (char *) in places that don't need it, for example:
char* cpp = (char*) cp; // Keep the start of the string
(cp is a char * already).
This:
memset(cp + inputLen, 0x00, 1);
is the same as:
cp[inputlen] = 0;
but unless the compiler inlines the memset, much faster.
Likewsie:
*(cursor+j) = 0x00;
can be written:
cursor[j] = 0;
However, assuming delimLen is greater than 1, you could get away with:
for(int j=0;j<delimlen;j++)
*(cursor+j) = 0x00;
converted to:
*cursor = 0;
Since your new cp value will skip to beyond delimlen anyway.
These serve absolutely no purpose:
cp = NULL;
cpp = NULL;
cursor = NULL;
isolate = NULL;
Unfortunately, I expect most of the time in your function won't be in any of the code I've commented on. But in the passing arguments back and forth between the calling JS library and the native C++ code. I'd be surprised if you gain anything over writing the same code in JS. (None of the above make much of a difference when it comes to speed, it's just correctness and "a small number of potentially wasted cycles if the compiler is rather daft").
I want to assign string to char array
here is code -
char *resultArray[100];
int cnt = 0;
void MySAX2Handler::startElement(const XMLCh* const uri, const XMLCh* const localname,
const XMLCh* const qname, const Attributes& attrs)
{
char* message = XMLString::transcode(localname);
resultArray[cnt] = message;
cnt++;
for (int idx = 0; idx < attrs.getLength(); idx++)
{
char* attrName = XMLString::transcode(attrs.getLocalName(idx));
char* attrValue = XMLString::transcode(attrs.getValue(idx));
resultArray[cnt] = attrName;
cnt++;
resultArray[cnt] = attrValue;
cnt++;
}
XMLString::release(&message);
}
after iterating through resultArray, its printing some garbage values
attrName and attrValue are both pointers and char is a type of integer, so the assignment operator will simply copy the value of the pointer (the address), not the content.
Either loop through the strings or use some version of strcpy(), or indeed one of the C++ string libraries.
First off, when you declare your array, you should use
char *resultArray = new ResultArray[100];
vs
char *resultArray[100];
Next, you shouldn't ever use a loop to fill up a bounded array without knowing the limits of the loop. You will overflow your array, and cause a segfault. Unless of course you know your length won't reach close to 100. (still a bad idea, but to slap something together quickly, I won't complain)
Without more information, I can't tell you why you're getting garbage. How are you printing these out? What do those 'transcode' functions do? Where is the data coming from?
PS - remember you can use
resultArray[cnt++] = attrName;
resultArray[cnt++] = attrValue;
I've got an string array
string name[1000];
and with
int counter;
counter = 0;
while(FindNextFile(fHandle, &wf))
{
... //some more code which is checking if its a folder
string theName = wf.cFileName;
if(theName.find(".bmp") != std::string::npos)
{
name[counter] = theName;
counter++;
}
}
I am adding each .bmp file to my name array.
Using NeHe's Tutorial I'm adding Textures to my Qubes, which is working very well.
Now my customized code looks like this:
int n; string imageFileString[1000]; char *imageFile[1000];
for(n=0; n<1000; n++)
{
imageFileString[n] = name[n];
imageFile[n] = new char[imageFileString[n].length()];
strcpy(imageFile[n], imageFileString[n].c_str());
if(TextureImage[n] = loadBMP(imageFile[n]))
{
... // Some more Functions to set textures
}
}
Everything is working well, only that my BMP Files arent loaded.
If I add
name[0] = "pic1.bmp";
name[1] = "pic2.bmp";
name[2] = "pic2.bmp";
name[3] = "pic2.bmp";
before setting the int n; string imageFileString..., so for the for(...) loop my Pictures are loaded without changing anything else. My first opinion was that the name array has no entrys, but I created a Log file with the output
name[0] << endl << name[1] << endl << name[2] ...
and in my Log file were the same names
pic1.bmp
pic2.bmp
pic3.bmp
so I think there is some other error adding the cFileName to my array.
Can anyone help me please? I dont know how to fix this, i mean I've no idea what is wrong...
imageFile[n] = new char[imageFileString[n].length()];
You're not accounting for the null-terminator. Add one to the length:
imageFile[n] = new char[imageFileString[n].length() + 1];
This isn't an answer, but it would be too hard to post in a comment.
Why are you doing all this?
int n; string imageFileString[1000]; char *imageFile[1000];
for(n=0; n<1000; n++)
{
imageFileString[n] = name[n];
imageFile[n] = new char[imageFileString[n].length()];
strcpy(imageFile[n], imageFileString[n].c_str());
if(TextureImage[n] = loadBMP(imageFile[n]))
{
... // Some more Functions to set textures
}
}
When you could just do this?
int n;
for(n=0; n<1000; n++)
{
if(TextureImage[n] = loadBMP(name[n].c_str()))
{
... // Some more Functions to set textures
}
}
Since you said everything works fine when you do name[0] = "pic1.bmp" etc, you need to print out/debug string theName = wf.cFileName; I would guess it is a pathing issue. wf.cFileName is probably returning a file path you aren't expecting.
For example I bet it's returning something like \MyData\Bitmaps\pic1.bmp where you are only expecting pic1.bmp
Update
Given all the other wonderful changes, you can also shorten it even further and do this
int counter = 0;
while (FindNextFile(fHandle, &wf))
{
if (strstr(wf.cFileName, ".bmp") != 0)
{
if(TextureImage[counter] = loadBMP(wf.cFileName)
{
... // Some more Functions to set textures
counter++
}
}
}
There isn't any reason to allocate more memory just to check if a string (".bmp") is present. Also note I don't update the counter unless the load succeeds.
You really should switch TextureImage to a std::vector then you wouldnt have to do any counting. Check to see if you pass wf.cFileName directly to your loadBMP if things work. And I do realize that this could present in an overflow due to TextureImage[] and counter which is why I suggest switching to std::vector. We don't see how he allocates TextureImage[], if it's like everything else it was with a magic number of 1000.
Also keep in mind that .cFileName is defined as TCHAR[] which can hold unicode values.
Ok I found the Problem myself,
Update, fixed version (WinMain):
void ScanTheDirectory()
{
// this function is scanning the directory and is adding
// each bmp file to the string array "name"
}
int initGL()
{
// this function calls the loadTextures() function
}
int loadTextures()
{
// this function is loading all files of the string array "name"
// converts them to a const char * and is adding them to the "textures" GLuint (array)
}
int WINAPI WinMain()
{
// this function is the main window which is showing the
// qubes (GL_QUBES)
ScanTheDirectory();
initGL();
}
The Problem was in WinMain(), because it looked like this:
initGL();
ScanTheDirectory();
If it is first calling the initGL(), so it is creating the Textures, and because the name array is empty, there are no Textures added to my Textures array.
After changing this to
ScanTheDirectory();
initGL();
Now it is first calling the ScanTheDirectory() void and so my name array is filled with names of BMP Image Files.
Now it can call the initGL and this is creating the Textures out of my Images.
Thanks for the Help, now my Code is looking a little bit clearer :D
Ahmet