why is this filename parameter a char pointer instead of string? - c++

There's a function provided by my uni that is supposed to read in a file. In the parameter, there's the fileName parameter. What I don't understand is why they're using a character pointer instead of a simple string?
Also, how would I call this function with a string filename then?
I'm running C++14 on Visual studio 2017 community edition.
double* read_text(char *fileName, int sizeR, int sizeC)
{
double* data = new double[sizeR*sizeC];
int i = 0;
ifstream myfile(fileName);
if (myfile.is_open())
{
while (myfile.good())
{
if (i > sizeR*sizeC - 1) break;
myfile >> *(data + i);
i++;
}
myfile.close();
}
else cout << "Unable to open file";
//cout << i;
return data;
}
Edit: I get it guys, it's stupid. I'll post a separate question then. Thanks for the fast response!

why is this filename parameter a char pointer instead of string?
Because the designer of the API chose to do so. Most people at Stack Overflow are not the author of that API, so we cannot answer this question accurately.
However, there is another similar question that we can answer: What are reasons to use character pointer as a string argument? Let me answer that question instead:
Not using std::string as an argument allows the user of the API to not create a std::string object. This may be useful when:
The API needs to be used in "freestanding" implementations that don't provide the standard library and thus have no std::string. This probably doesn't apply to your particular example since the implementation of the function uses the standard library, but I include this argument for completeness.
The API needs to be used on systems that provide no dynamic memory allocation, which std::string requires.
The dynamic memory allocation that creation of the string may require may be too slow in the context where the API is used (this won't apply to an API that is going to read from disk, but I include the argument here for completeness).
(const) char* makes it possible to use the API from C. This may be relevant because:
The API may have originally been written for C, and has been inherited to a code base that now uses C++, but the API has not been changed in order to maintain backwards compatibility.
Providing a C compatible API allows using the API from other languages that are able to interface with C. Many languages have support for C interfaces while very few languages have support for C++ interfaces.
Also, how would I call this function with a string filename then?
You can get a pointer to a null terminated string using the c_str member function. Unfortunately the API is badly designed and the argument is non-const, while the pointer returned by c_str is const. You can const_cast the constness of the argument away in order to call this function. This is "OK" because the function doesn't actually modify the pointed string.
If you can require C++17 standard and the source string is non-const, then the data member function will be simpler as it doesn't require const_cast. Prior to C++17 there was no non-const overload, so it would require the same const casting, and prior to C++11 the pointed string was not guaranteed to be null terminated.
To make it clear: Using a non-const string argument for this function is bad design - whether that argument is a character pointer to null terminated string, or a reference to std::string.
P.S.There are other, more serious problems:
The caller of the function cannot possibly know how many numbers were read from the file. There is no way of avoiding UB in case the file has less than sizeR*sizeC values.
Returning a bare pointer that owns dynamic memory resource is a very bad design.
The loop that reads from the file checks whether the read was successful after the value has already been added to the array and the value is never overwritten, so the last element written into the array is always has an unspecified value.

Related

Are the methods in the <cstring> applicable for string class too?

I've tried out using memcpy() method to strings but was getting a "no matching function call" although it works perfectly when I use an array of char[].
Can someone explain why?
www.cplusplus.com/reference/cstring/memcpy/
std::string is an object, not a contiguous array of bytes (which is what memcpy expects). std::string is not char*; std::string contains char* (somewhere really deep).
Although you can pull out the std::string inner byte array by using &str[0] (see note), I strongly encourage you not to. Almost anything you need to do already is implemented as a std::string method. Including appending, subtracting, transforming and anything that makes sense with a text object.
So yes, you can do something as stupid as:
std::string str (100,0);
memcpy(&str[0],"hello world", 11);
but you shouldn't.
Even if you do need memcpy behaviuor, try to use std::copy instead.
Note: this is often done with C functions that expects some buffer, while the developer wants to maintain a RAII style in his code. So he or she produces std::string object but passes it as C string. But if you do clean C++ code you don't need to.
Because there's no matching function call. You're trying to use C library functions with C++ types.

Getting address of string in stringstream object

Is it possible to get the pointer to the string stored in string stream object . Basically i want to copy the string from that location into another buffer ..
I found that i can get the length from below code
myStringStreamObj.seekg(0, ios::end);
lengthForStringInmyStringStreamObj = myStringStreamObj.tellg();
I know i can always domyStringStreamObj.str().c_str(). However my profiler tells me this code is taking time and i want to avoid it . hence i need some good alternative to get pointer to that string.
My profiler also tells me that another part of code where is do myStringStreamObj.str(std::string()) is slow too . Can some one guide me on this too .
Please , I cant avoid stringstream as its part of a big code which i cant change / dont have permission to change .
The answer is "no". The only documented API to obtain the formatted string contents is the str() method.
Of course, there's always a small possibility that whatever the compiler or platform you're using might have its own specific non-standard and/or non-documented methods for accessing the internals of a stringstream object; which might be faster. Because your question did not specify any particular compiler or implementation, I must conclude that you are looking for a portable, standards-compliant answer; so the answer in that case is a pretty much a "no".
I would actually be surprised if any particular compiler or platform, even some who might have a "reputation" for poisonings language standards <cough>, would offer any alternatives. I would expect that all implementations would prefer to keep the internal stringstream moving gears private, so that they can be tweaked and fiddled with, in future releases, without breaking binary ABI compatibility.
The only other possibility you might want to investigate is to obtain the contents of the stringstream using its iterators. This is, of course, an entirely different mechanism for pulling out what's in a stringstream; and is not as straightforward as just calling one method that hands you the string, on a silver platter; so it's likely to involve a fairly significant rewrite of your code that works with the returned string. But it is possible that iterating over what's in the stringstream might turn out to be faster since, presumably, there will not be any need for the implementation to allocate a new std::string instance just for str()'s benefit, and jamming everything inside it.
Whether or not iterating will be faster in your case depends on how your implementation's stringstream works, and how efficient the compiler is. The only way to find out is to go ahead and do it, then profile the results.
I can not provide a portable, standards compliant method.
Although you can't get the internal buffer you can provide your own.
According to the standard setting the internal buffer of a std::stringbuf object has implementation defined behaviour.
cplusplus.com: std::stringbuf::setbuf()
As it happens in my implementation of GCC 4.8.2 the behaviour is to use the external buffer you provide instead if its internal std::string.
So you can do this:
int main()
{
std::ostringstream oss;
char buf[1024]; // this is where the data ends up when you write to oss
oss.rdbuf()->pubsetbuf(buf, sizeof(buf));
oss << "Testing" << 1 << 2 << 3.2 << '\0';
std::cout << buf; // see the data
}
But I strongly advise that you only do stuff like this as a (very) temporary measure while you sort out something more efficient that is portable according to the standard.
Having said all that I looked at how my implementation implements std::stringstream::str() and it basically returns its internal std::string so you get direct access and with optimization turned on the function calls should be completely optimized away. So this should be the preferred method.

Passing character arrays in C++

While passing a character pointer used to reference a string by its address (i.e. directly via its name or &name[0]) the original string must get passed, since we are passing by address.
However, after executing the following code, I got two different values of address for the first element, which, surprisingly, are 2 bytes apart.
Also, modifying the contents of the string in the function, didn't change the content of the array passed, but this is because a new string will have generated a new address, right?
But about the address of the first element being different, how is that possible?
#include<conio.h>
#include<stdio.h>
#include<iostream.h>
void fn(char *arr)
{
cout<<endl<<&arr;
arr="hi";
}
void main()
{
clrscr();
char *arr="hey";
cout<<endl<<"main "<<&arr;//the address is different from that in fn
fn(arr);
cout<<endl<<arr;
}
You are passing a pointer by value, and then comparing the address of the pointer and the copy, which of course differ. If you want to check that they point to the same memory address you can do that:
std::cout << (void*)arr << std::endl;
modifying the contents of the string in the function, didnt change the content of the array passed
You are not modifying the contents of the string, but rather reassigning the copy of the pointer to point to a different string literal. Also note that modifying the pointed memory (the literal) would be undefined behavior.
The only reason that the compiler let the code through (i.e. compiled it) is that there is a backwards compatibility feature that allows you to have a char* that points to the contents of a string a literal (of type const char[]). You should have got a warning and you should avoid doing that.
Just an FYI. I was unable to comment on a similar question about passing character arrays because it was closed as a duplicate, but the issue is fairly important so hopefully you don't mind if i cross-post.
When using strings in a production application you usually go with UTF-8 because it significantly increases the market without a lot of effort.
http://www.joelonsoftware.com/articles/Unicode.html
Most applications also use a string class to encapsulate the characters. Then you can use something like:
void fn(..., const std::string &static_string, ...);
in your header. If you use a library like gettext, your code looks like:
printf(gettext("and suddenly there's one line which is good.."));
where the english strings act as intuitive indices into localization files and you can rapidly and easily switch languages at install or runtime.
If you can't use a class because you're using C then the gettext docs cover this case as well.

getline in istream and getline in basic_string

string text;
getline(text.c_str(),256);
1) I am getting an error "error: no matching function for call to 'getline(const char*, int)"
What's wrong in the above since text.c_str() also returns a pointer to array of characters.
If I write like this
char text[256]
cin.getline(text, 256 ,'\n');
it works fine. What's the difference between cin.getline and getline?
2) How come
text string;
getline(cin,text,'\n')
accepts the whole line as the input. Where is the pointer to array of characters in this one?
text.c_str() returns a const char *. You may not use it to modify the contents of the string, in any way. It only exists so that you can pass the string data to old C API functions without having to make a copy. You are not allowed to make changes because there is no way that the string object that holds the data could possibly find out about them, and therefore this would allow you to break the string's invariants.
Furthermore, std::getline accepts completely different parameters. (You would know this if you took two seconds to type 'std::getline' into Google.) The error means exactly what it says: "no matching function for call" means "you can't call the function with these kinds of parameters", because every overload of the function accepts something different (and incompatible).
std::getline accepts these parameters:
A stream. You have to pass this because otherwise it doesn't know where to read from.
A string object to read into. NOT a char buffer.
Optionally, a line delimiter char (same as the stream getline member function).
There is not really any such function as "cin.getline". What you are calling is the member function "getline" of the object "cin" - a global variable that gets defined for you when you #include <iostream>. We normally refer to this according to what class the function is defined in - thus, std::istream::getline.
std::istream::getline accepts these parameters:
A char buffer.
Optionally, a line delimiter char.
It does not need a stream parameter because it is a member function of the stream: it uses whatever stream we called it with.
I don't really get what the questioner is trying to do.
C++ allows function overloading, so the compiler is looking for a free function called getline that matches the parameters you have passed, and no such function exists, nor should it exist (what would getline(const char*, int) do anyway?)
The question has been asked many times why getline(istream&, string&) is a "free" function and not part of the iostream interface. Answers suggested have been that iostream outdates STL or that iostream has no dependent on the basic_string class (anywhere, which is also why opening files is done with raw pointers), and Herb Sutter would commend making getline a free-function because he feels class member functions should be minimal (and std::string has far too many, eg the find functions which could be free ones that use the class).
One thing about that function though is how useful it is as you do not need to pre-allocate a buffer and "guess" how big to make it. (Having said that if you read from a big file into a std::string you could bad_alloc if there are no newlines to be found!).
string::c_str() returns a const char *, not a char *. getline works with a string, so what you want is
string text;
getline(cin, text, '\n');
This version of getline allows the string to grow as much as needed. If you need to limit it to a certain number of characters, you would need to use a vector<char> as in the previous answer.
text.c_str() is an array of const characters. The const means neither you nor any function (including any sort of getline) may write into it.
There's no portable way to use a string as a writeable array of characters. But when necessary, you can use a vector<char> instead:
std::vector<char> buffer(256);
std::size_t len = cin.getline(&buffer[0], buffer.size());
std::string text(&buffer[0], len);
But just using the string overload of getline is probably best here.

