Copy string value into address - c++

I have the following class
class MyClass{
char myValue[14] //has a 13 character string in it already
public
void toStr(char* str) const;
}
The instruction is: The member function toStr is query that receives the address of a C-style, null-terminated string and fills that address with the object's value
This function assumes that the caller has allocated enough space to hold a thirteen (13) character string.
So I coded:
void myClass::toStr(char* str) const
{
std::strcpy(str, myValue);
}
However str is receiving the address of myValue and not the string itself. I did quite a bit of searching here and couldn't find anything similiar. I CANNOT use dynamic memory in this exercise.

Here is your class used in a simple example (this is all I wanted you to post, but for some reason you couldn't do it).
#include <cstring>
#include <iostream>
class MyClass
{
char myValue[14];
public:
void toStr(char* str) const;
MyClass() { std::strcpy(myValue, "0123456789012"); }
};
void MyClass::toStr(char* str) const
{ std::strcpy(str, myValue); }
int main()
{
MyClass m;
char testString[100];
m.toStr(testString);
std::cout << testString;
}
This function works as expected. I see testString being assigned the myValue text. I added a constructor to MyClass to ensure it is the same as you described, namely that myValue has a 13 character string before the call to toStr.
Now take that example I posted, and either
1) Change whatever you need to change to duplicate your error -- comments can come later as to why what you did doesn't work, or
2) point out what you missed in your code that you see in the example above, thus fixing your error.
There is no plagiarism here, since I have no idea what your assignment is really supposed to be -- this is purely written given your description. See how easy it is just to provide a simple example?

In your assignment there is written that str can hold only 13 characters while myValue is defined as an array of 14 characters. So you should use std::strncpy instead of std::strcpyFor example
void myClass::toStr(char* str) const
{
std::strncpy(str, myValue, 13);
str[12] = '\0';
}
I think you get the weird result because myValue is not zero-terminated. If you are considering the both strings as some buffers of bytes then you should use function std::memcpy In this case the function will look as
void myClass::toStr(char* str) const
{
std::memcpy(str, myValue, 13);
}
I

Try this! You dont need to bother about myValue array size.
void myClass::toStr(char* pstr) const
{
std::string str(myValue);
pstr = new char[str.size()+1];
strcpy(pstr, str.c_str());
}

We obviously need more information on this. But what I understood, your calling code should be as below:
MyClass a;
char *astr = new char[15]; //Allocate enough space for astr to hold myValue
a.toStr(astr);
cout << astr;
delete astr;
Also, value should be assigned in constructor or any other setter as below:
strcpy(myValue,"Test String");
Edit: As explained in another answer by Vlad, strncpy should be better.
This function assumes that the caller has allocated enough space to
hold a thirteen (13) character string.
This means before calling your function, your string already allocated space (as I have done with new).
Looks like you mis-understood question.

Related

How does the '->' operator work and is it a good implementation to modify a large string?

