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.
Related
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.
I am trying to learn about inheritance in C++. I am trying to make a subclass of vector::vector that only takes string pointers.
My grip on pointers and references is admittedly weak, but I can't for the life of me work out why the following code is setting each string to the same address:
#include <iostream>
#include <vector>
using namespace std;
class StringVector : public vector<void*> {
public:
void push_back(const string* str) {
vector::push_back(&str);
}
string* operator[](int pos) {
return (string*)vector::operator[](pos);
}
};
main() {
StringVector sv;
string str1 = "hello";
string str2 = "world";
sv.push_back(&str1);
sv.push_back(&str2);
for (int i = 0; i < 2; i++)
cout << sv[i] << " ";
}
When I run as is, I get:
0xffffcb68 0xffffcb68
i.e. same address.
When I try to deference the sv[i] (i.e. *sv[i]); I get an exception. Can anyone tell me where I am going wrong?
You're pushing &str which takes the address of the pointer, so the type you're pushing is string**. What's more, you're storing address of a short-lived variable (pointer) - it gets destroyed as soon as you leave your overloaded push_back.
The immediate fix is to simply change the push_back method (remove const on string and pass the pointer to vector::push_back):
void push_back(string* str) {
vector::push_back(str);
}
which is as good as simply removing the method altogether and using the inherited one.
That being said, it's a bad idea to inherit from most standard containers. You can have a vector of string pointers just by typing vector<string*>.
And if you want to print the string values instead of pointers, you need to dereference them:
for (int i = 0; i < 2; i++)
cout << *sv[i] << " ";
In this function
void push_back(const string* str) {
vector::push_back(&str);
}
you didn't push the address of the string - you pushed the address of the pointer to string. And in successive calls, the two different pointers were likely stored in the same place (albeit at different times).
Because your vector takes a void* and any pointer can convert to void*, your compiler didn't have a chance to alert you to your error. What you probably want is to use a std::vector<std::string*> or std::vector<const std::string*>. You shouldn't inherit from the standard collections; prefer to use them as members instead.
Consider this a lesson in the dangers of void* and of casts!
int FunctionName(const char *pValueName, const char *pValueData, long iMaxValueSize)
{
char *pDataToStore = const_cast<char *>(pValueData);
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize);
...
...
}
In the upper code snippet ProcessData() function modifies the char*, which it receives as parameter. Now even after assigning pValueData into pDataToStore, after ProcessData() get executed, value of pValueData is being same as pDataToStore.
My aim is to keep intact value of pValueData which is being passed as const char*
My aim is to keep intact value of pValueData which is being passed as
const char*
That's impossible. Passing via const means it cannot be modified, except when it was originally not constant.
Example:
char *ptr1 = new char[100]; // not const
char *ptr2 = new char[100]; // not const
int i = FunctionName(ptr1, ptr2, 123);
In this case, you could technically keep the const_cast. But what for? Just change your function parameters to take char *:
int FunctionName(char *pValueName, char *pValueData, long iMaxValueSize)
{
int iActualSiz = ProcessData(pValueData, iMaxValueSize);
// ...
}
However, you most likely want to be able to pass constant strings. For example string literals:
int i = FunctionName("name", "data", 123);
String literals are unmodifiable and thus require your function to take char const *. A later attempt to modify them causes undefined behaviour.
As you can see, the error is in the general architecture and code logic. You want to modify something and at the same time you do not want to allow to modify it.
The question is: What happens with your pDataToStore when ProcessData is done with it? Does the caller of FunctionName need to be aware of the modifications? Or is it just internal business of FunctionName?
If it's just internal business of FunctionName, then you can keep its signature intact and have ProcessData modify a copy of the passed data. Here is a simplified (not exception-safe, no error checks) example:
int FunctionName(const char *pValueName, const char *pValueData, long iMaxValueSize)
{
char *copy = new char[strlen(pValueData) + 1];
strcpy(copy, pValueData):
int iActualSiz = ProcessData(copy, iMaxValueSize);
// ...
delete[] copy;
}
The nice thing is that you can now massively improve the interface of FunctionName by hiding all the low-level pointer business. In fact, why use so many pointers at all when C++ standard classes can do all the work for you?
int FunctionName(std::string const &valueName, std::string const &valueData, long maxValueSize)
{
std::vector<char> copy(valueData.begin(), valueData.end());
int actualSize = ProcessData(©[0], maxValueSize);
// ...
// no more delete[] needed here
}
The std::vector<char> automatically allocates enough memory to hold a copy of valueData, and performs the copy. It fully automatically frees the memory when it is no longer needed, even if exceptions are thrown. And ©[0] (which in C++11 can be written as copy.data()) is guaranteed to yield a pointer to the internally used data, so that low-level C functions can modify the vector's elements.
(I've also taken the chance to remove the Microsoft-style Hungarian Notation. It's a failed experiment from the 90s, and you've even used it incorrectly, supposing that a leading i is supposed to indicate an int.)
The bottom line is really:
If you need a const_cast anywhere in your code to make it compile, then somewhere else there is at least either one const missing or one too much. A const_cast always makes up for a mistake in another piece of code. It is always a workaround and never a solution designed up front.
Well I have solved the issue by creating the heap memory.
char *pDataToStore = new char[iMaxValueSize];
memcpy(pDataToStore, pValueData, iMaxValueSize*sizeof(char));
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize);
...
....
delete []pDataToStore;
You have to make a difference between a const qualified type and a const qualified object.
The standard states in section 7.1.6.1: cv-qualifiers: (cv = const or volatile)
A pointer or reference to a cv-qualified type need not actually point
or refer to a cv-qualified object, but it is treated as if it does; a
const-qualified access path cannot be used to modify an object even if
the object referenced is a non-const object and can be modified
through some other access path.
If your pointer points to a non const object, the casting away will enable you to modifiy the objet, but as someone told, you are lying to the user of your function.
It your pointer points to a real const object (i.e. in const protected memory), the compiler will compile your code, but you might have a segmentation fault, typical for undefined behaviour.
Here an example, using the fact that "Ordinary string literal (...) has type “array of n const char”, where n is the size of the string (...)" (see standard, section 2.14.5):
char *my_realconst = "This is a real constant string"; // pointer does not claim that it points to const object
(*my_realconst)++; // Try to increment the first letter, will compile but will not run properly !!
So if your function ProcessData() is legacy code that is only reading the data but has forgotten to mention a const in the parameter list, your cast-away will work. If your function is however altering the data, it might work or it might fail, depending how the data poitned to was created !
So try to avoid casting const away if you are not 100% sure of what the effects will be ! Better clone your object the hard way creating a temporary object and copying the content.
I propose you a small template to handle these kind of issues easily:
template <typename T>
class Buffer {
size_t sz; // size
T* addr; // pointed
public:
Buffer(const T*source, size_t l) : sz(l), addr(new T[l]) { std::copy(source, source + l, addr); } // allocate and copy
~Buffer() { delete[]addr; } // destroy memory
operator T* () { return addr; } // convert to pointer
};
You may use your existing code almost as is:
Buffer<char> pDataToStore(pValueData, iMaxValueSize); // create the automatic buffer
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize); // automatic use of pointer to buffer
cout << "modified copy: " << pDataToStore << endl;
cout << "original: " << pValueData << endl;
The buffer will be automatically released once pDataToStore is no longer in scope.
If you have similar issues with wchar_t buffers or anything else, it will work as well.
For explanations on the evil of casting away const, see my other answer
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.
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];
}
}