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.
Related
class Class
{
public:
Class(array[3][3]) //the constructor
{
this->array = array
}
array[3][3];
};
int main()
{
array[3][3] = {...initialization...};
Class object(array[3][3]);
}
I want to make an object, which uses the 2d array and modifies it. I know that C arrays are just pointers to an address, but I couldn't pass it in the constructor no matter how many *, & or [] I write.
The most clever thing I could think of is making an array of POINTERS in the class, and assigning each pointer, to the address of the original array's element via for loop, but then every time I want to modify, or read from the array in main, I have to write for example *array[2][1] = 3.
Any clever solution?
If I finally got the question correctly, you can use a reference to an array:
struct Class {
Class(int (&array)[3][3]) : array_(array)
{}
void set11(int value) {
array_[1][1] = value;
}
int (&array_)[3][3];
};
int main() {
int array[3][3]{};
Class object(array);
object.set11(99);
std::cout << array[1][1]; // Prints 99
}
If that's not what you want, please clarify your question.
Here's how to declare a pointer in your class that can point to the array in main.
class Class
{
public:
Class(int (*array)[3])
{
this->array = array;
}
int (*array)[3];
};
int main()
{
int array[3][3] = { ... };
Class object(array);
}
So there seems to be some problem with the solution to Problem 9-2 in the book "Object-Oriented Programming in C++, 4th edition" by Robert Lafore. So the problem is that if I would like to create a Pstring object with a statement like Pstring = "This is a string", the Pstring constructor will only call the constructor with no arguments in the String class, instead of the second one with uses one char[] argument. Does anyone know what causes this kind of problem, and a fix to this? Thanks!
#include <iostream>
#include <cstring>
using namespace std;
////////////////////////////////////////////////////////////////
class String //base class
{
protected: //Note: can't be private
enum {
SZ = 80
}; //size of all String objects
char str[SZ]; //holds a C-string
public:
String() //constructor 0, no args
{
str[0] = '\0';
}
String(char s[]) //constructor 1, one arg
{
strcpy(str, s);
} // convert string to String
void display() const //display the String
{
cout << str;
}
operator char*() //conversion function
{
return str;
} //convert String to C-string
};
////////////////////////////////////////////////////////////////
class Pstring: public String //derived class
{
public:
Pstring(char s[]); //constructor
};
//--------------------------------------------------------------
Pstring::Pstring(char s[]) //constructor for Pstring
{
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally
}
////////////////////////////////////////////////////////////////
int main() { //define String
String s1 = "This is a string"; // This works great
s1.display();
Pstring s2 = "This is a string"; // *** Here, nothing will be assigned to s2****
s2.display(); // *** Nothing will be printed here***
return 0;
}
In a function parameter, a T[] (where T is char in your case) is really a T*.
In C++, a string literal is a const char[N] fixed array, which decays into a const char* pointer to the 1st element. But you don't have any constructors that accept either of those types as a parameter. A const char* can't be given to a char*. You need to add const to your constructors:
String(const char s[])
Pstring(const char s[])
Also, calling String(s) in the body of the Pstring constructor does not initialize the Pstring object using the base class String constructor, like you are expecting. It instead constructs a temporary String object that goes out of scope immediately. The Pstring object is not affected by that.
The only place that a base class constructor can be called by a derived constructor is in the member initialization list. In your case, there is no such call, so the compiler implicitly calls the base class default (0-param) constructor before entering the body of the derived constructor. Which doesn't help you, since you want the base class to initialize the str buffer with data.
One way you can do that is add another constructor to String that takes a user-defined length as input, and then call that from the Pstring constructor, eg:
String(const char s[], size_t len)
{
len = std::min(len, SZ-1);
memcpy(str, s, len);
str[len] = '\0';
}
Pstring::Pstring(const char s[])
: String(s, strlen(s))
{
}
Note that your 1-param String constructor has a buffer overflow waiting to happen, since the user can directly construct a String object with input that is greater than SZ characters in length. The String constructor should use strncpy() instead of strcpy():
String(const char s[])
{
strncpy(str, s, SZ);
str[SZ-1] = '\0'; // in case s is >= SZ chars
}
Which then makes the 1-param Pstring constructor redundant - especially since it is not handling the null terminator correctly to begin with, as the assignment of the terminator needs to be outside of the for loop, eg:
Pstring::Pstring(const char s[])
{
if (strlen(s) >= SZ)
{
for (int j = 0; j < SZ - 1; j++) {
str[j] = s[j];
}
// alternatively: memcpy(str, sz, SZ-1);
str[SZ-1] = '\0'; // <-- moved here
}
else
strcpy(str, s);
}
In this conversion constructor
Pstring::Pstring(char s[]) //constructor for Pstring
{
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally
}
at first the default constructor of the class String is called before the control will be passed to the constructor of the class Pstring.
So the data member is set like
String() //constructor 0, no args
{
str[0] = '\0';
}
As the argument that is the string literal "This is a string" that by the way as the argument has the type const char * due to the implicit conversion of arrays to pointers has the length that is less than SZ then within the body of the constructor Pstring nothing is done with the data member str. This statement
String(s);
creates a temporary object of the type String that is at once deleted.
What you need is to write at least
strcpy( str, s );
instead of creating the temporary object.
Pay attention to that the constructors with parameters shall be declared like
String( const char s[] );
and
Pstring( const char s[]);
if you are going to use string literals as arguments of the constructors.
You could move this code snippet
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally
form the constructor Pstring to the constructor String with parameter and substitute it for one call of strncpy like
strncpy( str, s, SZ - 1 );
str[SZ-1] = '\0';
In C++, constructors aren't allowed to be called like this:
else
//not too long,
String(s);
C++ wants you to use its initialization list instead (see the link above for some examples).
If you have a portion of the construction in the parent class you would like to call from inside the child constructor, you can use a protected method instead:
class String //base class
{
protected:
void commonTask(char s[]) {
// do something...
}
public:
String(char s[])
{
commonTask(s);
}
};
class Pstring: public String
{
public:
Pstring(char s[]) { //constructor
if(someCondition) {
commonTask(s);
}
}
};
I'm using pseudo code here, but hopefully you get the idea.
Dear StackOverFlowers,
I'm having trouble passing a const char* [] to an object. The scenario is as follows.
I have a class UlamScreen which contains a const char* [] with several strings. UlamScreen also contains an object homeScreenMenu.
class UlamScreen {
const char* homeScreenText[5] = {"EVA dun", "Sabine", "TPU dun", "test Wout",
UlamScreenMenu homeScreenMenu;
};
class UlamScreenMenu {
private:
const char* _menuText[];
public:
UlamScreenMenu(const char*[]);
void drawMenu();
};
I want to pass the const char* [] to UlamScreenMenu so I can use it in a member function called void drawMenu, like this:
void UlamScreenMenu::drawMenu() {
for (int i = 0; i < menuItems; i++) {
tft.println(_menuText[i]);
}
}
I passed it to UlamScreenMenu's constructor like this:
UlamScreen::UlamScreen() : homeScreenMenu(homeScreenText) {
}
UlamScreenMenu::UlamScreenMenu(const char* menuText[], int length) {
for(int i = 0; i < length; i++) {
_menuText[i] = menuText[i];
}
}
I thought this would work, but for some reason, it does not. tft.println(_menuText[i]); used with void drawMenu does not send anything to my tft screen. When I use tft.println(_menuText[i]); from within the UlamScreen class it works perfectly.
Just to be clear, I can use the tft object within the UlamScreenMenu class because other functions like tft.drawRect() are working correctly.
What is wrong with this way of passing the const char* []? Thanks in advance.
In C++, you can't declare a member variable of type const char* x[], since this would denote a flexible array member. Flexible array members are a C-feature allowing the last member of a struct to be an array of varying size (cf., for example, Arrays of unknown size / flexible array members). Having parameters of type const char* x[] in functions, however, is supported and has basically the same meaning as const char** x.
If you stick to a member of type const char**, then you'll have to handle memory management in that class. This means: take care of allocating, deallocating, copying, moving, copy-assigning, and move-assigning objets of that class (cf, for example, the rule of 0/3/5).
If - as suggested in the comments - you use standard library collections, e.g. std::vector, these classes will do all this stuff in a reliable manner for you. See the following example illustrating the difference between both:
Note that the C++-version probably would not even take a const char*[]-parameter but directly a const std::vector<const char*> &x-parameter. But I kept the const char*[]-parameter in the constructor to provide the same interface in both variants:
// Variant 1: "old" C-style:
class Menu {
public:
Menu(const char* x[], int length) {
m_x = new const char*[length];
m_length = length;
for (int i=0; i<length; i++) {
m_x[i] = x[i];
}
}
~Menu() {
delete[] m_x;
}
// TODO: implement copy- and move constructors + copy- and move assignments
// ...
void print() {
for (int i=0; i<m_length; i++) {
std::cout << m_x[i] << std::endl;
}
}
private:
const char** m_x = nullptr;
int m_length;
};
#include <vector>
// Variant 2: a C++- way:
class Menu2 {
public:
Menu2(const char* x[], int length) {
m_x.assign(x, x+length);
}
void print() {
for (auto s : m_x) {
std::cout << s << std::endl;
}
}
// Menu2 does not manage memory on its own, hence:
// No special copy/move - constructors/assignments to be implemented.
// No special destructor necessary
private:
std::vector<const char*> m_x;
};
int main() {
const char* x1[3] = {"one","two","three" };
const char* x2[2] = {"eins","zwei" };
// Variant 1
Menu m1(x1, 3);
m1.print();
// Variant 2
Menu2 m2(x2, 2);
m2.print();
}
C++ newbie here. This may be stupid but I am getting segmentation fault while assigning value to struct in a class. Any pointers?
#include <iostream>
#include<string>
using namespace std;
struct s { std::string s;};
class A {
public:
A(){}
~A(){}
struct s *ss[10];
};
int main(){
A a;
a.ss[0]->s = "test";
cout<<a.ss[0]->s<<endl;
return 0;
}
The pointer a.ss[0] is not allocated.
You could for example allocate it in the constructor of class A, like this:
A(){ ss[0] = new s; }
I'm not sure what the purpose of your code is.
P.S.: Don't forget to delete the allocated memory once it is not needed anymore. For example:
~A(){ delete ss[0]; }
Alternatively, as LogicStuff pointed out, you can rewrite the array of pointers to a regular array, like this:
struct s ss[10];
struct s *ss[10];
What this line declares is an array of 10 pointers to struct s, not 10 objects of type struct s. Those 10 pointers point nowhere, to make them useful you have to actually allocate memory for and create those object (and clean them up when you're done).
This is where constructors and destructors come in handy:
class A {
public:
A()
{
for(int i = 0; i < 10; ++i)
{
ss[i] = new s;
}
}
~A()
{
for(int i = 0; i < 10; ++i)
{
delete ss[i];
}
}
struct s *ss[10];
};
Now each of those 10 pointers in your array point to valid struct s objects, so you can safely access them:
A a;
a.ss[0]->s = "test";
When you say
/*struct*/ s *ss[10]; // P.S. you don't need "struct" here as in C
the compiler understands that it should reserve space in your class for 10 pointers to objects of type s. It doesn't make sure that those pointers point to anything valid, though.
Actually, the safest thing would be to avoid raw arrays entirely and use a vector. Your life will be much easier.
struct A {
// note no need to declare default ctor and dtor here
std::vector<s> ss{10}; // initialize with 10 default-constructed strings
};
// then in main()
A a;
a.ss[0].s = "test";
s* p = &ss[0]; // if you need a pointer; fine so long as vector doesn't change
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++