C++ std::string to char for using with OpenGL LoadBMP - c++

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

Related

For loop in C++ stops after a single iteration w/ pointer variable

So first all I'll preface this with: I just started using c++.
I have a structure that I store the pointer to in an unordered_map, setting members' values in the struct pointer as I get them through my process. Then I no longer need them in a map so I transfer then to a vector and loop through them.
Though on the second loop, it outputs my index (1) but the next statement of making a local pointer var for the struct at that index breaks it and the code terminates without any errors. since there are no errors then a try/catch doesn't give me anything either.
// Wanted to create a structure to handle the objects easier instead
// of multiple vectors for each property
struct appData {
std::string id = "";
std::string name = "";
std::string vdf_file = "";
std::string vdf_path = "";
};
// Relevant parts of my main()
int main() {
// Map that stores all the struct pointers
std::unordered_map<std::string, appData*> appDatas;
char memory[sizeof(appData)];
void* p = memory;
// New instance of appData
appData *tempAppData = new(p) appData();
tempAppData->appid = "86901";
// Add tempAppData to map with string key
appDatas["86901"] = tempAppData;
...
std::vector<appData*> unhashed_appDatas;
for (auto const& pair: appDatas) {
unhashed_appDatas.push_back(pair.second);
}
...
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
// Output index to see where it was messing up
std::cout << x << std::endl;
!! // This is where the issue happens on the second loop (see output)
appData *thisAppData = unhashed_appDatas[x];
std::string id = thisAppData->appid;
std::cout << id << std::endl;
/* ...
Do more stuff below
*/
}
...
return 0;
}
Terminal Output:
0 // Initial index of x
86901 // Id of first item
1 // New index of x on second loop before pointer var is created
// Nothing more is printed and execution terminates with no errors
My knowledge of c++ is pretty lacking, started it couple days ago, so the few things within my knowledge I've tried: moving the *thisAppData variable outside of the loop, using a for(var: vector) { ... }, and a while loop. I can assume that the issue lies with the pointer and the local variable when inside the loop.
Any help/input about how I could better approach this or if there's an issue with my code would be appreciated :)
Edit: Changed code to use .size() instead of sizeof() per #Jarod42 answer, though main issue persists
Edit2: Turns out it was my own mess-up, imagine that. 4Am brain wasn't working too well- posted answer regarding what I did incorrectly. Thanks to everyone who helped me
sizeof is the wrong tool here:
for (unsigned int x = 0; x < sizeof(unhashed_appDatas); x++) {
// ^^ wrong: give **static** size of the structure
// mainly 3 members (data, capacity, size), so something like `3*sizeof(void*)`
it should be
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
After many hours of trial and error I have determined the issue (aside from doing things in a way I should, which I've since corrected) it was something I messed up on that caused this issue.
TLDR:
Items wouldn't exist that I assumed did and tried to read files with a blank path and parse the contents that didn't exist.
Explaination:
In the first loop, the data I was getting was a list of files from a directory then parsing a json-like file that contained these file names and properties associated with them. Though, the file list contained entries that weren't in this other data file (since I had no check if they existed) so it would break there.
Additionally in the last loop I would get a member from a struct that would be the path of a file to read, but it would be blank (unset) because it didn't exist in data file so std::ifstream file(path); would break it.
I've since implemented checks for each key and value to ensure it will no longer break because of that.
Fixes:
Here are some fixes that were mentioned that I added to the code, which did help it work correctly in the end even if they weren't the main issue that I myself caused:
// Thanks to #EOF:
// No longer "using placement new on a buffer with automatic storage duration"
// (whatever that means haha) and was changed from:
char memory[sizeof(appData)];
void* p = memory;
appData *tempAppData = new(p) appData();
// To:
appData *tempAppData = new appData();
// Thanks to #Jarod42:
// Last for loop limit expression was corrected from:
for (unsigned int x = 0; x < sizeof(unhashed_appDatas); x++) {
}
// To:
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
}
// I am still using a map, despite comment noting to just use vectors
// (which I could have, but just would prefer using maps):
std::unordered_map<std::string, appData*> appDatas;
// Instead of doing something like this instead (would have arguably have been easier):
std::vector<std::string> dataKeys = { "1234" };
std::vector<appData*> appDatas = { ... };
auto indx = find(dataKeys.begin(), dataKeys.end(), "1234");
indx = (indx != dataKeys.end() ? indx : -1);
if (indx == -1) continue;
auto dataItem = appDatas[indx];
//
I appreciate everyone's assistance with my code

How to populate file attributes from a directory into a struct vector?

I'm brand new to C++ and I'm trying to learn on my own, so I'm running into a lot of simple issues. Right now I want to look at a directory, containing files that end in ".img", and push only the file name and creation time into a struct vector.
How does a push_back into a vector work? Does each struct pushed back populate into the vector or is it possible to make a mistake and be overwriting the previous push_back? I don't know if I'm over thinking this...
Could someone please take a look at my code and let me know if I'm doing this correctly or where I may need to make changes? Thank you so much!
void filterContextByHsiTime(const char *context_path, int hsi_create_time) {
struct contextFileStruct { //Define Struct containing key elements of a file
double createTime;
string fileName;
};
std::vector<contextFileStruct> contextVector; //Initialize resizable vector array of type contextFileStruct
contextFileStruct tempStruct;
_finddata_t allFiles; //Structure that holds file specific elements
int findFirstContextImage = _findfirst(context_path, &allFiles); //Int variable holding result of the findfirst function
//where -1 = no image fround and any other number = image found
tempStruct.fileName = allFiles.name;
tempStruct.createTime = allFiles.time_create;
contextVector.push_back(tempStruct);
if (findFirstContextImage != -1 ) {
int findNextContextImage = 0; //iterator for next context image in dir
while (findNextContextImage != -1) {
findNextContextImage = _findnext(findFirstContextImage, &allFiles);
tempStruct.fileName = allFiles.name;
tempStruct.createTime = allFiles.time_create;
contextVector.push_back(tempStruct);
}
_findclose(findFirstContextImage); //Close findfirst file function to prevent memory leaks
}
else {
cout << "There are no .img files in this directory!" << endl; //error handling for when there are no context files
}
}
I was looking at it incorrectly in the debugger. Instead of reviewing the populating of the vector, I was just looking at the struct populating and then adding the next file, so it looked as if it was overwriting. Silly error on my part. My code is working as I intended, thanks!

How to initialize an array of pointers (or do I need to do so at all)?

It's for my college exam, so don't ask why I'm not using advanced stuff in C++.
This is a console app. The problem to solve is to write missing functions inside defined structures. It is simulation of entrance exam so there's this question struct that has its attributes as follows:
char* _txtOfQuestion;
char* _answers[10]; //max 10 answers
int _correct; //location of the correct answer
int _points; //no. of points
Now, I need to implement the function Create() of this struct, which is responsible for initialising all the structure attributes.
I thought the parameters should be:
Create(char* text, char* answers[], int posOfCorrect, int points){
_txtOfQuestion = new char[strlen(text)+1];
strcpy_s(_txtOfQuestion , strlen(text), text);
// now this _question[10] attribute seems to be the toughest here
// as it happens to be an array
// how to initialize it here or if init. is not necessary, then
// how to assign it to this parameter answers, to that it fits?
// code here....
_correct = posOfCorrect;
_points = points;
}
Why don't you try something like this:
for (int i = 0; i < 10; ++i)
{
if (answers[i] != nullptr)
{
_answers[i] = malloc(strlen(answers[i])+1);
strcpy(_answers[i], answers[i]);
}
else
break;
}
of course you can omit nullptr check.
Is that helpful?

Wrong output when printing a string from inside a struct pointer (VC++ 2010)

I've found a very strange issue with both printf (and printf_s), and also std::cout. I'm not sure if it's some short of "glitch" or error in these functions, or if I'm doing something wrong. Since both functions do the same, I'm assuming I'm not doing it the right way.
I have the following structures in my program (By the way, this is a Visual C++ 2010 project):
#pragma pack(push, 1)
typedef struct nameentry
{
char NAME[17];
char EXT[4];
}NAMEENTRY;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct fileentry
{
unsigned int ID;
NAMEENTRY FILENAME;
unsigned int GPFID;
unsigned long long int FPOINTER;
size_t FILESIZE;
}FILEENTRY;
#pragma pack(pop)
Now I have the following portion of code:
NAMEENTRY fname = MCreateNameEntry("LONGFILE.JPG");
FILEENTRY* myfile_ = SearchFileByPkgID(0, fname);
printf("%s", myfile_->FILENAME.NAME);
So what this code is supposed to do is, create an instance of NAMEENTRY with NAME=LONGFILE, and EXT=JPG. Both character arrays are null terminated (last byte is a 0). Then create an instance of FILEENTRY with it's corresponding data from a database I'm developing, then print the name of the file from the FILEENTRY's NAMEENTRY structure.
After running the code, what I get instead of the name of the file, is... garbage. The classic garbage you get when trying to print text from a bad pointer. If I try to print any of the other fields, I also get wrong values.
So obviously, my first thought was that one of my functions were not returning the right value. So I started inspecting the code and, to my surprise, they are actually returning the right values and the structure is filled with the right data. I get the proper values in each field, every character array ends with a 0, etc.
So then I said... "What if I copy the entire block into another instance of FILEENTRY?", and I tried this:
NAMEENTRY fname = MCreateNameEntry("LONGFILE.JPG");
FILEENTRY* myfile_ = SearchFileByPkgID(0, fname);
FILEENTRY dMem;
memcpy(&dMem, myfile_, sizeof(FILEENTRY));
printf("%s", dMem.FILENAME.NAME);
And guess what? It works perfectly fine. I get the name of the file, no garbage. So I'm assuming, either the problem is inside of printf (I also tried std::cout with the same results), or I am doing something wrong when using these functions.
Well, that helps. Seems like the problem was trying to return a pointer to a local variable, as Igor Tandetnik suggested.
So as a workaround, I'm not sure if this is a proper way of handling this, instead of define a local variable, I'm using calloc to allocate a memory block for a FILEENTRY pointer, then fill it and return it. And yes, it seems to work this way.
This is the actual code of the function:
FILEENTRY* SearchFileByPkgID(int ID, NAMEENTRY fname)
{
FILEENTRY* myFile = (FILEENTRY*)calloc(sizeof(FILEENTRY),1);
std::vector<int> results;
unsigned int* dptable = GetDPTableByPkgId(ID);
bool found = false;
for(int x = 0; x < 1024; x++)
{
if(dptable[x] > 0)
{
fseek(PDBFILE, dptable[x], SEEK_SET);
fread(myFile, sizeof(FILEENTRY), 1, PDBFILE);
if(strcmp(myFile->FILENAME.EXT, fname.EXT) == 0)
if(myFile->FILENAME.NAME[0] == fname.NAME[0])
results.push_back(dptable[x]);
}
}
for(int y = 0; y < results.size(); y++)
{
fseek(PDBFILE, results[y], SEEK_SET);
fread(myFile, sizeof(FILEENTRY), 1, PDBFILE);
if(strcmp(myFile->FILENAME.NAME, fname.NAME) == 0)
{
found = true;
break;
}
}
results.clear();
if(found)
return myFile;
else
return 0L;
}
Any more suggestions are wellcome.

A class array inside of a class - issues with dynamic arrays (c++)

My homework is that I have to make a class (register) which contains 3 class arrays (birds, mammals, reptiles) which are in the animal class. Animal is the friend of Register. I will only show the birds part, to keep it simple.
The register class looks like:
class Register
{
Bird* birds;
unsigned int birdSize;
public:
...
}
The constructor of register:
Register::Register()
{
this->birds = new Bird[0];
this->birdSize = NULL;
}
Now I have a function in register that adds one element to the birds array, the input is cin.
void Register::add()
{
...
if (birdSize == 0)
{
birds = new Bird[0];
Bird* temp = new Bird[0];
temp[0].add();
this->birds = temp;
birdSize++;
}
else
{
Bird* temp = new Bird[birdSize+1];
for (unsigned int i=0; i<=birdSize; i++)
{
temp[i] = this->birds[i];
}
temp[birdSize+1].add();
birds = new Bird[birdSize+1];
birds = temp;
birdSize++;
}
temp[0].add() has the cin, it works properly. When I run the program, the user has to add 2 birds to the array. The problem occurs when reaching the part under 'else', so the second element of the array. The program surely reaches "temp[birdSize+1].add();" while running, then the "xyz.exe has stopped working" window pops up and it says in the details " Fault Module Name: StackHash_7e8e" so I'm sure something is wrong with the memory allocation, but the problem is that when I try to find the problematic line in debug mode, everything works fine.
Well, not everything. The program has a print() function, it prints out everything in Register. The second element of the array is the same as the first.
I have no clue what to do. I read many forum posts, read a cpp book, watched online tutorials, but I can't find the solution for this problem. Please help.
Array index starts from 0. So in else part you are writing
Bird* temp = new Bird[birdSize+1]; // size =birdSize +1;
So valid index range will be 0 -> birdSize, not birdSize+1.
The problem is
temp[birdSize+1].add();
you are using birdSize+1th index. It should be
temp[birdSize].add();
There are other bugs in your code:
for (unsigned int i=0; i<=birdSize; i++) // should be i<birdSize
{
temp[i] = this->birds[i];
}
There are other bad coding in your program:
Register::Register()
{
this->birds = new Bird[0]; // should be this->birds=NULL
this->birdSize = NULL; // should be this->birdSize = 0
}
And obviously if your homework does not demand it, you should not use arrays in this way. For variable size container, use vector, list.... Array is only when the size is fixed.