how do functions read pointers? - c++

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.

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 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.

Copy string value into address

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.

Overloading operator +. String class

Im writing string class by myself. And I overloaded + operator. Its works fine, but then I tried to eguate cstr = str +pop , its did nothing. `You could see my error in main() function. Complier doesnt give any mistake.
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
class S {
public:
S();
S(const char *str);
S(const S &s);
~S() { delete []string;}
S &operator =(const S &s);
int lenght() const {return l ;}
char* strS() const {return string;}
friend ostream &operator <<(ostream &, const S &first) {cout<<first.string;}
friend S operator+ (const S& first, const S& second);
private:
char *string;
int l;
};
int main(){
S pop("Q6");
S str("M5");
S cstr = str +pop; // works correct
cout<<str;
str = str + pop;
cout<<str ; // doesnt work, it doesnt write in terminal
return 0;
}
S::S()
{
l = 0;
string = new char[1];
string[0]='\0';
}
S::S(const char *str)
{
l = strlen(str);
string = new char[l+1];
memcpy(string, str, l+1);
}
S::S(const S &s)
{
l = s.l;
string = new char[l+1];
memcpy(string,s.string,l+1);
}
S &S::operator=(const S &s)
{
if (this != &s)
{
delete []string;
string = new char[s.l+1];
memcpy(string,s.string,s.l+1);
return *this;
}
return *this;
}
S operator +(const S& first, const S& second)
{
S temp;
temp.string = strcat(first.strS(),second.strS());
temp.l = first.lenght() + second.lenght();
return temp;
}
I`m looking forward to your help.
Your operator has bugs!
S temp;
//^^^^ has only one byte buffer!!!
temp.string = strcat(first.strS(),second.strS());
// 1 byte ^^^^^ strcat appends second.strS to first.strS
You should re-allocate memory for temp:
S temp;
temp.l = first.lenght() + second.lenght();
delete [] temp.string; // !!!! -
temp.string = new char[temp.l + 1]; // !!!!
// you should have another c-tor which can allocate memory!!!
// like: S(unsigned length, unsigned char c = '\0')
strcpy(temp.string, first.strS());
strcat(temp.string, second.strS());
Besides this obvious bug - you should also take care of exceptions - std::bad_alloc for example. Look at copy-and-swap idiom for better approach for this task.
From the manpage for strcat:
The strcat() and strncat() functions append a copy of the null-terminated
string s2 to the end of the null-terminated string s1, then add a termi-
nating `\0'. The string s1 must have sufficient space to hold the
result.
You're using it as if it allocates room for a new char array, then fills it. But, it doesn't do that.
The problem is that your operator+ doesn't allocate any memory for the combined string. Nor does it copy the string to right place (it copies the string to first, not to temp). There's no easy fix with the class design you have.
The problem is with your implementation of operator+. strcat() appends the string ponted by the second argument to the string pointed by the first argument. The return value is the first argument. Therefore on return from operator+ the resulting S and the first S argument will be pointing to the same buffer. Which will later be deleted twice...
Check the description of strcat. It appends the second argument to
the first, supposing both are null terminated strings, and returns the
first argument. In your case:
it appends to the string member of first, although there isn't
enoguh memory for it (undefined behavior), and
it sets the string pointer in temp to point to the same memory as
that in first; the first one to be destructed leaves the other
pointing to deleted memory, and the memory allocated in the default
constructor of temp is leaked.
Also, you never terminate your strings with '\0', so strcat may do
just about anything.
A better solution would be to implement += first, and define + in
terms of it. += would have to grow the memory it has, and append the
text from the second string to it.
And while I'm at it: your operator= doesn't work either. It will
leave the object in a state where it cannot be destructed if the new
fails (throwing std::bad_alloc). You must ensure that all operations
that can fail occur before the delete. (The fact that you need to
test for self assignment is a warning sign. It's very rare for this
test to be necessary in a correctly written assignment operator.) In
this case, the swap idiom would probably be your best bet: copy
construct a new S in a local variable, then swap their members.