I want to begin with saying that I have worked with pointers before and I assumed I understood how they worked. As in,
int x = 5;
int *y = &x;
*y = 3;
std::cout << x; // Would output 3
But then I wanted to make a method which modifies a rather large string and I believe therefore it would be better to pass a reference to the string in order to avoid passing the entire string back and fourth. So I pass my string to myFunc() and I do the same thing as I did with the numbers above. Which means I can modify *str as I do in the code below. But in order to use methods for String I need to use the -> operator.
#include <iostream>
#include <string>
int myFunc(std::string *str) { // Retrieve the address to which str will point to.
*str = "String from myFunc"; // This is how I would normally change the value of myString
str->replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
return 0;
}
int main() {
std::string myString << "String from main";
myFunc(&myString); // Pass address of myString to myFunc()
}
My questions are:
Since str in myFunc is an address, why can an address use an
operator such as -> and how does it work? Is it as simple as the
object at the address str's method is used? str->replace(); // str->myString.replace()?
Is this a good implementation of modifying a large string or would it better to pass the string to the method and return the string when its modified??
ptr->x is identical to (*ptr).x unless -> is overridden for a type you're dereferencing. On normal pointers, that works as you'd expect it to.
As for implementation, profile it when you implement it. You can't know what compiler will do with this once you turn optimizations on. For example, if given function gets inlined, you won't even have any extra indirection in the first place and it won't matter which way you do it. As long as you don't allocate a new string, differences should generally be negligible.
str is a pointer to std::string object. The arrow operator, ->, is used to dereference the pointer and then access its member. Alternatively, you can also write (*str).replace(0,1,"s"); here, * dereferences the pointer and then . access the member function replace().
Pointers are often confusing; it is better to use references when possible.
void myFunc(std::string &str) { // Retrieve the address to which str will point to.
str = "String from myFunc"; // This is how I would normally change the value of myString
str.replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
}
int main() {
std::string myString = "String from main";
myFunc(myString); // Pass address of myString to myFunc()
}
Is this a good implementation of modifying a large string or would it better to pass the string to the method and return the string when its modified??
If you don't want to change the original string then create a new string and return it.
If it's ok for your application to modify the original string then do it. Also you can return a reference to a modified string if you need to chain function calls.
std::string& myFunc(std::string &str) { // Retrieve the address to which str will point to.
str = "String from myFunc"; // This is how I would normally change the value of myString
return str.replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
}

how do functions read pointers?

im new to c++. I made this simple program using classes which does simple stuff like change instances of objects and copying objects.
But I'm confused how functions like std::strlen() read pointers.As far as i know pointer is just an address to another variable.If i pass in derefrenced pointer in std::strlen(*c) i get some error saying compiler cannot convert pointer to char, but if i pass in raw pointer like std::strlen(c)
the code compiles fine and gives the desired output.Why is that?std::strlen() should know the exact string to calculate length right?how does passing pointer help?
Same goes with strcpy_s() if i pass in derefrenced pointers like this strcpy_s(*str,strlen(str)+1,*c) it wont work but if i pass in pointers like strcpy_s(str,strlen(str) + 1, c), it works perfectly.
Please help me out as I'm really confused.Thanks
here is the code-
#include <iostream>
#include <cstring>
#include <vector>
class mystring
{
char* str;
public:
//constructors
mystring();
mystring(const char* c);
mystring(const mystring& original);
~mystring();
//methods
void display() const;
void length() const;
void display_vector(const std::vector <mystring>& thing) const;
//operator overloading
mystring& operator= (const mystring& source);
};
mystring::mystring() //default constructor
:str(nullptr)
{
str = new char[1];
*str = '\0';
}
mystring::mystring(const char* c) //overloded constructor (char *c)
{
str = new char[std::strlen(c) + 1];
strcpy_s(str, std::strlen(c) + 1, c);
}
mystring::mystring(const mystring& original) // copy constructor
{
str = new char[strlen(original.str) + 1];
strcpy_s(str, strlen(original.str) + 1, original.str);
}
mystring::~mystring() //destructor
{
delete[] str;
}
void mystring::display() const // display method for mystring
{
std::cout << str << std::endl;
}
void mystring::length() const // length fuc
{
std::cout << strlen(str) << std::endl;
}
mystring& mystring::operator= (const mystring& source) //= operator overload
{
delete[] this->str;
this->str = new char[std::strlen(source.str) + 1];
strcpy_s(this->str, std::strlen(source.str) + 1, source.str);
return *this;
}
int main()
{
mystring v{ "v_and_jackie" };
v.display();
mystring jackie;
jackie = v;
jackie.display();
std::vector <mystring> thing;
thing.push_back("wake up");
thing.push_back("samurai");
for (const auto i : thing)
i.display();
}
Thanks again.
std::strlen receives as an argument a pointer to the beginning of the string:
std::size_t strlen( const char* str );
Returns the length of the given byte string, that is, the number of characters in a character array whose first element is pointed to by str up to and not including the first null character. The behavior is undefined if there is no null character in the character array pointed to by str.
https://en.cppreference.com/w/cpp/string/byte/strlen
As far as i know pointer is just an address to another variable
Correct.
If i pass in derefrenced pointer in std::strlen(*c) i get some error saying compiler cannot convert pointer to char
Read the message again. It should say that it cannot convert a char to a pointer-to-char.
but if i pass in raw pointer like std::strlen(c) the code compiles fine and gives the desired output.Why is that?
This is because of type safety that C++ language has. std::strlen accepts an argument that is a pointer to char. If you pass the function something that isn't a pointer to char nor convertible to such pointer, like a char object for example, then the program is ill-formed, and you'll get an informative message pointing out your mistake.
When you indirect through a pointer, what you get back is not a pointer of same type. Instead, the value that you get back is the pointed object, which always has a different type. In case of pointer to char, the pointed object is a char.
how does passing pointer help?
Passing an argument of correct type into a function call helps.
I'm gonna try and explain the reasoning behind why you have to pass a char:
Back in the days memory was very valuable. And instead of using memory for an Integer to keep track of the string length a convention was used: End the string with a null-byte (zero).
Every character is saved in the ASCII format (lookup ASCII table).
Because every string is null-terminated "Hello" would look like {72, 101, 108, 108, 111, 0} in memory.
So to get the length of the string you need a pointer to the first character, then advance forwards until you get to the null-byte. By counting how many bytes you advanced in memory you know the amount of characters contained in the string.
This is exactly what strlen does.
By dereferencing the pointer to the first character you get the first character.
This way strlen would not know where the first character came from in memory and cannot read the next character.
So you can think of dereferencing the pointer to a string (the first char) as loosing all information about that string except what the first character is.
Hopefully this was understandable.

