c++ crashes on writing public variable - c++

I wrote a simple test program in c++ but why does this crash on:
s[i] = s[i] - 'a' + 'A';
with the exception: Access violation writing location 0x01327808
#include "stdafx.h"
#include <iostream>
using namespace std;
class String
{
public:
char *s;
int len();
void upper();
String(char*);
};
String::String(char*x)
{
s = x;
}
int String::len()
{
return strlen(s);
}
void String::upper()
{
for (int i = 0; i < len(); i++)
{
if (s[i] >= 'a' && s[i] <= 'z')
{
cout << s[i] << endl;
s[i] = s[i] - 'a' + 'A';
}
}
};
int main()
{
String s("test");
s.upper();
cout << s.len() << endl;
cout << s.s << endl;
system("pause");
}

It's because of:
String s("test");
What this does is to pass the const char * "test" to your constructor which then simply stores the address of that string.
Later, when you try to modify the memory that the pointer points to, that's undefined behaviour.
Typically, string literals will be stored in read-only memory to allow certain optimisations to take place, and any attempt to modify them will result in a access violation.
If you were to change:
String s("test");
into:
char cp[] = "test";
String s(cp);
you may well find it will work.
However, your class should really be making a copy of the string for its own purposes - a mere pointer is unsafe, since the code that passed you that pointer can change the contents of it as well.
Things you should change in your code to make it safer:
s should be a private member, not a public one.
your constructor should make its own copy of the string:s = new char[strlen(x)+1];strcpy (s,x);.
add a destructor to take care of that as well:String::~String() { delete[] s; }.
consider having your constructor receive a const char * (since you're not changing it).
consider using toupper(ch) instead of ch - 'a' + 'A'. While your formula works for ASCII, I don't believe it's guaranteed by the standard.
cout stuff should be handled by the class rather then code outside of it (this will be mandatory once you make s private.
consider having a no-argument constructor so that string arrays will work okay.

String literals are constant (you're exploiting a deprecated automatic conversion to char *), and you're trying to modify one inside your class, which is undefined behavior.
In practice, the access violation happens because newer versions of VC++ put string literals in a section of the executable which is mapped in memory as read-only (which is definitely a good thing), and any attempt to write it results (correctly) in an access violation.
Solution: copy the string passed to the constructor (which, by the way, should take a const char *) in a buffer local to your class, probably dynamically allocated. In this last case, if you don't want to implement a copy constructor and an assignment operator, make them private thus avoiding that the default ones are executed, otherwise you'll get troubles (double frees and other nasty stuff) if you create copies of a String object.
Better solution: in real projects, don't reinvent the wheel and use a good pre-made string class like std::string/CString/wxString/whatever the framework you're using provides you.

String::String(char*x)
{
s = x;
}
You shouldn't copy string literals address just like above. Behavior is undefined.
you need to allocate memory and copy it.
size_t len = strlen(x);
s = new char[len+1];
strcpy(s,x);
Make sure to delete it in destructor of your String class.

You tried to assign to a string literal. They are not char*, they are const char*. Attempting to modify a string literal is undefined behaviour.

"test" is a const string, you cannot write to it.
Instead of
s = x;
try doing strcpy, so that s will have a non-const copy of x, rather than the const original.

You cannot modify "test" string by accessing with [].
The error is s[i] = something.
Infact, char* is only a pointer to an IMMUTABLE string.
In the constructor you must allocate space internally for handle "test" string literal and then you can modify single character accessing with [] operator.
Example to solve (with basic copyng):
String::String(char *original)
{
size_t len = strlen(original) + 1;
s = new char[len];
for ( size_t i = 0; i < len; ++i )
{
s[i] = original[i];
}
}

Related

C++ Object Copy

I'm just looking at the following code snippet:
#include<iostream>
#include<cstring>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL); // constructor
~String() { delete [] s; }// destructor
void print() { cout << s << endl; }
void change(const char *); // Function to change
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
void String::change(const char *str)
{
delete [] s;
size = strlen(str);
s = s + 1;
s = new char[size+1];
strcpy(s, str);
}
int main()
{
String str1("StackOverFlow");
String str2 = str1;
str1.print();
str2.print();
str2.change("StackOverFlowChanged");
str1.print();
str2.print();
return 0;
}
I expect the output as:
StackOverflow,
StackOverflow,
StackOverflow,
StackOverflowChanged.
Before str2.change("StackOverFlowChanged") line, both str1 and str2's s point to the same memory location. However, in change method, since the pointer value changed, I except now str1 and str2's s point to the different locations and this is not the case. Can somebody explain why this is the case?
After calling str2.change, str1 no longer has a valid pointer. Since the two objects were sharing the same pointer, by deleting the array in one object, the other object now points to a deleted array. Attempting to access the array pointed to by str1 is undefined behavior, so str1.print() is invalid code.
Now, in this particular case, odds are good that the new char[] in str2.change just so happens to return a pointer to an address identical to the one that was just deleted. After all, the memory was just freed up, and no other allocations were made in the meantime. So while str1's pointer is still invalid, it just so happens to work out to pointing at a valid string by the time str1.print gets called.
But that's just happenstance; an implementation didn't have to do that. Undefined behavior is undefined, and you need to properly follow the Rule of 5. Or just use std::string.
The problem is that you called delete[] on the memory pointed by str1.
The runtime library is then allowed to reuse the same memory for the next allocation call and apparently this is what happened.
str1 didn't change the memory it pointed to, but the content changed.
Note that using a pointer to memory after it has been delete[]d is undefined behavior. So indeed anything can happen.
When you write classes that own heap allocated memory a lot of care should be taken about who owns the memory and when this memory is going to be released; in particular a lot of attention should go to copy constructor and assignment operator because the automatically generated code is rarely the correct one in case of memory owned using raw pointers.
No, str1 and str2 do not point to the same memory location, before str2.change("StackOverFlowChanged") line. str2 is in a different location but with the same value as of str1. You can verify this using -
cout << &str1 << '\t' << &str2 << endl;
It will show that they have different locations in memory.

Initializing a Struct's variable const char* const* with C++

I am trying to solve a coding question that requires the results be returned using a given struct. The struct is defined as:
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
}
Where the lastNames is a pointer to last names that are each terminated by a non-alpha char. I can not seem to find any way to convert the vector of strings that I am using to compile all the last names into a variable that I can assign to lastNames. I have tried making a single string with all the last names and assigning it with c_str() like so:
Ans->lastName = allNames.c_str(); but this gives me an error. Due to the limitations of the question I am unable to change the struct variable to anything else. How can I assign a string to a const char* const*
The structure being used effectively uses a C-style approach to defining a variable sized array of pointers to char (with const sprinkled over it). You’ll need storage for both the array of char const* as well as the entities pointed to. Here is how you could build it from a std::vector<std::string>:
std::vector<std::string> strings = somehow_compute_the_strings();
std::vector<char const*> array;
for (std::string const& s: strings) {
array.push_back(s.c_str());
}
Answer answer = { array.data(), array.size() };
Of course, you can’t return answer without the pointer inside pointing to stale data: you’d need to keep the two std::vectors alive. Potentially these two objects could be made members of an object the function is called on. To actually return an object of type Answer without a place to hold on to the std::vectors you could allocate the relevant entities and accept that the result will yield a memory leak unless the caller can clean the result up.
You can't just cast stuff. struct Answer is expecting a char**, so you are going to have to build it and keep it valid as long as the struct Answer is in use. At least they were kind enough to let us know they don't intend to modify it or mess with cleaning up the memory, since it takes "const char * const *".
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
typedef std::vector<std::string> VectorOfStrings_type;
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
};
class AnswerWrapper
{
private:
// construct and maintain memory so the pointers in the Answer struct will be valid
char ** lastNames;
unsigned int numberOfPeople;
public:
AnswerWrapper(const VectorOfStrings_type &input){
numberOfPeople = input.size();
// create the array of pointers
lastNames = static_cast<char**>(
malloc(numberOfPeople * sizeof(char*))
);
// create each string
for (unsigned int i = 0; i < numberOfPeople; ++i){
const std::string &name = input[i];
// allocate space
lastNames[i] = static_cast<char*>(
malloc(name.size() + 1)
);
// copy string
strncpy(lastNames[i], name.data(), name.size());
// add null terminator
lastNames[i][name.size()] = '\0';
}
}
operator Answer (){
return Answer{ lastNames, numberOfPeople };
}
~AnswerWrapper(){
// critcally important, left as an exercise
assert(0);
}
};
void SomeFunctionWhichUsesAnswer(Answer a){
// presumably you have some legacy C code here
// but here's a quick and easy demo
for (unsigned int i = 0; i < a.numberOfPeople; ++i)
std::cout << a.lastNames[i] << std::endl;
}
int main() {
// Here is your vector of strings
VectorOfStrings_type myData { "custom formatted data goes here", "and more here", "and again" };
// You must construct a buffer for the "Answer" type, which must remain in scope
AnswerWrapper temp{ myData };
// AnswerWrapper is currently in scope, so inside this function, the pointers will be valid
SomeFunctionWhichUsesAnswer(temp);
}
Also, I noticed that the strings in Answer are not referred to as null terminated. That is a separate issue you can take care of.
A const member variable can only be assigned in the constructor.
if you can add to the struct, define a constructor, and use the : lastname(value) syntax; or use the struct Answer myVar{value,number}; initialization, right where you declare your instance.
Another - ugly, dangerous, and frowned upon - alternative is a cast: (char**) lastname = value;, or in C++ syntax reinterpret_cast<char**>(lastname) = value.
If someone is teaching you either of those approaches, change the teacher.

How to make char array and std::string "in a relationship"?

I'm looking for a way to associate a char array with a string so that whenever the char array changes, the string also changes. I tried to put both char array and string variables in a union but that didn't worked as the compiler complained...
Any ideas are welcome...
class Observable_CharArray
{
char* arr;
std::function<void(char*)> change_callback;
public:
Observable_CharArray(int size, std::function<void(char*)> callback)
: arr(new char[size]), change_callback(callback){}
~Observable_CharArray()/*as mentioned by Hulk*/
{
delete[] arr;
}
void SetCallback(std::function<void(char*)> callback)
{
change_callback = callback;
}
/*other member function to give access to array*/
void change_function()
{
//change the array here
change_callback(arr);
}
};
class Observer_String
{
std::string rep;
void callback(char* cc)
{
rep = std::string(cc);
}
public:
Observer_String(Observable_CharArray* och)
{
och->SetCallback(std::bind(&callback, this, _1));
}
/*other member functions to access rep*/
};
The design can definitely be improved.
There can be other ways to solve your actual problem rather than observing char arrays.
The problem is that the std::string may change the string array inside (especially when it resizes). For instance, c_str returns the address of the current string - documentation says that "The pointer returned may be invalidated by further calls to other member functions that modify the object.".
If you're sure you won't call string methods (hence the string will stay at the same memory location), you could try accessing the c_str pointer (your char array) directly and modify its content.
std::string str = "test";
char* arr = (char*)str.c_str();
arr[3] = 'a';
NOTE: I strongly advice against this unless in a testing context.
In other words, the string class doesn't guarantee it's going to stay in the same place in memory - meaning trying to access it through a char array is impossible.
The best is to create another string class that enforces the char array to always stay the same size (and so can stay in the same memory position all the time). You could also create a bigger array (max size string for instance) to cope with any string size changes - but that should be enforced in your wrapper class.
Well you can do this, but you shouldn't
#include <iostream>
#include <string>
int main()
{
std::string test("123456789");
std::cout << test << "\n";
char* data = &test.front(); // use &(*test.begin()) for pre-C++11 code
for ( size_t i(0); i < test.size(); ++i )
{
data[i] = 57 - i;
}
std::cout << test << "\n";
}
Output will be
123456789
987654321
This however goes again everything std::string is trying to facilitate for you. If you use data, you risk causing UB and changes to test may make data point to garbage.
You should not do this!
However, there are many (dangerous) ways to achieve it:
char* cStr = const_cast<char*>(cppStr.c_str());
or
char* cStr = const_cast<char*>(cppStr.data());
or
char* cStr = &cppStr[0];
But beware that the cppStr might be reallocated whenever you touch it, hence invalidating your cStr. That would crash at some point in time, although maybe not immediately (which is even worse).
Therefore, if you are going to do this anyway. Make sure to cppStr.reserve(SOMETHING) *before* you get the cStr out of it. This way, you will at least stabilise the pointer for a while.

c++ pointer not declared

I am writing a member function for a class where I would like to print out some dynamically allocated array according to the string name passed to the member function. The following code somehow get a compilation error:
error: 'tmp' was not declared in this scope
How should I do the coding? What is the problem of my code?
void backgrnd::print(const char m[]){
if (m == "interior")
int* tmp = this->interior;
else if (m == "fB")
float* tmp = this->fB;
for (int i=0;i<this->n_vox;++i)
cout << tmp[i] << ' ';
}
There are a few problems with your code.
You're passing a string by pointer (writing const char [] is quite the same as writing const char * – BTW, const is left associative and you could write it as char const * as well).
void backgrnd::print(const char m[]){
Anyway, in the next line you're comparing this pointer m with the pointer refering to the string literal constant "interior"
if (m == "interior")
And this does not what you had most likely in mind. This operation compares the values of the pointers and not the strings! The pointers would only compare as equal, if the pointer you passed to the function was that of the same string literal "interior", which is very unlikely the case. If it was just any other string, even if it also contained the character sequence interior, it would not compare equal. It would also happen if the compiler and/or linker didn't redact redundant string literals into a single pointer constant.
And of course the other pointer - string literal comparisions suffer from the same problem.
Now the next problem is, that you create a scoped pointer variable tmp, which you initialize with some instance class member pointer variable of the same type. But as soon as the scope is left that variable is no longer visible...
int* tmp = this->interior;
else if (m == "fB")
float* tmp = this->fB;
... and this for loop can no longer see it. Now this loop is problematic by itself, because it's unclear what n_vox means.
for (int i=0; i < this->n_vox; ++i)
I guess you wrote the above to save some code duplication below. The problem is: C++ is a statically typed language so the following statement can not "dynamically" type to the type of the tmp variable.
cout << tmp[i] << ' ';
}
Here are a few suggestions:
when using C++ you should use std::string instead of naked char arrays. This also makes the equality operator == do what you naively expected. If you insist on using C-style char arrays, use a string comparision function like strncmp.
Since you need to write statically typed cout<< statements anyway, move that loop into the if clauses. Use curly braces to enclose them!.
Use braces if you are new to programming.. those variables are in local scope.
if (m == "interior")
{
int* tmp = this->interior;
}
....
tmp is out of scope..
tmp variable is only in if/else scope, it's not available in for loop.
However, I suggest a better print function:
void backgrnd::print(const std::string& m)
{
if (m == "interior")
{
std::cout << *interior << std::endl;
}
else if (m == "fB")
{
std::cout <<fB << std::endl;
}
}

deprecated conversion from string constant to 'char*' [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C++ deprecated conversion from string constant to 'char*'
I want to pass a string via char* to a function.
char *Type = new char[10];
Type = "Access"; // ERROR
However I get this error:
error: deprecated conversion from string constant to 'char*'
How can I fix that?
If you really want to modify Type:
char *Type = new char[10];
strcpy( Type, "Access" );
If you don't want to modify access:
const char *Type = "Access";
Please note, that, however, arrays of char in C and in C++ come with a lot of problems. For example, you don't really know if the call to new has been successful, or whether it is going to throw an exception. Also, strcpy() could surpass the limit of 10 chars.
So you can consider, if you want to modify type later:
std::string Type = "Access";
And if you don't want to modify it:
const std::string Type = "Access";
... the benefit of using std::string is that it is able to cope with all these issues.
There are a couple of things going on here.
char *Type = new char[10];
This create a char* pointer named Type and initializes it to point to the first element of a newly allocated 10-element array.
Type = "Access"; // ERROR
This assignment doesn't do what you think it does. It doesn't copy the 6-character string "Access" (7 characters including the terminating '\0') to the array you just created. Instead, it assigns a pointer to the first element of that array into your pointer Type. There are two problems with that.
First, it clobbers the previous value of Type. That 10-character array you just allocated now has nothing pointing to it; you can no longer access it or even deallocate it. This is a memory leak.
This isn't what the compiler is complaining about.
Second, a string literal creates a statically allocated const array ("statically allocated" meaning it exists for the entire execution of your program). Type is not declared with a const qualifier. If the compiler allowed you to point Type to the string "Access", you could use that pointer to (attempt to) modify it:
Type = "Access";
Type[0] = 'a'; // try to change the string to "access"
The purpose of const is to prevent you from modifying, or even attempting to modify, things that are read-only. That's why you're not allowed to assign a non-const pointer value to a const pointer object.
Since you're programming in C++, you're probably better off using std::string.
I want to pass a string via char* to a function.
Here is how you can pass a string via char* to a function (note the required const keyword in the function signature.)
#include <iostream>
void f(const char* p) {
std::cout << p << "\n";
}
int main() {
f("Access");
}
But, what if you are invoking an existing function, and cannot modify its signature?
If you have some external guarantee that the function will not write through its argument pointer,
#include <iostream>
void f(char* p) {
std::cout << p << "\n";
}
int main() {
f(const_cast<char*>("Access"));
}
If, on the other hand, the function might write to the string, then you'll need to allocate space for the string:
#include <iostream>
void f(char* p) {
*++p;
std::cout << p << "\n";
}
int main() {
// Allocate read-write space on the heap
char *p = new char[strlen("Access"+1)];
// Copy string to allocated space
strcpy(p, "Access");
f(p);
delete p;
}
or,
#include <iostream>
void f(char* p) {
*++p;
std::cout << p << "\n";
}
int main() {
// Allocate read-write space on the stack
char arr[] = "Access";
f(arr);
}
But, the best course by far is to avoid the whole pointer mishegas:
#include <iostream>
void f(const std::string& p) {
std::cout << p << "\n";
}
int main() {
f("Access");
}
You've got a basic operations problem here, not a coding issue.
When you want to change the contents of a C char array, you do not use the assignment operator. That will instead change the value of the underlying pointer. Ick.
Instead you are supposed to use the C string library routines. For instance, strcpy (Type, "Access"); will copy the string literal "Access" into your character array, with its all-important trailing nul character.
If you are using C++ (as your tags indicate), you should probably be using std::string instead of arrays of char. Assignment works they way you are expecting there.