I am used to higher level languages (java, python etc.), where this is dead obvious. I am trying to pass a string the user inputs to cin, the name of a file to open. There appears to be some sort of pointer madness error, and my code will not compile.
I deleted some of my code to make it more clear.
#include <iostream>
#include <fstream>
using namespace std;
string hash(string filename);
int main(){
cout << "Please input a file name to hash\n";
string filename;
cin >> filename;
cout <<hash(filename);
return 0;
}
string hash(string filename){
file.open(filename);
if(file.is_open()){
file.close();
}
return returnval;
}
Here is the compile time error.
<code>
$ g++ md5.cpp
md5.cpp: In function ‘std::string hash(std::string)’:
md5.cpp:22: error: no matching function for call to ‘std::basic_ifstream<char, std::char_traits<char> >::open(std::string&)’
/usr/include/c++/4.2.1/fstream:518: note: candidates are: void std::basic_ifstream<_CharT, _Traits>::open(const char*, std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]
</code>
(I know that there are libraries for md5 hashes, but I am trying to learn about how the hash works, and eventually hash collision)
open() takes a C-style string. Use std::string::c_str() to get this:
file.open (filename.c_str());
In order to use just a string, as pointed out below, you'll need to use a compiler with C++11 support, as the overload was added for C++11.
The reason it's not like Java etc. is that it came from C. Classes didn't exist in C (well, not nearly as well as they do in C++), let alone a String class. In order for C++ to provide a string class and keep compatibility, they need to be different things, and the class provides a conversion constructor for const char * -> std::string, as well as c_str() to go the other way.
Consider passing the argument (and maybe the return too) as const std::string & as well; no unnecessary copies. The optimization would probably catch those, but it's always good to do.
Related
The problem is simple, the code below does not work. it says Process finished with exit code -1073740940 (0xC0000374). Removing ampersand does not change anything.
int main(){
string x;
scanf("%s",&x);
cout << x;
}
scanf() with the %s format specifier reads bytes into a preallocated character array (char[]), to which you pass a pointer.
Your s is not a character array. It is a std::string, a complex object.
A std::string* is not in any way the same as a char*. Your code overwrites the memory of parts of a complex object in unpredictable ways, so you end up with a crash.
Your compiler should have warned about this, since it knows that a char* is not a std::string*, and because compilers are clever and can detect mistakes like this despite the type-unsafe nature of C library functions.
Even if this were valid via some magic compatibility layer, the string is empty.
Use I/O streams instead.
You cannot pass complex objects through the ... operator of printf/scanf. Many compilers print a warning for that.
scanf requires a pointer of type char* pointing to sufficient storage for an argument of %s. std::string is something completely different.
In C++ the iostream operators are intended for text input and output.
cin >> x;
will do the job.
You should not use scanf in C++. There are many pitfalls, you found one of them.
Another pitfall: %s at scanf is almost always undefined behavior unless you you really ensure that the source stream can only contain strings of limited size. In this case a buffer of char buffer[size]; is the right target.
In any other case you should at least restrict the size of the string to scan. E.g. use %20s and of course a matching char buffer, char buffer[21];in this case. Note the size +1.
You should use cin. But if you want to use scanf() for whatever reason and still manipulate your strings with std::string, then you can read the C-string and use it to initialize your C++ string.
#include <iostream>
#include <cstdio>
#include <string>
using std::cout;
using std::string;
int main()
{
char c_str[80];
scanf("%s", c_str);
string str(c_str);
cout << str << "\n";
}
If you want to use strings, use cin (or getline).
string s;
cin>>s; //s is now read
If you want to use scanf, you want to have a char array (and don't use &):
char text[30];
scanf("%s", text); //text is now read
You can use char[] instead of string
include <iostream>
using namespace std;
int main()
{
char tmp[101];
scanf("%100s", tmp);
cout << tmp;
}
Please help.
I have this program from here that calls a function in a header file.
#include <iostream>
#include "md5.h"
#include <string>
using namespace std;
int main(){
string x;
char* v_MD5String;
MD5 md5 ;
v_MD5String = "Hello World";
x = puts(md5.digestString(v_MD5String));
cout << x;
return 0;}
The function called:
char* digestString( char *string ){
Init() ;
Update( (unsigned char*)string, strlen(string) ) ;
Final() ;
return digestChars ;}
The above works, however when I use input from the user it compiles, but the run crashes without any errors.
In the program, this is changed:
v_MD5String = "Hello World";
to this:
cin >> v_MD5String;
What should I do to get this to work?
Thanks.
So, if I understand correctly, you have the following function declared in a header file which you cannot modify:
char* digestString( char *string );
You should first know that this is questionable coding style. The function takes a char * rather than a char const *, which implies that the passed data is changed, yet it also returns something. I had to dig around in the implementation posted on the page you linked to find out that string is really an input parameter, so that the author just forgot about using const and the data is not going to be changed anyway.
(The data not going to be modified is at least my assumption upon superficial code analysis and some compile tests. You should ask the author to be really sure!)
If you use this function in C++, your first task should be to provide a safer, easy-to-understand wrapper function which uses real C++ strings (the std::string class), not C strings (which happen to be completely unencapsulated pointers to characters in memory, which is fine in the C world but not in C++). You already use one std::string in your program. That's good. Now use it more:
std::string SafeDigestString(MD5 &md5, std::string const &input)
{
// the input of digestString will never be modified:
return md5.digestString(const_cast<char *>(input.c_str()));
}
Both the const & and the parameter name make it clear that we are dealing with input.
Note that I used a const_cast<char *> to pass the std::string's C-compatible data representation, which is char const *, to the digestString function. This is one of the rare cases where a const_cast is appropriate; it's also a typical one, namely making up for shortcomings with regards to const declarations in other code you have to use. If all functions in the MD5 class correctly declared their input parameters const, then no const_cast would be needed.
Also note that I just prepend every std identifier with std::, rather than having using namespace std. This is often the better, simpler, more consistent choice.
Now that we have our safe C++ mechanism in place, main becomes drastically simpler:
int main()
{
MD5 md5;
std::string result = SafeDigestString(md5, "Hello World");
std::cout << result << "\n";
}
We have laid the base to implement user input, which is best done with the std::getline function:
int main()
{
MD5 md5;
std::string input;
std::getline(std::cin, input);
std::string result = SafeDigestString(md5, input);
std::cout << result << "\n";
}
I'm trying to make boost::string_ref working as I want to, but I'm facing a problem right now - following code does not compile:
#include <boost/utility/string_ref.hpp>
#include <iostream>
#include <string>
using namespace std;
int main() {
string test = "test";
boost::string_ref rtest(test);
cout << (rtest == "test")<<endl;
}
and the gcc throws 30kB error log, starting with
source.cpp: In function 'int main()':
source.cpp:10:19: error: no match for 'operator==' (operand types are 'boost::string_ref {aka boost::basic_string_ref<char, std::char_traits<char> >}' and 'const char [5]')
cout << (rtest == "test")<<endl;
^
How to compare boost::string_ref to std::string?
Honestly, I'd just avoid using string_ref entirely until it matures. The fact that you can't compare a string_ref to a std::string or a const char * out of the box should set alarm bells ringing (looks like they forgot to write a bunch of comparison operators), and worse, it doesn't look like the library received sufficient testing (e.g. bug 8067!).
Just make a string_ref out of the string. They are very cheap to construct. Though against a string literal, you may want to include the length. Otherwise it's going to iterate once to find the end of the string, and then iterate again to compare them. Just make sure that if you change the string, you keep the count up to date.
cout << (rtest == boost::string_ref("test",4)) << endl;
With a std::string, you don't need to worry about the count, because string_ref will just call the size() member function, which is also very cheap.
string add_text()
{
const int string_size(30);
string add_string;
cin.getline (add_string,string_size,'\n');
return add_string;
}
When I compile the program with the function above, I get an error. Note that I am using using namespace std; earlier in the program. If it helps I am using Code Blocks and have also tried compiling the program using the Visual Studio 11 Professional Beta.
The Error:
C:\Users\Jonathan\Documents\Code_Blocks\test_12\main.cpp|32|error: no matching function for call to 'std::basic_istream<char, std::char_traits<char> ::getline(std::string&, const int&, char)'|
Any help with this issue will be greatly appreciated, thanks in advance!
You're calling std::istream::getline(char *, streamsize) - you can see it requires a char * instead of the std::string you're passing.
Use std::getline(std::istream&, std::string&, char) instead, like so:
getline(cin, add_string, '\n');
istream::getline doesn't take a std::string as parameter, but a char*. You can fix it by calling the function correctly.
So, provided you know the max size of the line:
char buff[256]; //or whatever length
cin.getline (buff,string_size,'\n');
string add_string(buff);
Don't use member .getline()s, but global std::getline().
Member .getline()s can only use char * as buffer, while std::getline() can use std::string.
cin.getline is a member function. As such, it is not overloaded to account for every possible type in existence. So, developers overload the global version (i.e., std::getline).
Can I specify what file I want to write into in C++? I want to be able to type in the filename and write into that file. When I try making myfile.open("example.txt") myfile.open(var), I get a big error...
error: no matching function for call to ‘std::basic_ofstream >::open(std::string&)’
/usr/include/c++/4.2.1/fstream:650: note: candidates are: void std::basic_ofstream<_CharT, _Traits>::open(const char*, std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits]
Can you make any sense of this or explain what I am doing wrong? I have a feeling this is very simple, as this is my first week using C++.
If var is an std::string, try:
myfile.open(var.c_str());
The error tells you exactly what's wrong, although the precision of the template types named doesn't help make that crystal clear. Take a look at the reference for .open(). It takes a const char * for the filename, and another optional mode parameter. What you are passing is not a const char *.
Like the error says, it is trying to match the parameters with a character pointer and std::string is not a character pointer. However std::string::c_str() will return one.
try:
myfile.open(var.c_str());
In short, yes you can specify a file to open and write into many different ways.
If you're using an fstream and want to write plain text out, this is one way:
#include <string>
#include <fstream>
int main()
{
std::string filename = "myfile.txt";
std::fstream outfile;
outfile.open( filename.c_str(), std::ios::out );
outfile << "writing text out.\n";
outfile.close();
return 0;
}
Is var a std::string? If so, you should be passing var.c_str() as there is not a variant of .open() that takes a std::string.
Is your variable a string, char[], or char*? I think the open() method wants a c-style string, which would be char[] or char*, so you'd need to call the .c_str() method on your string when you pass it in:
myfile.open(var.c_str());
There is a second parameter to the open call. it should be like myfile.open("example.txt", fstream::out)
The error message is quite clear. It says: the basic_ofstream class (your file object) does not have a member function that's called "open" and takes a single argument of type string (your var). You need to go from string to const char * - for that, you use var.c_str().