So I've this issue I can't get fixed :-(
In my .h I've this:
protected:
char* _textPath_1;
FileReader* _reader_3;
in .cpp I've:
_reader_3 = new FileReader();
_textPath_1 = "foo";
_reader_3->openFile(_textPath_1);
And FileReader has this:
private:
char* fileName;
public:
signed int openFile(char* name);
but If I write this (just to test):
signed int FileReader::openFile(char* name) {
std::cout << name << std::endl;
fileName = name;
stream.open(fileName, std::ios::in);
if (!stream.is_open()) {
FileReader::printErrorOpeningFile(fileName);
stream.close();
return -1;
}
return 0;
}
fileName is a char * and I need that it gets the same value (foo) of name. I get an error, and I'm not even able to print name, it just print a blank line.. why?
EDIT: it's not working even using strcpy.. Actually inside the function I can't print the value of name, it's like it has been "deininitialized"
You need to allocate space for your text string _textPath_1.
Try this instead.
char myTextString[] = "foo";
_textPath_1 = myTextString;
This creates a local character array (a character string), which is initialized to "foo\0". It then copies that character string's address to your char pointer _textPath_1. As a LOCAL storage, it will only be valid in the local code block and will not be usable once your code has dropped out of its scope. If you need that string past the local code block, you will need to allocate it from heap memory (using new for instance) and remember to deallocate it after you are done with it.
You cannot use strcpy with your unallocated pointer because strcpy expects the destination char* to be pointing at a character array acting as your destination string buffer. As you haven't allocated any char space at all, it cannot copy "foo" into your _textPath_1, and that's why you get a runtime error when you try to strcpy it.
These and other fun with char* is why std::string was invented. No worries about allocating and deallocating space, having to use strcpy to copy its value, etc etc etc. Consider using std::string _textPath_1 in place of your char* _textPath_1.
You have to allocate _reader_3 before calling the function.
FileReader* _reader_3 = new FileReader;
I assume fileName is your member variable. Accessing pointers without initialization will result in unpredictable results
If you're really defining global variables in your header file:
char* _textPath_1;
FileReader* _reader_3;
Then you shouldn't be doing that. Global variables should be declared in header files, but defined in an implementation file.
This code works fine:
#include <iostream>
#include <fstream>
struct FileReader {
char* fileName;
std::fstream stream;
signed int FileReader::openFile(char* name) {
std::cout << name << std::endl;
fileName = name;
stream.open(fileName, std::ios::in);
if (!stream.is_open()) {
FileReader::printErrorOpeningFile(fileName);
stream.close();
return -1;
}
return 0;
}
void printErrorOpeningFile(char *) {}
};
int main() {
char* _textPath_1;
FileReader* _reader_3;
_reader_3 = new FileReader();
_textPath_1 = "foo";
_reader_3->openFile(_textPath_1);
delete _reader_3;
}
Related
Based on the idea of this entry Is it a good idea to return “ const char * ” from a function?
I thought to extend this with another question I have.
Consider the following code:
#include <string>
#include <cstdio>
const char * GetSomeString()
{
std::string somestlstring;
somestlstring = "Hello World!";
return somestlstring.c_str();
}
int main()
{
const char * tmp = GetSomeString();
printf("%s\n", tmp);
return 0;
}
If I build it with
g++ source.cpp -o executable
and execute that, I get strange symbols displayed. This is because somestlstring is destroyed through the callstack and the pointer you keep after returning became invalid.
My question is: how should I design a method or function that does not have such behaviour without actually declaring additional global variables or potential member functions?
You should drop the whole C mindset and start writing C++:
#include <string>
#include <iostream>
std::string GetSomeString()
{
std::string somestlstring;
somestlstring = "Hello World!";
return somestlstring;
}
int main()
{
std::string tmp = GetSomeString();
std::cout << tmp << std::endl;
return 0;
}
One obvious solution is to make the return type std::string.
how should I design a method or function that does not have such beahviour without actually declaring additional global variables or potential member functions?
Not at all. If you return a const char *, your function is kind of telling the caller "here you have a C string to use, but it stays mine" *), and this implies the caller doesn't have to bother releasing the resources, for example. So you can do this from an instance method (returning a pointer to a field) or you can have a function return a pointer to some static buffer (global variable).
If you want to return a dynamically allocated C string from a function, you must return char * instead and the caller has to free() it when done using it.
That all said, in C++ this doesn't make much sense, except when somehow interfacing with C code. If you want to write C++ code, go with nvoigt's answer.
*) this is thinking in terms of ownership, which is very helpful dealing with manually managed resources. The owner of something is responsible for appropriate cleanup. You can only return a const raw pointer if you don't transfer ownership of the object to the caller.
You are currently referencing the memory of a local std::string object which is destroyed when the object goes out of scope (when returning from the function)
if you really want to return a const char *:
you have to make your std::string static (but only 1 value is shared by your application)
or you have to duplicate the string memory (but you need to free it or you get memory leaks, like happened a lot with the old str() method of the old strstream object, which was later converted to std::string)
But as others said, better stick to C++ std::string (or const reference) as a return value and take c_str() of that returned string when needed for C-style interfaces.
std::string tmp = GetSomeString();
FILE *f = fopen(tmp.c_str(),"r");
The local string variable in the GetSomeString() function will get out of scope after you returned from the funtion. You will be printing random stuff that is in the memory position where the string was before. Try this:
#include <string>
#include <cstdio>
void GetSomeString(std::string& str)
{
str = "Hello World!";
}
int main()
{
std::string str;
GetSomeString(str);
std::cout << str << std::endl;
return 0;
}
Following is my code to create char* _strbuf. It will be created but zero space will be assigned to it in the memory
StringBuffer::StringBuffer() {
char* _strbuf = (char*)malloc(sizeof(char)*_length);
}
private:
char* _strbuf; //buffer to store the original string
int _length=0;
Now, here is an append function which will simply append (concatenate) a character to this char* by reallocating it a new space
void StringBuffer:: append(char c) {
_length++;
_strbuf = (char*)realloc(_strbuf, sizeof(char) * _length);
cout << "\n";
cout << _strbuf;
_strbuf[_length-1] = c; //exception thrown here
cout << _strbuf;
}
There is some kind of a problem with assignment.
PS: Im trying to implement StringBuffer class. No std::strings allowed
When you write:
StringBuffer::StringBuffer() {
char* _strbuf = (char*)malloc(sizeof(char)*_length);
}
That doesn't malloc the member _strbuf. That mallocs a local variable named _strbuf, which happens to have the same name as your member _strbuf. But the member remains uninitialized.
So when you then do:
_strbuf = (char*)realloc(_strbuf, sizeof(char) * _length);
This fails, since _strbuf wasn't previously allocated by malloc().
To fix that, just change what you're doing in your constructor from a declaration to an assignment:
StringBuffer::StringBuffer() {
_strbuf = (char*)malloc(sizeof(char)*_length);
}
which can be moved into a mem-initializer-list to avoid any confusion:
StringBuffer::StringBuffer()
: _strbuf((char*)malloc(sizeof(char)*_length))
{ }
Once you fix that, strings in C/C++ have to be null-terminated. You're not accounting for that anywhere. You need to ensure that the last char in your buffer is always \0.
#include "stdafx.h"
#include "Cfriend.h"
int _tmain(int argc, _TCHAR* argv[])
{
std::string * TempName = new std::string;
std::cout << "Name your friend:\n";
std::getline (std::cin, TempName);
Cfriend * MyFriend = new Cfriend();
return 0;
}
Hi, I'm new around here. I'm trying to create a simple procedure where the player can assign a name to Cfriend, but the problem is that it won't let me assign cin to TempName.
I want to be able to delete TempName from memory as soon as I'm done with it.
The problem is you're trying to use a std::string* where a std::string is expected.
The best solution is to not use new to create every object, C++ is not Java or C#.
#include "Cfriend.h"
int main(int argc, char* argv[])
{
std::string tempName;
std::cout << "Name your friend:\n";
std::getline (std::cin, tempName);
Cfriend myFriend;
return 0;
}
I want to be able to delete TempName from memory as soon as I'm done with it.
Why? Is the name going to be thousands of bytes long?
If it's essential that it be destroyed then let the std::string destructor do that:
#include "Cfriend.h"
int main(int argc, char* argv[])
{
Cfriend myFriend;
{
std::string tempName;
std::cout << "Name your friend:\n";
std::getline (std::cin, tempName);
myFriend.setName(tempName);
}
return 0;
}
tempName goes out of scope at the closing brace and its memory is deallocated.
If you really, really can't re-arrange the code like this, you can still force the string to deallocate the memory it owns:
std::string tempName;
// ...
tempName.clear();
tempName.shrink_to_fit();
When every single commenter is telling you to stop using new explicitly that should be a pretty big hint to re-evaluate your assumptions about writing good C++.
As for the destruction of TempString, it will be destructed once it leaves the scope.
that means you can write e.g.
int main()
{
// Some code...
{
std::string temp;
std::getline(std::cin, temp);
// Do something with the string `temp`
}
// No `temp` string object, it doesn't exist, and has been destructed
// More code...
}
The big question here, though, is why you would want this? Unless you expect several megabytes of input text in a single line, there is really no use of scoping for temporary variables. And if you want to redeclare the temp (or TempString) variable, why would you do that? Just reuse the existing variable.
TempName there is a pointer to a string. Try adding a * before it for dereferencing when using it:
getline(std::cin, *TempName);
Or you can also just use a string in advance and not a pointer to it:
int main()
{
std::string myString;
std::getline(std::cin, myString);
// Do something with the string you just read
}
What did I do wrong here?
call
printf(filename(exename));
my function should return filename
const char* filename(const string& str)
{
const char* path;
size_t found;
found=str.find_last_of("/\\");
path = (str.substr(found+1)).c_str();
cout << str.substr(found+1); // ------------> is name ok
printf("\n\n");
printf(path); // ------------> is name not ok random numbers
printf("\n\n");
return path; // ------------> is not ok random numbers
}
str.substr(found+1) returns a temporary std::string.
You call c_str() method on that temporary std::string, and assign the returned pointer to path.
When the temporary is destroyed (at the ;), your path is pointing to garbage.
Make yourself a favor and use C++ (not C mixed with C++), using robust string classes like std::string to store strings (instead of raw potentially-dangling char* pointers):
std::string FileName(const std::string& str)
{
size_t found = str.find_last_of("/\\");
std::string path = str.substr(found+1); // check that is OK
return path;
}
Note also that your use of path variable name is confusing, since the function seems to return the file name (not the path).
A simpler rewrite (without the path variable):
std::string ExtractFileName(const std::string& fullPath)
{
const size_t lastSlashIndex = fullPath.find_last_of("/\\");
return fullPath.substr(lastSlashIndex + 1);
}
printf("Filename = %s\n", ExtractFileName("c:\\some\\dir\\hello.exe").c_str());
...or just use cout (which plays well with std::string and doesn't require c_str() method call to get a raw C string pointer like in C printf() function):
std::cout << ExtractFileName("c:\\some\\dir\\hello.exe");
You are returning a pointer to memory that is held by a temporary (str.substr(found+1)).c_str(). When the temporary goes out of scope, the memory could be overwritten at any time.
str.substr(found+1) is an expression that returns a string. This object is a temporary value which will go away at the end of the execution of the expression that contains it. With .c_str(), you are getting a pointer to memory controlled by this object. After the object's lifetime, this pointer is no longer valid.
Try declaring path as a string, and having your function return a string instead of a pointer.
In general, you should avoid working with raw char * when you are also working with the std::string class. That means you should also avoid using printf; use the std::iostream classes instead.
I have a the following code:
#include <iostream>
using namespace std;
void func(char * aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] aString;
aString = tmpStr;
}
int main()
{
char * str= new char[100];
cin.getline(str,100);
cout<< str <<endl;
func(str);
cout<< str <<endl;
return 0;
}
Why the second cout does not print the second input string? How can I change this code to work it?
As GregS has said, the simplistic answer is to declare your function using a reference:
void func(char *&aString)
However it is not really the best solution. In C++ you generally avoid simple arrays and use containers.
#include <iostream>
#include <string>
void func(std::string &s)
{
std::getline(std::cin, s);
}
int main()
{
std::string str;
func(str);
std::cout << str << std::endl;
return 0;
}
Because the second cout will print what is pointed by str. And str, the pointer, in your main function will have the same value before and after the call to func.
Indeed, in the func function, you are changing the value of the aString variable. But this is another variable than str in main.
If you want the value of str to be changed, you have to pass it to func by reference or by pointer. (Note that what you write, is to pass the characters by pointer. I mean you have to pass the pointer by pointer: void func(char **str_ptr), or by reference void func(char *&str_ref))
If you're really doing C++, you should use std::string instead of the old C strings.
An example of passing the pointer by pointer:
func(char ** aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] *aString;
*aString = tmpStr;
}
Plus you should call it like this: func(&str);
When func() is called from main() the value of str pointer is passed to the function (this is done by copying it's value to the stack)
The value that was stored on stack when calling func() becomes a local variable aString within func(). You can modify this value but as soon as func() returns all of it's local variables will be discarded. Value of aString won't be copied back to str.
For your code to work you have to either:
Use the buffer pointed to by aString to read data: cin.getline(aString ,100);
or
Pass pointer to pointer: void func(char **aString)
Change func to
void func(char * aString)
{
cin.getline(aString,100);
}
and it works, at least it did for me.
The pointer is passed by value. Yes, you can change the content of what that pointer points to, but the old address itself is preserved when you exit the function. Hence, "aString=tmpStr"; becomes useless and "char * tmpStr= new char[100];" creates a memory leak. You need to pass the pointer by reference:
void func(char*& aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] aString;
aString = tmpStr;
}
If your aim is to actually read a line from the keyboard, do this:
std::string foo;
std::getline(std::cin, foo);
Otherwise, when you pass a pointer to a function, the pointer is passed by value. This means you cannot change the pointer itself from within the function, but you can change the object it points to. In C++ you could do this as follows:
void bar(std::string & s) {
std::getline(std::cin, s);
}
// in calling code
std::string foo;
bar(foo);
This passes a reference to the string to the function. The function can now change the contents of the string.
If you want to write a function that allocates some memory to store a result in, do it like this:
boost::shared_array<char> foo() {
boost::shared_array<char> result(new char[100]);
std::cin.getline(result.get(), 100);
return result;
}
assignment to the parameter aString within the function has no effect on str in main()
you might try
return aString
and in main
str = funct(str);
But in fact there's probably no reason to pass str into the function.
The line aString = tmpStr just changes the value of astring (i.e. an adress/pointer) to another value (i.e. another adress/pointer), but not the content of the momory pointed to by aString.
You could try to change the signature to:
void func(char ** aString)
And changing the last two lines of func to:
delete [] *aString;
*aString = tmpStr;
So the last line causes the program to change the adress stored in the memory pointed to by aString to the adress newly allocated (tmpStr). (I know, it's mind-boggling.)
And then call it via
func(&str);
You need to pass str as a reference.
#include <iostream>
void func(std::istream& is, std::string& aString)
{
std::getline(is, aString);
}
int main()
{
std::string str;
std::getline(std::cin, str);
if(std::cin)
std::cout<< str << '\n';
std::string str;
func(std::cin, str);
if(std::cin)
std::cout<< str << '\n';
return 0;
}
The pointer aString which you pass to func() indicates where (at which address) you can read and write the string str. When you then say aString = tempStr, you're replacing its original value (the address of the string pointed to by str) with a new value (the address of the string pointed to by tempStr). This will not cause str to point to the same place as tempStr.
Imagine I give you a piece of paper with my friend's home address it. Then you scratch it out and write the address of your brother (who lives in London) on it. If I then decide to visit my friend, I won't find myself traveling to London, even though you may have a piece of paper that says "Paul's friend: 123 London".
To get main to print out the string you entered in func(), you can either copy the input string to aString (you move your brother to my friend's house), or pass a pointer or reference to str (have me give you my address book, so you can change the entry for my friend to London). Either way, next time I visit "my friend's house", your brother will be there.