Please note that's just a curious question, I don't need a problem solution!
I have a method that takes in a string reference (string &some_string) and only reads from referenced string. Writing some code I forgot that it needs a reference and passed a quoted string (not a variable, just like "something") and IDE suggested casting it to string reference, as it won't compile. I didn't give it a thought and applied the suggestion (now passing (string &) "something"). And my program crashed as it reached this piece of code. So, why exactly would it cause a crash, compiling without even a warning (g++, c++11)? I don't really understand it since I'm only reading from this string.
Example:
#include <string>
#include <iostream>
using namespace std;
class CharSet
{
private:
const string basis = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const int N = 26;
string array; // string containing all element of the set
int length;
bool add_element(char chr) // Add an element (as char) if not already. Returns true if added, false if not.
{
bool b = false;
if (!in_set(chr) && basis.find(chr) != string::npos) {
array += chr;
length++;
b = true;
}
return b;
}
bool in_set(char chr) const // Checks whether an element (as char) is in set. Returns corresponding bool value.
{
bool b = false;
if (array.find(chr) != string::npos) b = true;
return b;
}
public:
explicit CharSet(string& str) // str - string of possible elements
{
array = "";
length = 0;
int len = (int) str.length();
for (int i = 0; i < len; i++)
add_element(str[i]);
if (str.length() != length)
cout << "\nSome mistakes corrected. Elements read: " << array << endl;
}
};
int main()
{
CharSet A((string &)"AKEPTYUMRX");
getchar();
return 0;
}
A cast like this
(string)"a string literal"
constructs a new std::string by passing "a string literal" as an argument to its constructor. It is equivalent to static_cast<std::string>("a string literal"). It is completely valid, even though C-style casts in C++ are a bad idea in general.
On the other hand, a cast like this
(string&)"a string literal"
constructs a reference to an std::string object that resides at the same location as the string literal. Since there is no such object at that location, using this reference results in undefined behaviour (often expressed as a crash). This cast is equivalent to reinterpret_cast<std::string&>("a string literal"). You might know that reinterpret_cast is dangerous and should be avoided as much as possible. With reinterpret_cast, the compiler trusts the programmer nearly totally, which is not really a wise thing to do, but such is the C++ way.
For your function to be able to accept a string literal, it should have a const std::string& parameter, or perhaps better, if you are using C++17, an std::string_view.
Related
I'm working on a project for school, and we just found out that outtextxy() (a function from graphics.h, which we must use) requires as the text parameter a char array.
Here is its declaration: void outtextxy (int x, int y, char *textstring)
The issue is that we need to print out a number of type double, including the decimal point. I have previously tried making it work using knowledge from other similar questions, but none has worked.
Here are is my latest attempt, which resulted in a Segmentation Fault:
char *DoubleToString(long double x)
{
char s[256]="\000";
std::ostringstream strs;
strs << x;
string ss = strs.str();
for(int i=0; i < ss.length(); i++)
s[i] = ss[i];
return s;
}
NOTE: I am still somewhat new to programming and I don't exactly know what ostringstream and the bitshift-looking operation are doing, but I tried to copy-paste that part in hopes of it working.
... requires as the text parameter a char array.
Ok, then use a std::string:
std::string DoubleToString(long double x)
{
std::ostringstream strs;
strs << x;
return strs.str();
}
If you need the underlying character array use the strings data() method. It does return a pointer to the first element of the strings character array. For example:
std::string s = DoubleToString(3.141);
function_that_needs_pointer_to_char( s.data() );
Note that before C++17 data returned a const char* (and since C++11 the character array is null-terminated, as one would expect ;).
I know it is undefined behaviour, but it works. And I only need to pass the returned char* to outtextxy(), and not manipulate it later on, since I have the double variable stored in an object.
char *DoubleToString(long double x)
{
char s[256]="\000";
std::ostringstream strs;
strs << x;
string sd = strs.str();
strcpy(s, sd.data());
return s;
}
I've wanted to create a program using the operator new in order to obtain the right amount of memory for a string of characters.
#include <iostream>
#include <cstring>
using namespace std;
class String
{
private:
char* str;
public:
String(char* s)
{
int len = strlen(s);
str = new char[len + 1]; // points to a memory
strcpy(str, s);
}
~String()
{
cout << "Deleting";
delete[] str;
}
void display()
{
cout << str << endl;
}
};
int main()
{
String s1 = "who knows";
cout << "s1=";
s1.display();
return 0;
}
The constructor in this example takes a normal char* string as its argument. It obtains space in
memory for this string with new; str points to the newly obtained memory. The constructor
then uses strcpy() to copy the string into this new space. Of course, I've used a destructor as well.
However, the error is: no suitable constructor exists to convert from const char[10] to "String".
I'm a total beginner when it comes to pointers and I'm trying to understand why my constructor doesn't work as intended.
As noted in the comments, some compilers will accept your code (depending on how strict they are). For example, MSVC will accept it when "conformance mode" is disabled - specifically, the /Zc:strictStrings option.
However, to fully conform to strict C++ rules, you need to supply a constructor for your String class that takes a const char* argument. This can be done readily by just 'redirecting' that constructor to the one without the const keyword, and casting away the 'constness':
String(const char* cs) : String(const_cast<char*>(cs)) { }
An alternative (and IMHO far better) way is simply to add the const qualifier to your existing constructor's argument, as all the operations you do therein can be be done perfectly well with a const char* (you would then not actually need the non-const version):
String(const char* s) {
int len = strlen(s);
str = new char[len + 1]; // points to a memory
strcpy(str, s);
}
Without one or other of these 'amendments' (or something equivalent), you are passing the address of string literal (which is immutable) to a function (the constructor) that takes an argument that (in theory, at least) points to data that could be changed within that function; thus, a strict compiler is within its 'rights' to disallow this. As your constructor doesn't change the data, then you should have no problem qualifying its argument as const.
This question already has answers here:
Access violation writing location when working with pointers to char
(4 answers)
Closed 5 years ago.
I'm trying to implement tolower(char *) function, but I get access violation error. I came to know that this is because to compiler stores string literals in a read-only memory. Is this true?
Here's some code:
char* strToLower(char *str)
{
if(str == nullptr)
return nullptr;
size_t len = strlen(str);
if(len <= 0)
return nullptr;
for(size_t i = 0; i < len; i++)
*(str+i) = (char)tolower(*(str+i));//access violation error
return str;
}
int main()
{
char *str = "ThIs Is A StRiNgGGG";
cout << strToLower(str) << endl;
system("pause");
return 0;
}
If this is true, how am I supposed to implement such function?
Yes, it's true. You cannot modify a string literal. In fact, if your compiler were not from 1922 it would have prevented you from even obtaining a non-const pointer to a string literal in the first place.
You didn't state your goals, so when you ask "how am I supposed to implement such function" it's not really clear what you want to do. But you can make a copy of the string literal to get your own string, then modify that as you please:
// Initialises an array that belongs to you, by copying from a string literal
char str[] = "ThIs Is A StRiNgGGG";
// Obtains a pointer to a string literal; you may not modify the data it points to
const char* str = "ThIs Is A StRiNgGGG";
// Ancient syntax; not even legal any more, because it leads to bugs like yours
char* str = "ThIs Is A StRiNgGGG";
Of course, since this is C++, you should not be using C-strings in the first place:
std::string str("ThIs Is A StRiNgGGG");
In Lua (apologise, I like working with it the best), the conversion between int and string is done automatically, so
"hi"..2
would result as
"hi2"
In C++ (cause I can't seem to get the default C++11 stoi() and to_string() methods to work) I defined these for myself:
int stoi(string str) {
char* ptr;
strtol(str.c_str(), &ptr, 10);
}
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
which are basically how the default ones are defined anyways.
Then I did this:
string operator+ (string& stuff, int why) {
stuff.append(to_string(why));
}
I tried it on the following code:
void print(string str) {
cout << str << endl;
}
int main() {
cout << stoi("1") + 2 << endl;
print("die" + 1);
return 0;
}
And it outputs
3
ie
Why is this so, and how can I fix it?
EDIT:
Here's what the code looks like now:
using namespace std;
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
string operator+ (string stuff, int why) {
stuff.append(to_string(why));
return stuff;
}
int main() {
cout << string("die") + 2 << endl;
return 0;
}
And it just keeps giving me stackdumps.
Replace print("die" + 1); with cout << std::string("die") + 1;
print() doesn't know what to do with strings. Use std::cout. "die" is a char*, +1 will increment the pointer.
std::string to_string(int i) {
char buf[(sizeof(int)*CHAR_BIT+2)/3+3];
sprintf(buf, "%d", i);
return buf;
}
You need to make an actual buffer to print to. The math is a quick over-estimate of big the largest decimal int is in characters; 3 bits can fit in 1 decimal character, plus null, plus negation, plus rounding, plus 1 for good measure. Hopefully I did not err: do some testing.
Also use snprintf instead of sprintf while you are at it: buffer overflows are not to be toyed with.
The next problem is that "hello" is not a std::string, It is a char const[6] -- an array of 6 char. It can be converted tomstd::string, but +1 will instead convert it to a pointer to the first character, then +1 it to the 2nd character.
Cast it to std::string before.
Finally, it is ambiguous in the standard (really) of pverloading an operator on std::string + int is legal. It is definitely poor practice, as you cannot do it in std legally, and you should overload operators in the type's namespace (so ADL works): these two conflict. On top of that, if std in the future adds such a + your code starts behaving strangely. On top of that, operators are part of a class's interface, and modifying the interface of a class you do not 'own' is rude and a bad habit.
Write your own string class that owns a std::string rather. Or a string view.
Finally, consider telling your compiler to use c++11, you probably just need to pass a flag to it like -std=c++11.
std::string s1("h1");
std::string s2("2");
s1 += s2;
If you are using C++11 compatible compiler you can convert int to string like this:
int i = 2;
std::string s = std::to_string(i);
If you are using Boost library:
#include <boost/lexical_cast.hpp>
int i = 2;
std::string s = boost::lexical_cast<std::string>(i);
Please do not use raw char pointers in C++ for strings.
overloading the operator+ on other than your own types it at best dangerous.
Just use std::to_string in conjunction with operator+ or +=, e.g.
std::string x = "hi";
x += std::to_string(2);
C++14 introduces a user-defined literal that takes a string literal (conversions are applied to make this a pointer) and returns a std::string. In C++11, you can just write your own (this is taken from libstdc++):
inline std::string
operator""_s(const char* str, size_t len)
{
return std::string{str, len};
}
(Note: UDLs without a preceding underscore are reserved names)
And you can use it like this:
// Assumes operator+ is overloaded
print("die"_s + 1);
Demo
"die" is not a std::string. It's a string literal.
Thus when you add 1 to the string literal, it decays to a const char* and the + 1 simply increments that pointer — to next char, 'i'.
Then you call print with the incremented pointer, which causes a std::string to be constructed using that pointer. Since it pointed to the 'i' character, to constructed string is initialized to "ie".
You must first make a std::string out of your string literal to make it call your operator+:
std::cout << std::string("die") + 1;
And then make a few fixes to your operator+:
string operator+ (string stuff, int why) {
return stuff.append(to_string(why));
}
Now it works.
I am using qsort c++ function. I am passing wordArr in my insert function. The objective is to sort the letters for each word belonging to wordArr.However, while using qsort, I get write access violation. Please let me know, where is my mistake.
char* wordArr[]={"cat","bat","dog"};
int tableClass::compChar(const void* a, const void* b)//in my header file this is static
{
return *(const char*)a - *(const char*)b;
}
void tableClass::insert(char* wordArr[],const int size)
{
for (int i = 0; i < size; i++)
{
qsort(wordArr[i], strlen(wordArr[i]), sizeof(char),tableClass::compChar);
}
}
There are several problems with your code:
1) The parameters are wrong, look at the documentation
2) You're trying to modify read-only memory by reordering an array of pointers to strings allocated into a read-only area. That is not allowed and can result in undefined behavior, i.e. anything could happen.
I would suggest using std::sort for this kind of things and possibly use a stl vector
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
void sort_stuff(std::vector<std::string>& arr)
{
sort(arr.begin(), arr.end());
}
bool myfunction (char *i,char *j) {
int res = strcmp(i,j); // Needed to compare all characters
return (res < 0) ? true : false; // Weak ordering criterion
}
int main() {
std::vector<std::string> arr;
arr.push_back("cat");
arr.push_back("dog");
arr.push_back("bat");
sort_stuff(arr);
// --- edit: if you really want to use a char array ---
char cat[] = "cat";
char bat[] = "bat";
char dog[] = "dog";
char* wordArr[]={cat, bat, dog};
sort(wordArr, wordArr+sizeof(wordArr)/sizeof(char*), myfunction);
cout << wordArr[0] << wordArr[1] << wordArr[2];
return 0;
}
Try it live: http://ideone.com/ErEWnb
Edit: I'm not sure why you really want to use a char array but in case you really need it, you should
1) Put those into writeable memory (e.g. local memory, not string literals)
2) Specify the comparison function since if you pass a char pointers array straight away to sort you would compare the pointers instead of the data they point to. And make sure you compare all characters of the strings. strcmp does what you want
bool myfunction (char *i,char *j) {
int res = strcmp(i,j); // Needed to compare all characters
return (res < 0) ? true : false; // Weak ordering criterion
}
...
char cat[] = "cat";
char bat[] = "bat";
char dog[] = "dog";
char* wordArr[]={cat, bat, dog};
sort(wordArr, wordArr+sizeof(wordArr)/sizeof(char*), myfunction);
cout << wordArr[0] << wordArr[1] << wordArr[2];
Your code attempts to sort the characters of each string.
char* wordArr[] = { "cat", "bat", "dog" };
Is an array of pointers to string literals. No matter that you store the location of those character literals as char* and not as char const* (which is only possible due to the wish of the c++ standards committee to preserve backwards compatibility), changing a string literal causes undefined behavior.
In your case, the storage for the string literals will be allocated in read only memory, leading to an access violation when you attempt to write it.
By storing the string literals in memory under your own control, the access violation does not happen:
char cat[] = "cat";
char bat[] = "bat";
char dog[] = "dog";
char* wordArr[]={cat, bat, dog};