How can I convert a string of characters to an object type?

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.

C++ weird behaviour with stack variables and functions

I've got a String class with a char* buffer and a unsigned int length.
The string class has two constructors:
String(const char* str);
String(const String& other);
and a destructor
~String()
which deletes the char array with delete[] buffer;.
Both constructors create a new buffer array buffer = new char[size]; and fill it with the correct data from either the const char* string or the const String& other. The string buffer is null-terminated.
In my main function I've got the following code:
int main() {
String a("Hello");
a = a.Replace('l', 'p');
printf("%s\n", a.char_ptr());
}
I would expect it to print Heppo to the console. The replace function takes two characters where all occurrences of the first one are replaced by the second one. It returns an entirely new String:
String String::Replace(const char& a, const char& b) {
const char* buf = ...;
// Do the replacement and store the result in buf
String s(buf);
delete[] buf;
return s;
}
From my understanding, the compiler will return a copy of the local variable s. Because of that, the a variable in main() should be a perfectly legitimate String. But the output to the console looks like ¦¦¦¦¦¦¦¦¦¦, which looks like uninitialized memory.
Even weirder, when i change my main method to:
int main() {
String a("Hello");
String b = a.Replace('l', 'p');
printf("%s\n", b.char_ptr());
}
I see the expected output. After a lot of reading I could not figure out the solution, as this is problem is really hard to describe in a google/stackoverflow search.
the main problem is violation of the rule of big 3. since you have a none trivial destructur, you must also define a copy constructor and an assignment operator.
you may consider the copy-swap idiom in implementing the above functions.
Not definining either of the two in presence of a none-trivial destructor, leads to resource(memory in this sample) leak.

char* to char[]

