hi i need to do something like filesystem and i need to write and read from file (the write function work) i have a function signature
void read(int addr, int size, char *ans);
void BlockDeviceSimulator::read(int addr, int size, char *ans) {
memcpy(ans, filemap + addr, size);
}
and this is my function to read from file and print it
std::string MyFs::get_content(std::string path_str) {
std::string ans;
//open file
BlockDeviceSimulator *newFile = new BlockDeviceSimulator(path_str);
newFile->read(1,newFile->DEVICE_SIZE,(char*)&ans);
std::cout << ans << std::endl;
delete newFile;
return "";
}
can you help me what is wrong here and why it dosen't print?
You are trying to cast address of std::string object to pointer to char. At first you need to allocate enough size to read into std::string - ans.resize(newFile->DEVICE_SIZE);. Secondly you need to get char * from std::string - &ans[0].
Related
I am wondering how can you write data of type char*,int,double using char* and also reading a whole file line by line using again char* ? I know it can be done with std:string really beautiful but I am interested with char*. I have created a Write() method which writes char* successfully
but I don't know how to adjust it for ints and doubles, also I have started creating Read() method to read each line and save it to char* then print it to the console but I don't know how to implement it.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
void Write(char* fileName, char* pData)
{
ofstream file (fileName, ios::out | ios::app );
if (file.is_open())
{
size_t len = strlen(pData);
file.write(pData, len);
}
}
void Read(char* fileName, char* pData)
{
ifstream file(fileName, ios::in );
if(file.is_open())
{
file.read((char*)&pData, sizeof(pData));
file.close();
}
}
int main()
{
char* fileName = "E:\\cpp\\CarsIO\\data.txt";
char* data = "hello\n";
Write(fileName , data);
char* read = "";
Read(fileName , read);
return 0;
}
I have created a Write() method which writes char* successfully but I don't know how to adjust it for ints and doubles [...]
First of all, the function std::ofstream::write is intended for unformatted (binary) I/O. Since you are outputting text, it would be easier to use the formatted I/O functions, for example operator <<, like this:
void Write( char* fileName, char* pData )
{
ofstream file( fileName, ios::out | ios::app );
if ( file.is_open() )
{
file << pData;
}
if ( !file )
{
//TODO: handle error
}
}
In order for the function Write to print data of type int, you can simply create an appropriate overloaded function Write, like this:
void Write( char* fileName, int data )
{
ofstream file( fileName, ios::out | ios::app );
if ( file.is_open() )
{
file << data;
}
if ( !file )
{
//TODO: handle error
}
}
In order to make it also print the data type double, you can create an additional overloaded function for this data type. You can simply copy the function above and change int data to double data.
However, now you have 3 overloaded functions, one for the data type char *, one for int and one for double. That is a lot of unnecessary code duplication. It would be less messy to make a single template function, which can handle all three data types:
template <typename T>
void Write( char* fileName, T data )
{
ofstream file( fileName, ios::out | ios::app );
if ( file.is_open() )
{
file << data;
}
if ( !file )
{
//TODO: handle error
}
}
[...] also I have started creating Read() method to read each line and save it to char* then print it to the console but I don't know how to implement it.
The function std::ifstream::read is intended for unformatted (binary) input, not for formatted text input. Since you insist on using char* instead of std::string, I recommend that you use the function std::istream::getline in order to read exactly one line of text input, like this:
void Read( char* fileName, char* pData, std::streamsize count )
{
ifstream file(fileName, ios::in );
if(file.is_open())
{
file.getline( pData, count );
}
if ( !file )
{
//TODO: handle error
}
}
In your code, you were simply using sizeof(pData) to pass the size of the memory buffer. This will not work, because this will give you the size of the pointer pData (which is probably 4 or 8 bytes), instead of the size of the memory buffer. That is why the function Read must take an additional parameter which specifies the size of the memory buffer.
In your code, you are calling the function Read like this:
char* read = "";
Read(fileName , read);
This code is wrong, for two reasons:
You must ensure that the memory buffer is large enough to store the read data. This would be handled automatically when using std::string, but you must handle this yourself when using char*.
The line char* read = ""; makes the pointer read point to an (empty) string literal. String literals are read only. That is why C++ requires that pointers to string literals are declared as const char * instead of char *. You cannot pass a pointer to a read-only string literal to the function Read, because that function will attempt to write to that string literal, which causes undefined behavior.
In order to call the function Read and print the result, you can use the following code:
char buffer[100];
Read( fileName, buffer, sizeof buffer );
std::cout << buffer << "\n";
I'm trying to read the data from a file using pointers but it gives error at the getline part that goes by "no instance of overloaded function". Couldn't figure out how to go about this..
Code is below:
#include<iostream>
#include<fstream>
using namespace std;
void read(const char * const, char const *);
int main()
{
char filename[20] = { "sentence.txt" }, data[50] = { '\0' };
read(filename, data);
return 0;
}
void read(const char * const ptr, char const * ptr2)
{
ifstream file;
file.open(ptr);
if (!file.is_open())
{
cout << "File not found " << endl;
exit(0);
}
else
{
while (!file.eof())
{
file.getline(ptr2, 49, ' ');
cout << ptr2 << endl;
}
file.close();
}
}
Function read is already defined in the C++ libraries:
https://en.cppreference.com/mwiki/index.php?title=Special%3ASearch&search=read
You should use a different name for your function.
Also as written in the comments, const char * and char const * are the same. They are pointers to constant char, which doesn't let you modify the contents of the char array. What you probably wanted is constant pointer to char:
char * const
Ok it was just a simple error that I can't believe I didn't see. The asterisk should be before const so correct indentation would be char * const ptr2 and not char const * ptr2
Call me dumb duh.
This problem is blowing my mind right now.
int main()
{
char inputChar;
char *buffer = nullptr;
int size = 0;
read(buffer); //this is the line causing problems...
int numberOfFrames = (size / MAX_FRAME_SIZE) + 1;
frame array[numberOfFrames];
for(int i = 0; i < size; i++)
{
buffer[i] = appendParityBit(buffer[i]);
}
constructFrame(buffer, size, array);
transmitFrames(array, numberOfFrames);
}
int read(char *buffer)
{
int fileSize;
ifstream myfile ("inputFile");
if (myfile.is_open())
{
fileSize = getFileLength(myfile);
buffer = new char[fileSize];
myfile.read(buffer, fileSize);
myfile.close();
}
return fileSize;
}
int getFileLength(ifstream &myfile)
{
myfile.seekg(0, ios::end);
int size = (int) myfile.tellg() - 1;
myfile.seekg(0, ios::beg);
return size;
}
now if i do a
cout << read(buffer);
on the line that is causing problems, i receive an integer back...great, perfect. but if i try to do
size = read(buffer);
my program crashes...i'm at a loss.
You are passing a variable by value (doesn't matter if it is a pointer or not). On the receiving end, the function makes a local copy of what is passed, works with the local copy, and poof, the local copy goes away when the function returns.
This occurs regardless of whether what you're passing is a pointer or not. For example, take this simple code:
void foo(int x)
{
x = 10;
}
int main()
{
int val = 0;
foo(val);
cout << val; // how come val is still 0 and not 10?
}
Note that val is still 0, even though the function is changing the parameter that is being passed. To fix this problem, you pass a reference to the value that will be changed:
void foo(int& x)
{
x = 10;
}
int main()
{
int val = 0;
foo(val);
cout << val; // now val is 10
}
With pointers, the rules don't change. You need to pass a reference to the pointer to have the change reflect back to the caller:
int read(char*& buffer)
{
int fileSize;
ifstream myfile ("inputFile");
if (myfile.is_open())
{
fileSize = getFileLength(myfile);
buffer = new char[fileSize];
myfile.read(buffer, fileSize);
myfile.close();
}
return fileSize;
}
Now the buffer in that function is not a local copy, but a reference to the variable you passed.
The other method (which is more "C" style) is to pass a pointer to the thing you want to change. You want to change the pointer value, so you pass a pointer to the pointer:
int read(char** buffer)
{
int fileSize;
ifstream myfile ("inputFile");
if (myfile.is_open())
{
fileSize = getFileLength(myfile);
*buffer = new char[fileSize];
myfile.read(buffer, fileSize);
myfile.close();
}
return fileSize;
}
// the caller
char *buffer;
//...
read(&buffer);
Of course, we have to change the syntax since it is a pointer that is being passed, thus we need to dereference it.
You are passing your buffer (char*) by value. Even when you allocate the buffer in your read() routine, this modifies local copy of the pointer. When you return from read(), you still have the old unititialized value of the pointer, which is not usable. To alleviate the issue, you can pass your buffer by reference.
I think the other answers have identified your coding error.
I note that you have tagged this as C++ ... and I suggest that perhaps your error would not have occurred if you used C++ features.
I have found the following (in SO and else where). It is similar, but relies on the strongly tested std::string memory management, and the file size requires no extra code on your part.
size_t read(std::string& buffer)
{
std::ifstream sIn("inputFile");
if (!sIn.is_open())
{
std::stringstream ssErr;
ssErr << "Can not open file '" << "inputFile" << "'" << std::endl;
throw ssErr.str();
}
std::stringstream ss(buffer);
ss << sIn.rdbuf(); // one line transfer of file contents
sIn.close(); // close sIn when we are done with it
if(sIn.bad())
throw "Err: sIn.rdbuf()";
return (ss.str().size());
}
Somewhere you might want a std::char array ... note that the c-style result (null terminated string) is available in buffer.c_str().
You can load any size text file (that fits in your memory) using this technique.
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 want to add a new (fstream) function in a program that already uses char arrays to process strings.
The problem is that the below code yields strings, and the only way i can think of getting this to work would be to have an intermediary function that would copy the strings, char by char, into a new char array, pass these on to the functions in the program, get back the results and then copy the results char by char back into the string.
Surely (hopefully) there must be a better way?
Thanks!
void translateStream(ifstream &input, ostream& cout) {
string inputStr;
string translated;
getline(input, inputStr, ' ');
while (!input.eof()) {
translateWord(inputStr, translated);
cout << translated;
getline(input, inputStr, ' ');
}
cout << inputStr;
the translateWord func:
void translateWord(char orig[], char pig[]) {
bool dropCap = false;
int len = strlen(orig)-1;
int firstVowel = findFirstVowel(orig);
char tempStr[len];
strcpy(pig, orig);
if (isdigit(orig[0])) return;
//remember if dropped cap
if (isupper(orig[0])) dropCap = true;
if (firstVowel == -1) {
strcat(pig, "ay");
// return;
}
if (isVowel(orig[0], 0, len)) {
strcat(pig, "way");
// return;
} else {
splitString(pig,tempStr,firstVowel);
strcat(tempStr, pig);
strcat(tempStr, "ay");
strcpy(pig,tempStr);
}
if (dropCap) {
pig[0] = toupper(pig[0]);
}
}
You can pass a string as the first parameter to translateWord by making the first parameter a const char *. Then you call the function with inputStr.c_str() as the first parameter. Do deal with the second (output) parameter though, you need to either completely re-write translateWord to use std::string (the best solution, IMHO), or pass a suitably sized array of char as the second parameter.
Also, what you have posted is not actually C++ - for example:
char tempStr[len];
is not supported by C++ - it is an extension of g++, taken from C99.
You can use the member function ifstream::getline. It takes a char* buffer as the first parameter, and a size argument as the second.