I have a program with one structnamed sample, it contains 2 int members and one char *. when creating 2 objects called a and b, I try assign a new dynamic string to a with the pointer and then copy all the values to b. so b = a. But later on when try to make changes to a like this : a.ptr[1] = 'X'; the pointer in b also changes. I want to know why, and how can I solve this.
struct Sample{
int one;
int two;
char* sPtr = nullptr;
};
int _tmain(int argc, _TCHAR* argv[])
{
Sample a;
Sample b;
char *s = "Hello, World";
a.sPtr = new char[strlen(s) + 1];
strcpy_s(a.sPtr, strlen(s) + 1, s);
a.one = 1;
a.two = 2;
b.one = b.two = 9999;
b = a;
cout << "After assigning a to b:" << endl;
cout << "b=(" << b.one << "," << b.two << "," << b.sPtr << ")" << endl << endl;
a.sPtr[1] = 'X' ;
cout << "After changing sPtr[1] with 'x', b also changed value : " << endl;
cout << "a=(" << a.one << "," << a.two << "," << a.sPtr << ")" << endl;
cout << "b=(" << b.one << "," << b.two << "," << b.sPtr << ")" << endl;
cout << endl << "testing adresses for a and b: " << &a.sPtr << " & b is: " << &b.sPtr << endl;
return 0;
}
Your struct contains a char*. When you assign all values in a to b, the pointer is also copied.
This means that a and b now point to the same char array. Therefore changing a value in this char array changes it for both structs.
If you do not want this, make a new char array for b and use strcpy.
You are copying the pointer not the value. To solve this you could override your assignment operator in the structure:
struct Sample{
int one;
int two;
char* sPtr = nullptr;
Sample& operator=(const Sample& inputSample)
{
one = inputSample.one;
two = inputSample.two;
sPtr = new char[strlen(inputSample.sPtr) + 1];
strcpy (sPtr, inputSample.sPtr);
return *this;
}
};
Related
I am relatively new to C++. I am hoping to get assistance creating an overload operator that will permit me to use a literal string with a class I am writing. This project is for learning.
I created a custom Date class (and have not worried about the actual logic in the class; I'm just trying to get the interface working and to understand where my roadblock is.
It may not look like it, but I have put in a lot of time on this, so an explanation designed for a beginning c++ progammer would be very helpful to me and anyone who follows in my footsteps.
Basically, I'd like to be able to do this with my class:
Date dt(5,6,92);//create class object
int myint;
myint = dt;//this works
string mystr;
mystr = dt("mm/dd/yy");//this does not compile
Thanks in advance. (A compilable test program shown below)
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
class Date
{
int mo, da, yr;
public:
Date(int m, int d, int y)
{
cout << "Constructor int m, int d, int y called " << endl;
mo = m; da = d; yr = y;
}
string getdatestr(const char *s = "") {//user sends in format "d2/" "mm/dd/yy" etc
cout << "getdatestr const char *s called mo = " << mo << " da = " << da << "yr = " << yr << endl;
return to_string(mo) + "/" + to_string(da) + "/" + to_string(yr);
}
int getdate(){
cout << "getdate int t called" << endl;
string tag;
tag = to_string(yr) + to_string(mo) + to_string(da);
return stoi(tag);
}
string getdate(string &str){
cout << "getdate with string as ref" << endl;
return "5/5/55";
}
int getdate(int &myint){
cout << "getdate with int as ref" << endl;
return 12345;
}
void setdate(string dt){
cout << "setdate string dt called " << dt << endl;
mo = 1;
da = 2;
yr = 2020;
}
void setdate(int intdte){
cout << "setdate int to " << intdte << endl;
mo = 99;//any int for now
da = 98;
yr = 1997;
}
void setdate(const char *dte){
cout << "setdate char* dte = " << dte << endl;
mo = 94;
da = 95;
yr = 1996;
}
~Date(){
cout << "destructor called" << endl;
}
//below code permits this in main(): myint = dt;
operator int() {
cout << "operator int()" << endl;
string tag;
tag = to_string(yr) + to_string(mo) + to_string(da);
return stoi(tag);
}
//end section to permit: myint = dt;
//what do I need so I can do this: mystr = dt("mm/dd/yy");, nothing below worked; I tried many more iterations
//than what are shown here
/*
operator string() {
cout << "operator string char" << endl;
return "hello world";
}
string operator = (string &rhs){
cout << "string" << endl;
return "return a string";
}
operator = (const string &rhs){
cout << "will this work?" << endl;
return *this;
}
char& operator = (char(&)[9]){
cout << "whoa, it worked" << endl;
//return "got it";
}
operator = (char*){
cout << "try again" << endl;
}
string operator const char(&)[9] {
cout << "one more time" << endl;
string *ptr;
ptr = "one more time";
return ptr;
}
//end nothing worked to permit me to do this mystr = dte("mm/dd/yy"); section
*/
};//end of class
int main()
{
//create a Date class object dt
Date dt(5, 6, 92);
dt.setdate("02/15/22");
cout << endl;
cout << "next two mystr messages return null because I " << endl;
cout << "can't seem to write a valid overload operator for a literal string" << endl;
string mystr;
//mystr = dt("mm/dd/yy");//does not compile (no match for call to '(Date) (const char [9])'
cout << "mystr using dt(str) = " << mystr << endl;
string myconv = "mm/dd/yy";
//mystr = dt(myconv);//does not compile (no match for call to '(Date) (std::__cxx11::string&)'
cout << "mystr using dt(mm//dd//yy) = " << mystr << endl;
cout << endl;
//this section works
//can I assign dt to an integer (as #days from a reference date)
cout << "this section seems to work" << endl;
int myint;
cout << "myint = dt;" << endl;
myint = dt;//does not compile
cout << "myint (using = dt;) = " << myint << endl;
cout << endl;
system("pause");
}
The test method on the following class does not have the effect I would expect it to. I have a suspicion it is something to do with the fact that the invocation of emplace_back somehow invalidates the reference obtained via the subscript.
Either way I would expect the second print in test to result in
v[0] = 1
however both result in
v[0] = 5
suggesting that the assignment does not take place.
class FooBar {
vector<size_t> v;
public:
size_t add(size_t x) {
cout << "add(" << x << ")" << endl;
size_t K(v.size());
v.emplace_back(x);
return K;
}
void test(size_t idx) {
cout << "v[" << idx << "] = " << v[idx] << endl;
v[idx] = add(0);
cout << "v[" << idx << "] = " << v[idx]<< endl;
}
};
int main(int argc, char* argv[])
{
FooBar f;
f.add(5);
f.test(0);
}
I know that I can get around the problem by creating a temporary to store the result of add and then perform the assignment but I am interested as to why I cannot use just a straight assignment and why I do not get any kind of error when attempting to perform this.
Compiled and tested with MSVC (Visual Studio 2015).
The line
v[idx] = add(0);
is cause for undefined behavior. You are modifying the contents of v in add while assuming that v[idx] will be valid.
For predictable behavior, you can use:
void test(size_t idx) {
cout << "v[" << idx << "] = " << v[idx] << endl;
size_t val = add(0);
v[idx] = val;
cout << "v[" << idx << "] = " << v[idx]<< endl;
}
Take a look at the initialization list of the derived class in the code below.
class city {
private:
int id;
int x;
int y;
public:
int getID(){return id;};
int getX(){return x;};
int getY(){return y;};
city(){
id =0; x=0; y=0;
}
city(int idx, int xx, int yx){
id = idx;
x = xx;
y = yx;
}
city(city* cityobj){
id = cityobj->id;
x = cityobj->x;
y = cityobj->y;
}
};
class city_detail : public city{
private:
city* neighbor;
public:
city_detail (city& neighborX, city& cityobj): city(cityobj){ // What???
/* ^ city(cityobj) and city(&cityobj) both work here */
neighbor = &neighborX;
}
city* getN(){return neighbor;}
};
int main(int argc, char*argv[]){
city LA(42, 1, 2);
city PDX(7, 3, 4);
city_detail LA_Detail(PDX, LA);
cout << "LA_Detail.ID: " << LA_Detail.getID() << endl; // works both ways
cout << "LA_Detail.x: " << LA_Detail.getX() << endl; // works both ways
cout << "LA_Detail.y: " << LA_Detail.getY() << endl; // works both ways
cout << "LA_Detail.NN: " << LA_Detail.getN() << endl; // returns address as it should
city * LA_neighbor = LA_Detail.getN();
cout << "LA_neighbor.ID: " << LA_neighbor->getID() << endl; // address is indeed valid
cout << "LA_neighbor.x: " << LA_neighbor->getX() << endl; // address is indeed valid
cout << "LA_neighbor.y: " << LA_neighbor->getY() << endl; // address is indeed valid
return 0;
}
Why is it that both ...: city(&cityobj) AND ...: city(cityobj) work here?
I would think that I cannot do the latter, ...: city(cityobj), and that I must pass in an address to cityobj since the base class' constructor takes in a pointer.
Why am I not getting some compile error such as:
cannot convert type city to city * ?
Clearly, I am not able to do this in other places, such as:
void getID(city* aCity){
cout << "aCityID: " << aCity->getID() << endl;
cout << "aCityX: " << aCity->getX() << endl;
}
void wrapper(city &aCity){
getID(&aCity); // I must pass in the address here, else I get an error
}
city Greenway;
wrapper(Greenway);
The reason it works is that when you call city(cityobj) it uses the compiler's implicitly defined copy constructor, and when you call city(&cityobj) it uses the converting constructor you defined yourself: city(city* cityobj).
You didn't mean to say neighbor(&cityobj) did you?
I have implemented the swap via function for two numbers and this works well. However, I am now trying to swap two character strings but i receive the names in the same order. Would anybody know where I am going wrong or what I could do to have the names change positions? here is an example of the code below:
#include "stdafx.h"
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
void swapages (int &age1, int &age2);
void swapname(char *person1, char *person2);
int _tmain(int argc, _TCHAR*argv[])
{
char person1[] = "Alex";
char person2[] = "Toby";
int age1 = 22;
int age2 = 27;
cout << endl << "Person1 is called " << person1;
cout << " and is " << age1 << " years old." << endl;
cout << "Person2 is called " << person2;
cout << " and is " << age2 << " years old." << endl;
swapname(person1,person2);
swapages(age1,age2);
cout << endl << "Swap names..." << endl;
cout << endl << "Person1 is now called " << person1;
cout << " and is " << age1 << " years old." << endl;
cout << "Person2 is now called " << person2;
cout << " and is " << age2 << " years old." << endl;
system("pause");
return 0;
}
void swapages(int &age1, int &age2)
{
int tmp = age2;
age2 = age1;
age1 = tmp;
}
void swapname(char *person1, char *person2)
{
char* temp = person2;
person2 = person1;
person1 = temp;
}
You have tagged this as C++, and you are including the <string> header already, so why not use std:string instead of all those pointers and arrays?
void swapname(string &person1, string &person2)
{
string temp(person2);
person2 = person1;
person1 = temp;
}
int _tmain(int argc, _TCHAR*argv[])
{
string person1 = "Alex";
string person2 = "Toby";
swapname(person1, person2);
}
The problem is that you are trying to swap pointers that are local variables of the function while you need to swap strings. So you need to copy one string into another string. Moreover the strings can have different lengths so the exact swap will be impossible. It could be done without problems if the parameters of the function would be arrays (references to arrays) of the same size. For example
void swap_name( char ( &lhs )[5], char ( &rhs )[5] )
{
char tmp[5];
std::strcpy( tmp, lhs );
std::strcpy( lhs, rhs );
std::strcpy( rhs, tmp );
}
You need to make minor changes to get it to work the way you want it to work.
void swapname(char **person1, char **person2);
.
.
char *person1 = "Alex";
char *person2 = "Toby";
.
.
swapname(&person1, &person2);
.
.
and
void swapname(char **person1, char **person2)
{
char* temp = *person2;
*person2 = *person1;
*person1 = temp;
}
In your code, person1 and person2 are defined as 2 char arrays not char pointer variables, you can not swap them, if you pass the 2 arrays into the swapname function which takes 2 pointers as parameters, it should not even compile.
Consider the following, you have two sets of arrays - one of which has some set of integers stored with values, you can put these in an array and cout the value in the array with ease. However when you have an array with empty integers within it - it does not seem to be able to "store" the values to the integer value - why?
Here is an example:
int empty1;
int empty2;
int contain1 = 100;
int contain2 = 200;
int container [2] = { contain1, contain2 };
int empty_container [2] = { empty1, empty2 };
int i = 0;
while ( i != 2 ) {
empty_container[i] = i;
cout << endl << "empty_container[i]: " << empty_container[i] << endl
<< "empty1: " << empty1 << endl << "empty2: " << empty2 << endl;
cout << "i: " << i << endl;
cout << "container[i]: " << container[i] << endl;
cout << "contain1: " << contain1 << endl;
cout << "contain2: " << contain2 << endl;
i++;
}
Output:
empty_container[i]: 0
empty1: 4197341
empty2: 0
i: 0
container[i]: 100
contain1: 100
contain2: 200
empty_container[i]: 1
empty1: 4197341
empty2: 0
i: 1
container[i]: 200
contain1: 100
contain2: 200
Notice how empty1 all of a sudden has the value "4197341" while empty2 is 0, what is going on here?
UPD(from comments):
I mean like declaring an integer before and then set it through an array - is this not possible with C++?
Since you have never initialized or assign values to empty1 and empty2. empty1 and empty2 do not have global or static storage, they will not be initialized implicitly. Both of them contain garbage values.
You have undefined behavior. You can see that this compiler gives you different results on values of empty1 and empty2: Local variable not initialized Demo
Always remember to initialize variables before using it.
EDIT:
I mean like declaring an integer before and then set it through an array - is this not possible with C++?
IMHO, you cannot do that. You can initialize array elements with given initialized variables. However, what you did:
int empty_container [2] = { empty1, empty2 };
will not assign values to empty1 and empty2 with values in that array since the array itself is not initialized.
However, you may try the following:
empty_container[2] = {10}; //initialize array at first
empty1 = empty_container[0];
empty2 = empty_container[1]; //this will give you empty1 10 and empty2 0
See another live demo here: Array and Variable initialization demo
In here
...
int i = 0;
while ( i != 2 ) {
empty_container[i] = i; // <- HERE
cout << endl << "empty_container[i]: " << empty_container[i] << endl
...
you must have assumed that doing empty_container[i] = i would also affect empty1 or empty2. It seems that your thinking it wrong.
In C++, doing int empty_container [2] = { empty1, empty2 }; copies the values of empty1 and empty2 into the respective elements of empty_container. This means that even if they have the same values, they do not refer to the same memory location.
In order to also modify empty1 and empty2 when you modify empty_container, you must modify empty_container and change it to an array of pointers, or some similar methods to refer to some object.
The code:
#include <iostream>
using namespace std;
int main() {
int empty1;
int empty2;
int contain1 = 100;
int contain2 = 200;
int container [2] = { contain1, contain2 };
int* empty_container [2] = { &empty1, &empty2 };
// ^ Notice this
int i = 0;
while ( i != 2 ) {
*(empty_container[i]) = i;
// ^ Also this
cout << endl << "empty_container[i]: " << empty_container[i] << endl
<< "empty1: " << empty1 << endl << "empty2: " << empty2 << endl;
cout << "i: " << i << endl;
cout << "container[i]: " << container[i] << endl;
cout << "contain1: " << contain1 << endl;
cout << "contain2: " << contain2 << endl;
i++;
}
}
Notice that empty1 becomes 0 in the first iteration, and empty2 becomes 1 in the second iteration.