I have char* which is of fixed (known) width but is not null terminated.
I want to pass it into LOG4CPLUS_ERROR("Bad string " << char_pointer); but as its not null terminated it will print it all.
Any suggestions of some light weight way of getting "(char[length])*char_pointer" without performing a copy?
No, you'll have to deep-copy and null-terminate it. That code expects a null-terminated string and it means a contiguous block of characters ending with a null terminator.
If your goal is to print such a string, you could:
Store the last byte.
Replace it with \0.
Print the string.
Print the stored byte.
Put the stored byte back into the last position of the string.
Wrap all this in a function.
Real iostreams
When you're writing to a real iostream, then you can just use ostream.write() which takes a char* and a size for how many bytes to write -- no null termination necessary. (In fact, any null characters in the string would be written to the ostream, and would not be used to determine the size.)
Logging libraries
In some logging libraries, the stream that you write to is not a real iostream. This is the case in Log4CPP.
However, in Log4CPlus which is what it appears matt is using, the object that you're writing to is a std::basic_ostringstream<tchar> (see loggingmacros.h and streams.h for the definition, since none of this is obvious from the documentation). There's just one problem: in the macro LOG4CPLUS_ERROR, the first << is already built into the macro, so he won't be able to call LOG4CPLUS_ERROR(.write(char_pointer,length)) or anything like that. Unfortunately, I don't see an easy way around this without deconstructing the LOG4CPLUS_ERROR error macro and getting into the internals of Log4CPlus
Solution
I'm not sure why you're trying to avoid copying the string at this point, since you can see that there's a lot of copying going on inside the logging library. Any attempt to avoid that extra string copy is probably unwarranted optimization.
I'm going to assume that it's an issue of code cleanliness, and maybe an issue of making sure the copy happens inside the LOG4CPLUS_ERROR macro, as opposed to outside it. In that case, just use:
LOG4CPLUS_ERROR("Bad string " << std::string(char_pointer, length));
We're getting hung up on the semantics of conversion between char* and char[]. Take a step back, what are you trying to do? If this is a simple case of on an error condition, streaming out the content of a structure to a stream, why not do it properly?
e.g.
struct foo
{
char a1[10];
char a2[10];
char a3[10];
char a4[10];
};
// free function to stream the above structure properly..
std::ostream operator<<(std::ostream& str, foo const& st)
{
str << "foo::a1[";
std::copy(st.a1, st.a1 + sizeof(st.a1), std::ostream_iterator<char>(str));
str << "]\n";
str << "foo::a2[";
std::copy(st.a2, st.a2 + sizeof(st.a2), std::ostream_iterator<char>(str));
str << "]\n";
:
return str;
}
Now you can simply stream out an instance of foo and don't have to worry about null terminated string etc.!
I keep a string reference class in my toolkit just for these type of situations. Here is a greatly abbreviated version of that class. I trimmed away anything that is not relevant to this particular problem:
#include <iostream>
class stringref {
public:
stringref(const char* ptr, unsigned len) : ptr(ptr), len(len) {}
unsigned length() { return len; }
const char* data() { return ptr; }
private:
const char* ptr;
unsigned len;
};
std::ostream& operator<< (std::ostream& os, stringref sr) {
const char* data = sr.data();
for (unsigned len = sr.length(); len--; )
os << *data++;
return os;
}
using namespace std;
int main (int argc, const char * argv[])
{
cout << "string: " << stringref("test", 4) << endl;
}
or, in your case:
LOG4CPLUS_ERROR("Bad string " << stringref(char_pointer, length));
should work.
The idea of a string reference class is to keep enough information about a string (a size and a pointer) to refer to any block of memory which represents a string. It relies on you to make sure that the underlying string data is valid throughout the lifetime of a stringref object. This way you can pass around and process string information with a minimum of overhead.
When you know it is of fixed length: Why not simply add one more charakter to the size of the array? Then you can easily fill this last char with \0 terminating character and all will be fine
No, you'll have to copy it. There is no proper conversion in the language that you can use to get the array type out of it.
It seems very odd that you want to do this, or that you have a non-terminated C-style string in the first place.
Why are you not using std::string?