Convert Function to Work With Class

Feb 1, 2020 at 6:37am
I had a function that I created and it works on its own with main. Now, I am in the process of trying to convert the function so that it works with a given class. The function checks to see if a word is a palindrome (spelled same way forwards and backwards), and it also ignores white space and special characters.

The problem I am having has to due with the "MyString inString" array object I have created. It starts with the way I am reading data into it, and continues with its parameter usage. Any guidance on how to use this object correctly will be appreciated.

I'll post the header file so anyone can see the specifications of the class. If you need me to post any functions from it, please let me know.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  #ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>

namespace compsci_mystring {
    class MyString {
    public:
        MyString(const char* inString);
        MyString();
        MyString(const MyString& copyMe);
        ~MyString();
        friend std::ostream& operator<<(std::ostream& out, const MyString& printMe);
        friend std::istream& operator>>(std::istream& in, MyString& readMe);
        void read(std::istream& in, char delimeter);
        static const int MAX_INPUT_SIZE = 127;
        char operator[] (int index) const;
        char& operator[](int index);
        friend bool operator<(const MyString& left, const MyString& right);
        friend bool operator>(const MyString& left, const MyString& right);
        friend bool operator<=(const MyString& left, const MyString& right);
        friend bool operator>=(const MyString& left, const MyString& right);
        friend bool operator==(const MyString& left, const MyString& right);
        friend bool operator!=(const MyString& left, const MyString& right);
        MyString operator=(const MyString& right);
        friend MyString operator+(const MyString& left, const MyString& right);
        MyString operator+=(const MyString& right);
        int length() const;
    private:
        char* str;
    };
}

#endif




#include <iostream>
#include <cstring>
#include <cctype>
#include "mystring.h"
using namespace std;
using namespace compsci_mystring;

bool isAPalindrome(MyString inString, int start, int end);

int main()
{
	const int SIZE = 256;
	MyString inString[SIZE]{};
	char quit[] = { "quit" };
    int start, end;

	cout << "Enter a string or type quit: ";  // test: Able was I, ere I saw Elba
	cin.getline(inString, SIZE);

	while (strcmp(inString, quit) != 0) {

		cout << inString;
		if (isAPalindrome(inString, inString[0], inString[strlen(inString) - 1])) {
			cout << " is a palindrome." << endl;
		}
		else cout << " is not a palindrome." << endl;



		cout << "Pick 2 elements, everything in between "
			<< "and including the elements wil be checked for palindrome." << endl;
		cout << "Starting element: ";
		cin >> start;
		cout << "Ending element: ";
		cin >> end;
		if (isAPalindrome(inString, start, end)) {
			while (start <= end) {
				cout << inString[start];
				start++;
			}
			cout << ": is a palindrome." << endl;
		}
		else {
			while (start <= end) {
				cout << inString[start];
				start++;
			}
			cout << ": is not a palindrome." << endl;
		}
		cin.ignore();
		cout << "Enter a string or type quit: ";
		cin.getline(inString, SIZE);
	}

	return 0;
}





bool 
isAPalindrome(MyString inString, int start, int end)
{
	if (start < end) {

		if (isspace(inString[start]) || ispunct(inString[start]))
			return isAPalindrome(inString, start + 1, end);

		else if (isspace(inString[end]) || ispunct(inString[end]))
			return isAPalindrome(inString, start, end - 1);


		if (toupper(inString[start]) != toupper(inString[end]))
			return false;

		return isAPalindrome(inString, start + 1, end - 1);
	}
	return true;
}
Feb 4, 2020 at 9:39pm
Hello stoneJax,

Yes please post the class functions.

I tried to compile your program and the first problem I encountered is:
50
51
52
53
54
55
    MyString inString[SIZE]{};  // <--- Defines an array of classes.
    char quit[] = { "quit" };
    int start, end;

    cout << "Enter a string or type quit: ";  // test: Able was I, ere I saw Elba
    cin.getline(inString, SIZE);

line 55 needs a character array, but you are trying to use an array of classes.

Which is followed by the while loop and then the call to "isAPalindrome".

Mostly need the class functions for now to see what I am missing.

Andy
Feb 4, 2020 at 11:37pm
Hello stoneJax,

Would still like to see the class functions file to see if what I did is correct.

