I am confused about this library code..
what is the purpose of writing pointer in attributes name?
Like string *name;
this is the code:
#include <iostream>
using namespace std;
class stringlist
{
private:
int numstrings;
string *strings;
public:
stringlist() : numstrings(0), strings(NULL)
{}
// copy constructor
stringlist(const stringlist &other) :
numstrings(other.numstrings),
strings(new string[other.numstrings]) {
for (int i=0; i<numstrings; i++) {
strings[i] = other.strings[i];
}
}
// destructor
~stringlist() {
if (numstrings > 0) delete [] strings;
}
void printStrings();
const string& getString(int num);
void setString(int num,
const char *astring);
void setString(int num,
const string &astring);
int getNumstrings() {
return numstrings;
}
void setNumstrings(int num);
void swapStrings(stringlist &other) ;
// overloaded operators
stringlist& operator =
(const stringlist &other) {
stringlist temp(other);
swapStrings(temp);
return *this;
}
};
Can anyone please explain what is the purpose of
using string *strings
instead of string strings?
Thanks all!
string *strings;
declares a pointer to the first element of an array of strings. Because of C/C++ array/pointer semantics, you can treat this as an array of strings, e.g. index it as strings[n] to get the nth element.
string strings;
would just be one string. Since the class is for holding a list of strings, declaring just one string would not be sufficient.
In the code you gave, *strings is used for a dynamic array.
You can see that it's allocated with strings(new string[other.numstrings]) and the destructor deletes it if it's pointing to something.
More on dynamic arrays:
- http://www.cplusplus.com/doc/tutorial/dynamic/
Static array vs. dynamic array in C++
Related
I am working on some pointer practice in my C++ class and have gotten stuck working on problem, say I have a class like this :
class foo
{
public:
foo(char *inputWord = ""); // Default parameter constructor
private:
char * word;
int wordSize; // length of word
};
and in main I have :
int main()
{
foo baz("t");
foo bar("test");
return 0;
}
How would I make an implementation for this constructor?
So far I know that to initialize wordSize I could just do :
foo::foo()
{
wordSize = strlen(inputWord);
}
But I don't understand how to initialize the char *word.
I've tried the following:
strcpy(word,strlen);
for(int i =0; i< wordSize; i++)
word[i] = inputWord[i];
int count = 0;
while(count < wordSize+1)
{
inputWord = word;
inputWord++;
}
None of the above methods work. I even tried using memcpy() and memmove() but I just got stuck.
Has anyone dealt with this before and could point me in the right direction?
You can simply use strcpy just after having allocate memory:
Foo(char *inputWord) {
if (inputWord==nullptr) { // manage null pointer
wordSize=0;
word=nullptr;
return;
}
wordSize = strlen(inputWord); // store string length
word = new char[wordSize+1]; // allocate enough memory to store the original C-style string
strcpy(word,inputWord); // copy the original into destination
}
This is C-style, but you'd better use strings in C++:
class Foo {
private:
string word;
public:
Foo(const string &input) : word(input) {} // initialize word with inputWord (let C++ string type do all the tricky parts)
};
C++ string type is able to manage correctly (de)allocations, length, etc.
I just started learning about operator overloading and was just playing around with code to learn how it works. So, I wrote a code that adds two characters. Ex: '#' + '%' = 'H' because of ASCII value addition.
Here is my code:
#include <iostream>
using namespace std;
class Strings {
//everything is public
public:
char str;
//empty constructor
Strings();
Strings(char);
//operator takes in an object of Strings
Strings operator+(Strings);
};
Strings::Strings()
{}
//constructor
Strings::Strings(char a) {
str = a;
}
//aso is "another string object"
//makes new empty object "brandNew"
//brandNew is the two characters added together
//returns object brandNew
Strings Strings::operator+(Strings aso) {
Strings brandNew;
brandNew.str = str + aso.str;
return brandNew;
}
int main() {
Strings a('#');
Strings b('%');
Strings c;
//now, we can use + operator to add characters
c = a + b;
cout << c.str << endl;
return 0;
}
What if I wanted to add two strings? If I make the input
Strings a("###");
Strings b("%%%");
And I want the output to be
HHH
How would I alter my code to add the two strings? I started with changing all of the char type declarations into string. I'm thinking I would have to make a for loop inside the operator function to iterate through each character of both inputs while adding them. But, I'm confused on the syntax for it and also confused on how to implement that. Any help and explanation would be appreciated!
I will give you some help declaring the class.
class Strings {
private:
char* str;
unsigned int length;
unsigned int size;
public:
//constructor
Strings();
~Strings();
Strings(const char*);
Strings(const Strings&);
//operator
Strings operator+(const Strings&);
Strings operator+(const char*);
Strings operator=(const Strings&);
Strings operator=(const char*);
Strings operator+=(const Strings&);
Strings operator+=(const char*);
///Accessors
const char* GetStr()const;
unsigned int GetLength()const;
unsigned int GetSize()const;
};
I have a class with member of dynamic array (I posted my code in pastebin) I wonder if my both classes are correct and if there is anything wrong with them? Also how I need to write (41 line) a function that sets class Student to StudentsDynamicArray?
Here is my array class
class StudentsDynamicArray{
private:
Student *Stud;// students dynamic array
int n; // current size of array
int nmax; // max size of array
public:
StudentsDynamicArray():n(0), Stud(NULL), nmax(0){}
StudentsDynamicArray(int n):
n(n){}
~StudentsDynamicArray(); // destructor
void SetStud(Student S){Stud[n++] = S;} // I get error when I try to set String or Int. //How I need to change this?
Student GetStud(int i){return Stud[i];}
void IncreaseSize(int ns);
};
//Function which change size of array
void Student::ChangeSize(int kiek){
if(kiek > nmax){
int *SNEW = new int[kiek];
for(int i=0; i<n; i++)
SNEW[i] = mark[i];
delete [] mark;
mark = SNEW;
nmax = kiek;
}
else if(kiek < nmax){
int *SNEW = new int[kiek];
for(int i=0; i<n; i++)
SNEW[i] = mark[i];
delete [] mark;
mark = SNEW;
n = nmax = kiek;
}
}
In Student class you have
int *mark
this is indication that you must apply rule of three: copy constructor, assignment operator and destructor. First two should make a copy of dynamic array, and destructor should free memory. You have only destructor properly implemented. The same applies to StudentsDynamicArray class.
as for:
void SetStud(Student S){Stud[n++] = S;}
from your code it looks like you have not called IncreaseSize initially, and Stud is possibly NULL once you call SetStud. You can fix it by calling it in constructor:
StudentsDynamicArray():n(0), Stud(NULL), nmax(0){ IncreaseSize(10); }
also, all of the above would not be necessary if you would use std::vector, so if such low lever dynamic arrays are not your requirement then use std::vector. Then you would use rule of zero.
[edit]
Your copy constructor / assignment operators should like as follows:
Student (const Student& other) {
// here allocate this->mark to be the same size as in other
// copy values from other.mark to this->mark
// also copy other values from `other` to this
}
Student& operator= (const Student& other)
{
// here allocate this->mark to be the same size as in other
// copy values from other.mark to this->mark
// also copy other values from `other` to this
return *this;
}
As you can see they are "quite" similar. Wiki on rule of three is actually updated to C++11, where you can add move semantics which increase efficiency of copy by value operations (and actually are known as rule of five). If you are learning basics, you can stay with previous rules.
You could better use std::vector to wrap the students into a collection. This will dramatically increase performance, and will lead to less errors.
Below is the prototype of classes you can use.
class Student
{
private:
string mName;
unsigned int mAge;
public:
Student() : mName(""), mAge(0) {}
Student( string name, unsigned int age ) : mName(name), mAge(age) {}
string get_name() const;
void set_name( string name );
unsigned int get_age() const;
void set_age( unsigned int age );
};
class Students
{
private:
vector<Student> mCollection;
public:
Students() : mCollection() { }
Students( vector<Student> &input_collection ) : mCollection( input_collection ) { }
Students &add_student( Student &s );
Students &remove_student( Student &s );
Students &remove_student( string name );
Students &remove_student( size_t index );
Students &edit_student( size_t index, string new_name, unsigned int new_age );
};
Hope this helps.
I am practicing overloading operators in C++ right now and I have a problem.
I created String class, it has just to fields one is char array other is length.
I have a String "Alice has a cat" and when I call
cout<<moj[2];
I would like to get 'i', but now I am getting moj + 16u adress of moj + 2 sizeof(String)
When I call
cout<<(*moj)[2];
it works as it shoud but I would like to dereference it in overloaded operator definition. I tried many things but I can't find solution. Please correct me.
char & operator[](int el) {return napis[el];}
const char & operator[](int el) const {return napis[el];}
AND the whole code, the important things are down the page. It's compiling and working.
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstring>
using namespace std;
class String{
public:
//THIS IS UNIMPORTANT------------------------------------------------------------------------------
char* napis;
int dlugosc;
String(char* napis){
this->napis = new char[20];
//this->napis = napis;
memcpy(this->napis,napis,12);
this->dlugosc = this->length();
}
String(const String& obiekt){
int wrt = obiekt.dlugosc*sizeof(char);
//cout<<"before memcpy"<<endl;
this->napis = new char[wrt];
memcpy(this->napis,obiekt.napis,wrt);
//cout<<"after memcpy"<<endl;
this->dlugosc = wrt/sizeof(char);
}
~String(){
delete[] this->napis;
}
int length(){
int i = 0;
while(napis[i] != '\0'){
i++;
}
return i;
}
void show(){
cout<<napis<<" dlugosc = "<<dlugosc<<endl;
}
//THIS IS IMPORTANT
char & operator[](int el) {return napis[el];}
const char & operator[](int el) const {return napis[el];}
};
int main()
{
String* moj = new String("Alice has a cat");
cout<<(*moj)[2]; // IT WORKS BUI
// cout<<moj[2]; //I WOULD LIKE TO USE THIS ONE
return 0;
}
String* moj = new String("Alice has a cat");
cout<<(*moj)[2]; // IT WORKS BUI
// cout<<moj[2]; //I WOULD LIKE TO USE THIS ONE
That can't be done, the subscript operator in the later case is applied to a pointer. It is only possible to overload operators when at least one of the arguments is of user defined type (or a reference to it, but not a pointer); in this particular case the arguments are String* and 2, both fundamental types.
What you may do is drop the pointer altogether, I don't see why you need it:
String moj("Alice has a cat");
// cout<<(*moj)[2]; <-- now this doesn't work
cout<<moj[2]; // <-- but this does
String * means a pointer to a String, if you want to do anything with the String itself you have to dereference it with *moj. What you can do instead is this:
String moj = String("Alice has a cat"); // note lack of * and new
cout << moj[2];
Also note that anything you allocate with new needs to be deleted after:
String *x = new String("foo");
// code
delete x;
Sorry, new to C++, converting from C, and have struggled to find a good way to do this...
//Fragment follows
const char *List1[]={"Choice1", "Not a good choice", "choice3"}; //rom-able
const char *List2[]={"Hello", "Experts", "Can", "You", "Help?"};
class ListIF{
private:
int index;
char *list;
public:
void GetValString(char *tgt,int len);//get parameter value as string max len chars
void SetIndex(int n){index = n;};
int GetIndex(void){return index;};
};
//end Fragment
The problem is how to write the constructor so that I can "encapsulate" the lists inside the class, without getting heap bloat (embedded target). And then how to write the gettor so that we can see list[index] within the class.
I am going daft trying to do something that seems obvious, so I am missing something?
In C++, prefer using std::string over const char*. It will solve most of your problems you face with const char*.
For an array of strings, use std::vector<std::string>. It will solve most of your problems you face with const char *[].
You can even initialize the std::vector with multiple strings as,
std::vector<std::string> List1(adder<std::string>("Choice1")("Not a good choice")("choice3"));
std::vector<std::string> List2(adder<std::string>("Hello")("Experts")("Can")("You")("Help?"));
Where adder<> is a class template defined as:
template<typename T>
struct adder
{
std::vector<T> items;
adder(const T &item) { items.push_back(item); }
adder& operator()(const T & item) { items.push_back(item); return *this; }
operator std::vector<T>&() { return items ; }
};
Sample running code here : http://www.ideone.com/GLEZr
/** Wrapper for C style arrays; does not take ownership of the array */
template <typename T>
class static_array
{
T *array;
size_t nelems;
public:
template <size_t N>
static_array(T (&a)[N]) : array(a), nelems(N) {}
T &operator[](size_t i) { return array[i]; }
T const &operator[](size_t i) const { return array[i]; }
size_t size() const { return nelems; }
};
typedef static_array<char const *> static_cstr_array;
Construct as static_cstr_array array1(List1). The setter is operator[], i.e.
array1[1] = "foo!";
You can add any method that you want to this class.
(I chose the name static_array because, as far as the class is concerned, the underlying array must be static: it should not grow, shrink or move due to realloc or otherwise. It doesn't mean the array must have static linkage.)
Not sure what you want your functions to be but one way to wrap the arrays would be:
EDIT : changed to incorporate Larsmans suggestion (on the chance that your compiler can't handle his answer).
class ListIF
{
private:
std::vector<const char*> m_list;//stores ptrs to the ROM
public:
ListIF(char const **list, size_t n) : m_list(list, list+n) {}
const char* get( int pos )
{
return m_list[pos];
}
};