Why did this work with Visual C++, but not with gcc?

I've been working on a senior project for the last several months now, and a major sticking point in our team's development process has been dealing wtih rifts between Visual-C++ and gcc. (Yes, I know we all should have had the same development environment.) Things are about finished up at this point, but I ran into a moderate bug just today that had me wondering whether Visual-C++ is easier on newbies (like me) by design.
In one of my headers, there is a function that relies on strtok to chop up a string, do some comparisons and return a string with a similar format. It works a little something like the following:
int main()
{
string a, b, c;
//Do stuff with a and b.
c = get_string(a,b);
}
string get_string(string a, string b)
{
const char * a_ch, b_ch;
a_ch = strtok(a.c_str(),",");
b_ch = strtok(b.c_str(),",");
}
strtok is infamous for being great at tokenizing, but equally great at destroying the original string to be tokenized. Thus, when I compiled this with gcc and tried to do anything with a or b, I got unexpected behavior, since the separator used was completely removed in the string. Here's an example in case I'm unclear; if I set a = "Jim,Bob,Mary" and b="Grace,Soo,Hyun", they would be defined as a="JimBobMary" and b="GraceSooHyun" instead of staying the same like I wanted.
However, when I compiled this under Visual C++, I got back the original strings and the program executed fine.
I tried dynamically allocating memory to the strings and copying them the "standard" way, but the only way that worked was using malloc() and free(), which I hear is discouraged in C++. While I'm curious about that, the real question I have is this: Why did the program work when compiled in VC++, but not with gcc?
(This is one of many conflicts that I experienced while trying to make the code cross-platform.)
Thanks in advance!
-Carlos Nunez
This is an example of undefined behavior. You're passing the result of string::c_str(), a const char*, to strtok, which takes a char*. By modifying the contents of the std::string data, you're invoking undefined behavior (you should be getting warnings for this unless you're casting).
When are you checking the value of a and b? In get_string, or in main? get_string is passed copies of a and b, so strtok will most likely not alter the originals in main. However, it could, as you are invoking undefined behavior.
The "right way" to do this is to use malloc/free or new[]/delete[]. You're using a C function, so you're already guilty of the same crime as you would be using malloc/free. A relatively elegant yet safe way to approach this is:
char *ap = strdup(a.c_str());
const char *a_ch = strtok(ap, ",");
/* do whatever it is you do */
free(ap);
Also bear in mind that strtok uses global state, so it won't play well with threads.
Tokens will be automatically replaced by a null-character by function strtok. That is not what you can do with constant data.
To make your code safe and cross-platform consider using boost::tokenizer.
I think the code is working because of differences in string implementation. VC++ string implementation must be making copies when you pass them to a function that could potentially modify the string.