I had to make some changes to get it to work before I could put the function in the class. Starting with the beginning of "main":
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//bool isAPalindrome(char* inString, int start, int end); // <--- Remove when moved to class.

int main()
{
	const int SIZE = 256;

	//MyString inString[SIZE]{}; // <--- Do not understand why you need an array here.

	MyString myString; // <--- Only need one for now. Can be changed to an array later if needed.

	char inString[SIZE]{"Able was I, ere I saw Elba"}; // <--- Changed and used for testing. Delete quoted string when finished.
	char quit[] = { "quit" };
	int start{}, end{}, begin{};  // <--- Added "begin".

	cout << "\n Enter a string or type quit: test: Able was I, ere I saw Elba\n"; // <--- Used for testing.
	//cout << "\n Enter a string or type quit: ";  // test: Able was I, ere I saw Elba
	//cin.getline(inString, SIZE);

	while (strcmp(inString, quit) != 0)

The comments should explain it, but if not let me know.

Looking at line 1 you need to send the character array to the function. Once I changed this most if not all the errors went away. You could also write the first parameter as char inString[], but since it degrades to a pointer either way will work.

Creating the character array on line 11 allows lines 17 and 19 to work properly.

After that the rest of the while loop works with a regular function.

I did make one other change in the while loop. See what you think.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cout << "\n Pick 2 elements, everything in between "
	<< "and including the elements wil be checked for palindrome." << endl;

cout << "\n Starting element: ";
cin >> start;
		
cout << " Ending element: ";
cin >> end;

begin = start; // <--- Because you do not want to change the value of "start".

std::cout << "\n ";

while (begin <= end)  // <--- You can do this once and do not need to duplicate it in the if/else statements.
{
	cout << inString[begin++];
	//start++;
}

if (isAPalindrome(inString, start, end))
{
	cout << ": is a palindrome.\n" << endl;
}
else
{
	cout << ": is not a palindrome.\n" << endl;
}

I included lines 1 - 8 because the prompt and inputs may not be easy for everyone to understand. Just to let you know.

After that putting it into the class was easy.

Start by deleting the prototype in "main" and past it into the "public" area of the class. Put the function into the class functions file and write it like the others;
bool MyString::isAPalindrome(char* inString, int start, int end)

In "main" call the function as
myString.isAPalindrome(inString, inString[0], inString[strlen(inString) - 1])

Andy
Feb 6, 2020 at 12:53am
Hi Andy,

Thank you for the response. I'll take some time to absorb what you have done. Also, I'll post the functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#include "mystring.h"
#include <iostream>
#include <cstring>
#include <cassert>
using namespace std;



namespace compsci_mystring {

   



    MyString::MyString(const char* inString)
    {
        str = new char[strlen(inString) + 1];
        strcpy(str, inString);
    }








    MyString::MyString()
    {
        str = new char[1];
        strcpy(str, "");
    }







    MyString::MyString(const MyString& copyMe)
    {
        str = new char[strlen(copyMe.str) + 1];
        strcpy(str, copyMe.str);
    }






    MyString::~MyString()
    {
        delete[] str;
    }







    ostream& operator<<(ostream& out, const MyString& printMe)
    {
        out << printMe.str;
        return out;
    }







    istream& operator>>(istream& in, MyString& readMe)
    {
        delete[] readMe.str;
        char tempStr[MyString::MAX_INPUT_SIZE + 1];
        in >> tempStr;
        readMe.str = new char[strlen(tempStr) + 1];
        strcpy(readMe.str, tempStr);
        return in;
    }







    void MyString::read(istream& in, char delimiter)
    {
        char tempStr[MyString::MAX_INPUT_SIZE + 1];

        in.getline(tempStr, MyString::MAX_INPUT_SIZE + 1, delimiter);
        delete[] str;
        str = new char[strlen(tempStr) + 1];
        strcpy(str, tempStr);
    }







    char MyString::operator[](int index) const
    {
        assert(index >= 0 && index < strlen(str));
        return str[index];
    }







    char& MyString::operator[](int index)
    {
        assert(index >= 0 && index < strlen(str));
        return str[index];
    }







    bool operator<(const MyString& left, const MyString& right)
    {
        return strcmp(left.str, right.str) < 0;
    }





    bool operator>(const MyString& left, const MyString& right)
    {
        return strcmp(left.str, right.str) > 0;
    }





    bool operator<=(const MyString& left, const MyString& right)
    {
        return strcmp(left.str, right.str) <= 0;
    }





    bool operator>=(const MyString& left, const MyString& right)
    {
        return strcmp(left.str, right.str) >= 0;
    }





    bool operator==(const MyString& left, const MyString& right)
    {
        return strcmp(left.str, right.str) == 0;
    }





    bool operator!=(const MyString& left, const MyString& right)
    {
        return strcmp(left.str, right.str) != 0;
    }







    MyString MyString::operator=(const MyString& right)
    {
        if (this != &right) {
            delete[] str;
            str = new char[strlen(right.str) + 1];
            strcpy(str, right.str);
        }

        return *this;
    }







    MyString operator+(const MyString& left, const MyString& right)
    {
        MyString tempStr;
        delete[] tempStr.str;
        tempStr.str = new char[strlen(left.str) + strlen(right.str) + 1];
        strcpy(tempStr.str, left.str);
        strcat(tempStr.str, right.str);
        return tempStr;
    }







    MyString MyString::operator+=(const MyString& right)
    {
        *this = *this + right;
        return *this;
    }







    int MyString::length() const
    {
        return strlen(str);
    }
}
Feb 6, 2020 at 6:32am
I can't even test what I am doing because I am getting some errors that I have no idea what they mean. I have no red squiggly lines in Visual Studio, and when I try to compile I get this error:

Severity Code Description Project File Line Suppression State
Message see declaration of 'strcpy' repalidrome C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\string.h 133

When I click on it another tab for string.h opens up, and on line 133 it says:

__DEFINE_CPP_OVERLOAD_STANDARD_FUNC_0_1(
Feb 6, 2020 at 9:32am
see declaration of 'strcpy'

The declaration starts from line 133 but apparently spans multiple lines.

when I try to compile I get this error

Is there any indication which line of your code leads to that error?
Feb 6, 2020 at 3:27pm
Hello stoneJax,

Given the changes needed for your original code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//bool isAPalindrome(char* inString, int start, int end); // <--- Remove when moved to class.

int main()
{
	const int SIZE = 256;

	//MyString inString[SIZE]{}; // <--- Do not understand why you need an array here.

	MyString myString; // <--- Only need one for now. Can be changed to an array later if needed.

	char inString[SIZE]{"Able was I, ere I saw Elba"}; // <--- Changed and used for testing. Delete quoted string when finished.
	char quit[] = { "quit" };
	int start{}, end{}, begin{};  // <--- Added "begin".

	cout << "\n Enter a string or type quit: test: Able was I, ere I saw Elba\n"; // <--- Used for testing.
	//cout << "\n Enter a string or type quit: ";  // test: Able was I, ere I saw Elba
	//cin.getline(inString, SIZE);

	while (strcmp(inString, quit) != 0)


If you could use a "std::string", and it would be better if you can, it would look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//bool isAPalindrome(char* inString, int start, int end); // <--- Remove when moved to class.

int main()
{
	const int SIZE = 256;

	//MyString inString[SIZE]{}; // <--- Do not understand why you need an array here.

	MyString myString; // <--- Only need one for now. Can be changed to an array later if needed.

	std::string inString{"Able was I, ere I saw Elba"}; // <--- Changed and used for testing. Delete quoted string when finished.
	std::string quit{ "quit" };
	int start{}, end{}, begin{};  // <--- Added "begin".

	cout << "\n Enter a string or type quit: test: Able was I, ere I saw Elba\n"; // <--- Used for testing.
	//cout << "\n Enter a string or type quit: ";  // test: Able was I, ere I saw Elba
	//cin.getline(inString, SIZE);

	while (inString != quit)


If part of the program is to use C strings then use what you need to.

The member functions file helped. At least I know what I did was on the right track, but now I can see what you are doing.

One thing I have found with versions 2015 and 2017 is that most of "string.h" is old and not recommended by VS. One of the give a ways is the path to "string.h", which is included by "cstring", "C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\string.h". This is not the normal path to the C++ include files, but is made available more for older code.

In order to use the "strcpy()", "strcmp()" and others I had to add this to the "mystring.cpp" file
#pragma warning(disable : 4996) . This allows use of the older less secure versions of these functions.

So far I have not been able to duplicate your error message. It is quite possible that with the changes I made it did not show up.

Andy
Feb 8, 2020 at 8:02am
Hi Andy,

Thank you for pointing out that the cin.getline() works with an array of chars and not an array of classes like I had. Also, your idea for the while loop is much cleaner than what I was trying to do. I want to remember that one and put it into practice. Furthermore, I never would have known about the #pragma warning(disable : 4996) , but after making that change I was able to run my program again to test and fine tune it. Now, the programs runs nicely, and I got it going with user input.

What started out as feeling like a big mess actually broke down to be quite clean and simple!

Thank again!
Feb 8, 2020 at 3:03pm
Hello stoneJax,

I will try this again.

You are welcome.

The "#pragma" is just a quick fix and something you should working removing.

Functions like "strcpy()" are old and not secure. My VS suggests using functions that end in "_s" for better memory management of the character arrays. Those functions do not need the "#pragma" directive.

More often I find the using the "std::string" works just as good, but may not be available to you for what yo are learning.

Andy
Feb 9, 2020 at 11:10pm
These things are out of the scope of what I have been studying. However, out of curiosity I've done a some googling (seem to get mostly really old forums) and it appears that functions like "strcpy()" are part of the ISO standard library, and functions that end in "_s" are a Microsoft extension. The "_s" stands for safe because the functions are supposed to be safer than the ISO Standard. Unfortunately, I find conflicting opinions about whether or not to use the "_s" functions as some say they can have harder to find bugs. Again the information I read was old, so I am curious about any up to date information regarding this that anyone may have or any good links to read about it.

When you say "std::string" are you talking about using #include <string>?

If I should be working on removing the "#pragma", how would that be accomplished?
Is it a lot of work, or something as simple as a #include?

I am happy that I have a working program, but if there are better programming practices then I care more about becoming a better programmer, rather than just making it work.
Feb 10, 2020 at 2:37am
Hello stoneJax,

For the first part I will have to admit that you know more than I do right now. It is easy to accept that the "_s" is from Microsoft and sound about right. Mostly I just accept some things because I find it easier to work with some programs then to spend a lot of time on something I try to avoid using, the "cstring" or "string.h" header files, and do what I need to make it work.

The "#pragma" line I use is something I found because I was having trouble with "#define _CRT_SECURE_NO_WARNINGS". Now if I understand correctly it should be the first line in a program before any header files.

When you say "std::string" are you talking about using #include <string>?

Yes. The "string" header file defines the string class along with several public member functions that you can use along with other functions to deal with storing and retrieving your string. AS I have read the "std::string" is basically a C string character array, but handled differently by the string class. Which means that you can do str[index] to access each element of the string and the class knows where to find each character.

In order to remove or stop using the "#pragma" line you just need to work away from using the "cstring" or "string.h" header file along with functions like "stcpy()".

I am happy that I have a working program, but if there are better programming practices then I care more about becoming a better programmer, rather than just making it work.


I do not know if it is good or bad or just my oppion , but what I have read here in the past try to avoid using C functions and C code in a C++ program. This may take a little time to learn the C++ way and move away from the C code. In the end there are a few C header files still worth using and those that are supported have a C++ file name that starts with "c" the file name and no extension.

Mostly it will just take some time to learn the C++ way. Also there is a lot of good code posted here if you have the time to read as much as you can.

Andy
Feb 10, 2020 at 2:53am
it appears that functions like "strcpy()" are part of the ISO standard library, and functions that end in "_s" are a Microsoft extension.

With C11 what used to be MS extensions are now part of the C standard for many string manipulation and examination functions.

https://en.cppreference.com/w/c/string/byte

None of this is carried forward into the C library headers in C++. Using std::string in C++ code is encouraged.
Feb 10, 2020 at 7:32am
I haven't been taught anything about #includes or #defines that I should or should not use. At least not in this context. On the other hand, I may be told something like I can't use #include <string> because they want to teach solving a problem with restricted tools. Also, I never thought about a C way or a C++ way; I just thought C++ was an extension of C with object oriented features. In the end I need to get more familiar with and remember what all the # includes have to offer.

Furry Guy, thank for pointing out that the Microsoft extensions _s are now part of the C standard; I was curious about that.

Both you guys broaden my perspective on things that I should keep an eye out for to learn more about. Thank you.

Topic archived. No new replies allowed.