I know there are a lot of questions similar to this, but I don't know of any that are the same, so here's my issue:
I'm trying to pass a filename as a const char * to my ifstream to read and load.
BUT: When I pass the filename, instead of reading the whole string "map.obj"; it just reads the first character "m" and as a result, the ifstream fails.
I don't know what I'm doing wrong and would appreciate a little help. My code follows:
#include <fstream>
using namespace std;
void loadModel(const char* filename);
int main()
{
// Creates and positions the four boxes on the screen. Temporary.
//rotation r = {0.0f, 0.0f, 0.0f};
const char* filename = "map.obj";
loadModel(filename);
return 0;
/*meshMgr.addObject(new Object());
position p = {0.f, 10.f, 10.f};
meshMgr.addObject(new Object(p, r));
p.y = 0.f;
p.z = 20.f;
meshMgr.addObject(new Object(p, r));
p.y = -10.f;
p.z = 10.f;
meshMgr.addObject(new Object(p, r));*/
}
void loadModel(const char* filename)
{
ifstream in(filename, ios::in); //Open the model file
if (in.is_open()) //if not opened, exit with -1
{
//Set up an array to act as a buffer for text read from the input file
char buf[256];
//Read input file text to end of file and push onto lines list
while (!in.eof())
{
in.getline(buf, 256);
//lines.push_back(new std::string(buf));
}
in.close();
}
}
EDIT: Before anyone asks, yes the file is being referenced as a local file (do I need to use absolute paths or something?) and exists in the same directory as the source code
As a response to my own question, it appears that my code didn't like passing the variable that stored the filename as a cost char * when the data in the variable was stored in a string-like format.
To counteract this, I simply changed the code from:
int main ()
{
...
const char* filename = "map.obj";
loadModel(filename);
...
return 0;
}
void loadModel(const char* filename)
{
...
}
to the following:
int main ()
{
...
string filename = "map.obj";
loadModel(filename);
...
return 0;
}
void loadModel(string filename)
{
...
}
where "..." indicates more code as shown in the question.
This answers the error in the question, but begins with a string instead and uses a char instead of const char*. It's an alternative solution.
const char* not passing full filename
std::string filename = "map.obj";
char *cstr = new char[filename.length() + 1];
Related
So I have a function returning a std::string as follows:
string ReadShaderSource(const char* filename, GLint& shaderSize) // Load the shader source code.
{
ifstream::pos_type size;
string text;
ifstream file(filename, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
shaderSize = (GLuint)size;
text.resize(size);
file.seekg(0, ios::beg);
file.read(&text[0], text.size());
file.close();
return text;
}
else
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error!",
"Could not load the shader source code from the file.", NULL);
Lunar::Exit();
}
return "";
}
But When I call the function like this:
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
The value of testStr is full of this:
0x036fdcd8
"îþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþ...
Which makes no sense. The function returns the right value, so when I return text in the function it contains the source code of the shader, but when I do
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
testStr is full of rubbish.
Any ideas?
Thank you!
You need to use
string str = ReadShaderSource("test.glsl", size);
const char* testStr = str.c_str();
instead of
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
When you use the second form, you are storing a pointer in testStr that is not valid any more since the returned value of the function is a temporary string.
As was pointed out by #IInspectable, you could also use a const& to extend the lifetime of the temporary object.
string const& str = ReadShaderSource("test.glsl", size);
const char* testStr = str.c_str();
The following program is well behaved:
#include <iostream>
#include <string>
std::string foo()
{
return "This is a test.";
}
void bar(std::string const& str)
{
std::cout << str.c_str() << std::endl;
}
int main()
{
std::string const& str = foo();
bar(str);
std::cout << str.c_str() << std::endl;
}
Re
“when I do const char* testStr = ReadShaderSource("test.glsl", size).c_str(); testStr is full of rubbish.”
you're initializing the pointer to point to a buffer in a temporary string, that has ceased to exist already when the initialization finishes.
Instead use a string for the result variable.
Note that the conclusion that the function returns garbage is unwarranted, it does not follow from that observation of garbage, but might still be true.
You should test anew, with proper result variable type, to check that.
I am having a string that has some binary data in it. The string in xml format, so before i am gonna proccess it i need to convert the binary data in the base64 format.
I am using a function called findXMLTag that will find the position of the start and the end of the data given the xml tag that contains it.
Now i am able to convert that data into base64 but i am having problems replacing the old binary data with my new base64 data.
The thing is that i can't use any type of string because when it locates a null char it will consider it as the terminating point of the string but in fact since i have binary data stored in the string then that null char can be part of my binary data.
So i guess i am looking for some kind of binary replacement and i can't figure out how to make it work.
Thanks in advance for any kind of help.
This is the code that i am using to locate the start and the end of the data in an xml string.
std::vector<TForm1::Pair> TForm1::findXMLTag(char *XMLString, char* XMLTag, int XMLSize)
{
void *found = XMLString;
int XMLTagLen = strlen(XMLTag);
std::vector<TForm1::Pair> result;
TForm1::Pair pair;
AnsiString XMLTagEnd = "</";
XMLTagEnd += &XMLTag[1];
while(found = memmem(XMLString, XMLSize - ((char*)found - XMLString), XMLTag, XMLTagLen))
{
if(found == NULL)
return result;
found = (char*)found + XMLTagLen;
pair.start = int((char*)found - XMLString);
found = memmem(found, XMLSize - ((char*)found - XMLString), XMLTagEnd.c_str(), XMLTagEnd.Length());
pair.end = int((char*)found - XMLString);
found = (char*)found + XMLTagEnd.Length();
result.push_back(pair);
}
return result;
}
Translating your C-style answer to C++, we are left with a one-liner which is safe (for valid indices), efficient and readable:
std::string binary_replace(
std::string const& bin, unsigned bin_start, unsigned bin_end,
std::string const& replace_with
) {
assert(bin_start < bin.size() and bin_end < bin.size());
return bin.substr(0, bin_start) + replace_with + bin.substr(bin_end);
}
This can be made even simpler by using the replace function for this purpose:
std::string binary_replace(
std::string bin, unsigned bin_start, unsigned bin_end,
std::string const& replace_with
) {
assert(bin_start < bin.size() and bin_end < bin.size());
return bin.replace(bin_start, bin_end - bin_start, replace_with);
}
(Take heed that bin is passed by value here since replace modifies it.)
Essentially there’s a direct substitute for most C-string functions in C++ – in this case, have a look at the documentation of std::basic_string::substr.
Here's a little self-contained example that might help you. Note that there is no error or bounds checking, it's just meant to demonstrate a concept.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// stub for real base64_encode
std::string base64_encode(const string &data)
{
return "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
}
// search without terminating on NULL
size_t binary_find(const string &str, size_t offset, const string &s)
{
for (size_t i=offset; i<str.length(); i++)
if (str.compare(i, string::npos, s) == 0)
return i;
return string::npos;
}
int main()
{
string tag = "<data>";
string endtag = "</data>";
string xml("<data>\0\0\0\0\0\0\0\0\0\0</data>", 23);
size_t start = xml.find(tag) + tag.length();
size_t end = binary_find(xml, start, endtag);
string binary = xml.substr(start, end-start);
string base64 = base64_encode(binary);
xml.replace(start, end-start, base64);
cout << xml << endl;
}
char *binary_replace(char *binString, int _strlen, int binDataStart, int binDataEnd, char* replaceWith)
{
char *buffer = (char*)malloc( (strlen(replaceWith)+(_strlen - (binDataEnd-binDataStart)))*sizeof(char) );
memcpy(buffer, binString, binDataStart);
strcat(buffer, replaceWith);
memmove(buffer+binDataStart+strlen(replaceWith), binString+binDataEnd, _strlen - binDataEnd);
return buffer;
}
I know that this is not c++ but it solved my problem.
I have a .txt parameter file like this:
#Stage
filename = "a.txt";
...
#Stage
filename = "b.txt";
...
Basically I want to read one stage each time I access the parameter file.
I planed to use getline in C++ with delimiter "#Stage" to do this. Or there is a better way to solve this? Any sample codes will be helpful.
*struct content{
DATA data;
content* next;
};
struct List{
content * head;
};
static List * list;
char buf[100];
FILE * f = fopen(filename);
while(NULL != fgets(buf,f))
{
char str[100] ={0};
sccanf(buf,"%s",str);
if(strcmp("#Stage",str) == 0)
{
// read content and add to list
cnntent * p = new content();
list->add();
}
else
{
//update content in last node
list->last().data =
}
}*
Maybe I should express more clear. Anyway, I manage like this:
ifstream file1;
file1.open(parfile, ios::binary);
if (!file1) {
cout<<"Error opening file"<<parfile<<"for read"<<endl;
exit(1);
}
std::istreambuf_iterator<char> eos;
std::string s(std::istreambuf_iterator<char>(file1), eos);
unsigned int block_begin = 0;
unsigned int block_end = string::npos;
for (unsigned int i=0; i<stage; i++) {
if(s.find("#STAGE", block_begin)!=string::npos) {
block_begin = s.find("#STAGE", block_begin);
}
}
if(s.find("#STAGE", block_begin)!=string::npos) {
block_end = s.find("#STAGE", block_begin);
}
string block = s.substr(block_begin, block_end);
stringstream ss(block);
....
I'd read line by line, ignoring the lines, starting with # (or the lines, with content #Stage, depending on the format/goal) (as there's no getline version, taking std::string as delimiter).
Im trying to implement a 'search and replace all'. I have 2 pointers to monitor characters nclude
#include
#include
using namespace std;
const int BUFSIZE = 256;
const char * const SEARCH = "the";
const char * const REPLACE = "Who is John";
int main()
{
char buf[BUFSIZE];
Error(SOURCE_FILE);
//open file for append and update
fstream destination(DESTINATION_FILE,
ios_base::in | ios_base::out | ios_base::app);
//check if destination file is open
if (!destination.is_open())
Error(SOURCE_FILE);
bufPtr += length; //move bufPtr to point past the SEARCH
destination << bufPtr; //write rest of buf to destination
//destination.seekg(0);
//write lines from source to destination
//if(!(destination << buf << '\n'))
//Error(SOURCE_FILE);
}
source.close();
destination.close();
return 0;
}
You're not checking for the case where strstr() doesn't find the search string. It returns NULL in that case, and your while loop loop won't do the right thing in that case.
I have a question regarding passing a variable that is a char array from one function into the next.
Here are the samples of code involved:
int main( int argc, char** argv )
{
int value = 0;
int nCounter = 0;
FILE* fIn = NULL;
char * sLine = new char[MAX_FILENAME_SIZE];
char * sFileName = new char [MAX_FILENAME_SIZE];
char * s = new char [MAX_FILENAME_SIZE];
if ((fIn = fopen(ImgListFileName,"rt"))==NULL)
{
printf("Failed to open file: %s\n",ImgListFileName);
return nCounter;
}
while(!feof(fIn)){
//set the variables to 0
memset(sLine,0,MAX_FILENAME_SIZE*sizeof(char));
memset(sFileName,0,MAX_FILENAME_SIZE*sizeof(char));
memset(s,0,MAX_FILENAME_SIZE*sizeof(char));
//read one line (one image filename)
//sLine will contain one line from the text file
fgets(sLine,MAX_FILENAME_SIZE,fIn);
//copy the filename into variable s
strncpy(s, sLine, strlen(sLine)-1);
//put a \0 character at the end of the filename
strcat(sLine,"\0");
//create the filename
strcat(sFileName,s);
nCounter++;
fclose(fIn);
delete sLine;
delete sFileName;
delete s;
const int size = 60;
char path[size] = "path";
strcat(path,sFileName);
printf (path);
IplImage *img = cvLoadImage(path);
detect_and_draw(img);
cvWaitKey();
cvReleaseImage(&img);
cvDestroyWindow("result");
void detect_and_draw( IplImage* img )
{
More code that isn't involved....
cvSaveImage(sFileName, img);
Now, I have tried the following:
void getFilename(char * sFileName)
{
printf("The filename is %s\n", sFileName);
return;
}
And then call with
char * S ="string"
getFilename(S);
cvSaveImage(S,img);
But "string" is placed into "The filename is: string".
What can I do so that I can use sFileName, the char array, in cvSaveImage(sFileName, img)?
Thanks in advance, and if you need any further clarifications, please ask!
Ignoring the undefined behavior, unnecessary dynamic allocation, etc., what you seem to be trying to accomplish boils down to something on this general order:
std::string path;
while (std::getline(fIn, path)) {
std::cout << "path: " << path;
IplImage *img = cvLoadImage(path.c_str());
detect_and_draw(img, path);
cvWaitKey();
cvReleaseImage(&img);
cvDestroyWindow("result");
}
void detect_and_draw(IpImage *img, std::string const &path) {
// ...
cvSaveImage(path.c_str(), img);
}
I think I'd do things a bit differently from that though -- probably starting with an Image class, something like:
class Image {
IpImage *img;
std::string path;
public:
Image(std::string const &name) :
img(cvLoadImage(name.c_str()), path(name)
{ }
~Image() { cvReleaseImage(&img); }
void detect_and_draw() {
// ...
cvSaveImage(path);
}
};
Using that, your code would look more like this:
while (std::getline(fIn, path)) {
Image img(path);
img.detect_and_draw();
cvWaitKey();
cvDestroyWindow("result");
}
It's not entirely clear, but cvDestroyWindow sounds a lot like something that really belongs in a destructor as well, but I'm not certain enough about how these pieces fit together to be sure what destructor -- perhaps Image's, more likely something else.
I'd note that detect_and_draw virtually screams "this code ignores the single responsibility principle". It lists two responsibilities in the name, and appears to have at least a third (saving the file) as well.
If I'm understanding correctly, what you have is a scoping problem. You essentially have:
int main(/* */)
{ char sFileName[MAX_FILENAME_SIZE];
/* code to initialize sFileName to contain a value */
detect_and_draw(img);
}
void detect_and_draw(IplImage *img)
{ cvSaveImage(sFileName, img);
}
The problem is that sFileName is local to main() and not accessible in detect_and_draw(). You can either modify detect_and_draw() to take a second argument:
int main()
{ /* stuff */
detect_and_draw(img, sFileName);
}
void detect_and_draw(IplImage *img, const char* fn)
{ cvSaveImage(fn, img);
}
Or make sFileName a global variable declared/defined outside the scope of main() - although that's quite often considered to be an inferior solution.