Palindrome

Write your question here.
I need to write a program that will read some unknown content from a file. The program is supposed to read and output whether the line is a palindrome or not, disregarding punctuation, spaces, and capital letters. I'm obligated to use only the function prototypes given and no other, neither can I use multiple string variables in the main body and no arrays either. Here is my code, I'm having trouble locating the string and adding a character to it to make it palindrome, also my output is coming out all together and its supposed to be spaced between each line read.
PLEASE help.
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
#include<iostream>
#include<string>
#include<cctype>
#include<fstream>

using namespace std;

string process(string&, string&);
bool is_palindrome(string);
int palindrome_fix_location(string);

int main()
{
        ifstream infile("data");
        int location = 0;

        string line, combine, phrase, fix, word, wordr;

        while (getline(infile, line)) //opening data file
        {
                cout << "Original line: " << line << endl;


                process(line, combine);
                cout << "Processed line: " << combine << endl;

                if ( is_palindrome(combine) == false)
                {
                        location++;
                        cout << "Line is NOT a palindrome" << endl;
                }
                else
                    	cout << "Line is a palindrome" << endl;

                if (is_palindrome(combine) == false)
                {
                        palindrome_fix_location(word);
                        cout <<"Characters to insert at location " << location                                                                                      <<" are " << wordr << endl;  
                        cout << "Final line: " << fix << endl;
                }


        }

	infile.close();

        return 0;

}
string process(string& word, string& combine)
{
        combine = ""; // creates an empty string.
        int c;
	c = word.length();

        for (int i = 0; i < c; i++)
        {
                word[i] = tolower(word[i]); // makes all characters lower case
                if (isalnum(word[i])) //if characters are numbers or letters
                        combine = combine + word[i]; 
}
	return combine;

}
bool is_palindrome(string word)
{
        bool comparing;
        int l = word.length();

        for (int i = 0, r = l-1; i < l/2; i++, r--)
                if (word[i] == word[r])
                        comparing = true;
                else
                    	comparing = false;
        return comparing;

}
int palindrome_fix_location(string word)
{
        int w = word.length();
        string fix, wordr;

        for ( int i = 0, r = w-1; i < w/2; i++, r--)
        {
 if (word[i] != word[r])

                        wordr = word[r];
                        fix = word[i] + word[r];
        }
	return 0;

}



  Put the code you need help with here.


int palindrome_fix_location(string word)
{
int w = word.length();
string fix, wordr;

for ( int i = 0, r = w-1; i < w/2; i++, r--)
{
if (word[i] != word[r])

wordr = word[r];
fix = word[i] + word[r];
}
return 0;

}
Hello enrikm84,

Welcome to the forum.

A few things to work on while I get the program loaded an tested.

For your learning:

Try to avoid using using namespace std; in your programs it may seem easy now, but WILL get you in trouble some day.

It is better to learn to qualify what is in the standard name space with "std::" and then to learn what is in the standard name space now while it is easy. And not all at once to try to keep a job.

What you are most likely to use for now is "std::cout", "std::cin" and "std::endl". About a week or so of typing this and you will not even notice that you are doing it.

It is ALWAYS a good practice and programming to initialize your variables. If your compiler is using the C++11 standards or after the easiest way to initialize variables is with empty {}s, e.g., int num{};. This will initialize the variable to 0 (zero) or 0.0 for a double. A "char" will be initialized to "\0". "std::string"s are empty to start with and do not need to be initialized. Should you need to you can put a number between the {}s.You can also Initialize an array, e.g., int aNumbers[10]{};. This will initialize all elements of the array to 0 (zero). A use of
int aNumbers[10]{ 1 }; will initial the first element to "1" and the rest of the array to "0".. Following the "1" with ", 2 ..." will initialize the array with the numbers that you have used up to the entire array.

I figured I would say this while I was here. I do give you credit that you did initialize your variables. Good job.

Lastly post the input file that you are using. This way I will be using the same information that you are, so when talking about the program we will be on the same page using the same input.

Hope that helps,

Andy
Hello enrikm84,

As I work through the program I find the instructions a bit confusing. They say
neither can I use multiple string variables in the main body
yet you have a function that requires two "std::strings", so you need to define two variables in main. I would probably use the firt two and delete the rest.

If you think about it there is no restrictions on how many "std::string" variables you can define in the functions.

Once you have created and opened the "ifstream" you need to check that the file did open and that the stream is good. Something like:

1
2
3
4
5
6
if (!inFile)  // <--- Sorry this way of writing the variable is just habit for me.
{
	std::cout << "\n File \'Data\" did not open" << std::endl;
	std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread"
	exit(1);  // <--- Because there is no reason to continue any farther.
}


The comment on the while statement should read "// Reading data file" not opening this was done earlier.

The lineprocess(line, combine); is a conundrum because you are passing "combine" by reference yet the function returns "combine" that the function call never uses, but any change the function makes to "combine" is reflected back in main, so there is no need for the return variable.Although passing a "std::string" by reference is generally less overhead for the computer than making a copy first when passed by value.

It looks to me that the "process" function should change any letters to lower case and remove any punctuation and spaces leaving you with a string of just letters.

In the "process function" the line that defines could be written asint c = word.length();, but this is not even needed because in your for loop it should be for (std::size_t i = 0; i < word.length(); i++). Keep in mind that "word.length()" returns an "unsigned int", so "i" should be defined the same. "std::size_t" is just another name for "unsigned int".

In thee for loop the first line is OK and the if statement I believe is OK. The line following the if statement can be shortened to combine += word[i]. It does the same thing and I am not saying that you have to change it, but it would make your code look better and might make you as a programmer look better. Just saying.

Lastly you are returning "combine" back to main this is what the function needs to do except for the conundrum of the fact that "combine" being passed by reference the changes to this variable have already been made in main, so why return something that has already been changed.

The last two functions as with the whole program I have not had a chance to actually test yet. That is my next task.

I thought you might want to know this first.

Hope that helps,

Andy
Before all, Andy, thank you very much for taking the time of the day. I truly appreciate it. The use of using namespace std; I don't have a say about it I'm currently enrolled in a C++ course that is how we are being thought to use it and with my professor God forbid you try something not to his standards. I' ll keep it in mind for future reference since I wasn't aware of it and I still have another C++ course to take. Here is the data sheet I'm using for the program.

lappal
lapal
A man, a plan, a canal, Panama!
lap
alapa
bath
aabcaa
abc...123...cba

this is my code:

#include<iostream>
#include<string>
#include<cctype>
#include<fstream>

using namespace std;

string process(string, string&);
bool is_palindrome(string);
int palindrome_fix_location(string);

int main()
{
ifstream infile("data");
int location = 0;

string line, combine, phrase, fix, word, wordr;

while (getline(infile, line)) //opening data file
{
if (line.empty())
break;

cout << "\n\nOriginal line: " << line << endl;

process(line, combine);
cout << "Processed line: " << combine << endl;


if (is_palindrome(combine))
cout << "Line is a palindrome" << endl;
else
{
cout << "Line is NOT a palindrome" << endl;
location = palindrome_fix_location(combine);
}
}

infile.close();

return 0;

}
string process(string word, string& combine)
{
combine = ""; // creates an empty string.
int c;
c = word.length();

for (int i = 0; i < c; i++)
{
word[i] = tolower(word[i]); // makes all characters lower case
if (isalnum(word[i])) //if characters are numbers or letters
combine = combine + word[i];
}
return combine;

}
bool is_palindrome(string word)
{
bool comparing = true;
int l = word.length();

for (int i = 0, r = l-1; i < l/2; i++, r--)
{
if (word[i] != word[r])
comparing = false;
}

return comparing;

}
int palindrome_fix_location(string word)
{
string fix="", wordr="";

int i,j, k=0, location = 0;
char ch;
int l = word.length();

j = l-1;
for ( i = 0; i<l; i++,j--) // This is to reverse string in wordr string
{
wordr = wordr + word [j];
}

for ( i = 0; i< l/2; i++)
{
if ( word[i] !=wordr[i]) // find out location where first mismatch occurs.
{
location = i; // This is the location where we need additional char to place to make string palindrome
ch = word[i];
do
{
fix = fix + wordr[i]; // prepare fix string by characters from wordr until the char founds which caused first //mismatch
k++;
i++;
}while(wordr[i]!=ch); // This loop will break when char from wordr matches with first mismatch char from //word i.e. ch

}
if (k>0)
break;
}
// Display location and fix required to make string as palindrome.
cout <<"Characters to insert at location " << location <<" are " << fix << endl;
// Insert the fix at given locaton using insert function.
word.insert(location,fix);

cout << "Final line: " << word << endl;

return 0;

}

The program is already doing what it is supposed to but as you mention earlier the function string process(string&, string&) is not what we are supposed to do but I just couldn't figure out any other way of doing it. But is supposed to look like this string process(string) with no alterations.
Hello enrikm84,

Sorry I got behind in these messages. Soon as I get my lap top restarted and running better I will look into it shortly.

Andy
Hello enrikm84,

string process(string&, string&) is not what we are supposed to do but I just couldn't figure out any other way of doing it. But is supposed to look like this string process(string) with no alterations.

If you can not figure this out then you will fail the assignment.

The instructions also say:
I'm obligated to use only the function prototypes given and no other, neither can I use multiple string
variables in the main body and no arrays either.
Neither point have you met. You have defined six string variables where you should only have one.

I see nothing in the instructions that restrict you from defining any extra string variables that you may need or any restriction on additional functions.

You should take a look at: http://www.cplusplus.com/forum/beginner/235118/ it looks like the same program.

I will work on what you have and see what I can coke up with.

Hope that helps,

Andy
enrikm84 wrote:
I'm obligated to use only the function prototypes given and no other, neither can I use multiple string variables in the main body and no arrays either.

It'd be super helpful if you provided the exact required prototypes and a description of what each function is supposed to do. As it stands now, you're making us guess ;D

- I'm not sure, for example, what the purpose of palindrome_fix_location() is. I'd probably remove this method.
- why can't the signature of process() be bool process(string line) ? It could create an altered, standardized, string, and return is_palindrome(standardized).

pseudo-code of workflow for a bool process(string line):

for each line in file:
    print line
    print process(line) // true or false        


ok, if you're forced into string process(string line), the workflow would look like so:

for each line in file:
    print line
    print is_palindrome(process(line))


So you see, no need for "combine" second parameter. Breathe and break down the issues step by step; there's usually a logical way to move forward.
is_palindrome() has a bug. Each time through the loop, you set comparing. That means each time through the loop, you throw away any previous value. As a result, the value you return only reflects whether the middle two characters are the same.

A better approach is to return false as soon as you discover that it isn't a palindrome:
1
2
3
4
5
6
7
8
9
10
11
bool is_palindrome(string word)
{
        int l = word.length();

        for (int i = 0, r = l-1; i < l/2; i++, r--) {
                if (word[i] != word[r]) {
                        return false;
                }
        }
        return true;
}

On the subject of advice, always use { and }, even when the body is just one statement. Otherwise some day you'll find that you needed two statements. You'll add the second one, indented appropriately, and forget to add the braces. 15 hours later you'll find the bug.

If it's a really short statement and I don't want to use braces, I put it all on one line as a reminder. For example, I might combine lines 6-8 above into if (word[i] != word[r]) return false;
Oh, also, about your process() question -- I'll format what you wrote in your latest:
enrikm84 wrote:
string process(string word, string& combine)
{
    combine = ""; // creates an empty string.
    int c;
    c = word.length();

    for (int i = 0; i < c; i++)
    {
        word[i] = tolower(word[i]); // makes all characters lower case
        if (isalnum(word[i])) //if characters are numbers or letters
            combine = combine + word[i];
    }
    return combine;
}

Your extra param, 'combine', is what's known as an outgoing parameter. Usually this is done when you need multiple outgoing things, or don't want to create extra copies, or if you'd rather that the method return something like a Success/Fail status for consistency with other methods. As you have it now, you're actually modifying the caller's param and returning a value copy as the return of the function. Since you were asked just for a returned copy, the fix is to remove 'combine' parameter and just create it locally instead:
1
2
3
4
5
6
string process(string line)  // By the way, you're processing a line, not just a word
{
    string combine("");
    // ...
    return combine;
}


Note: It's actually a bit inefficient to keep increasing string size like this. Idk if you've examined string buffers from other languages or w/e, but the C++ version would be to use an outgoing string stream, found in the header <sstream>. You should also get into the habit of commenting what the method does:
1
2
3
4
5
6
7
8
9
10
// Builds new string of just alpha letters converted to uppercase
string process(const string& line)
{
    ostringstream oss;
    for (const char& c : line)
        if (isalpha(c))
            oss << (char)toupper(c);

    return oss.str();
}
Last edited on
It's actually a bit inefficient to keep increasing string size like this. Idk if you've examined string buffers from other languages or w/e, but the C++ version would be to use an outgoing string stream

I don't think ostringstream is more efficient. After all, it still has to expand the string (or whatever internal storage it uses for the streambuf) as it goes. Then when you call oss.str(), it creates and returns a copy of the data.

As I recall, std::string usually grows by 50% when it has to grow, so it's usually not noticeable

If you're worried about the way a string grows then just reserve approximately enough space up front. For example:
1
2
3
4
5
6
7
string process(string line)  // By the way, you're processing a line, not just a word
{
    string combine;  // default constructor makes an empty string.
    combine.reserve(line.size());  // reserve the max amount of space that it will need.
    // ...
    return combine;
}
I would like to thank you all for the help. Here was my final code:


#include<iostream>
#include<fstream>

using namespace std;

int read(ifstream &, int [], int); /*reads all values from
the file into an array.*/
void display(int [], int); // displays all values from the array.
void insertion_sort(int [], int); // sorts the array.
void selection_sort(int [], int); //sorts the array.

int main()
{

int a = 0;
int ar[100];

ifstream infile; //Opening file.

infile.open("data1");

a = read(infile,ar,a);

display(ar,a);
cout << endl;

insertion_sort(ar, a);//Calling insertion sort function.

display(ar,a);
cout << endl;

infile.open("data2"); //Opening file.

a = read(infile, ar, a);

display(ar, a);
cout << endl;

selection_sort(ar, a);//Calling selection sort fucntion.

display(ar, a);
cout << endl;


return 0;
}
int read(ifstream &infile,int ar[],int a)
{
int count;
a = 0;


while (infile >> count) /*Reading throught the file.*/
{
ar[a] = count;
a++;
}


infile.close();
infile.clear();


return a;

}
void display(int ar[], int a)
{
int i;
/*This function is used to display content
from files*/
for (i=0; i < a; i++)
{
if ( i == a)
cout << ar[i];
else
cout << " " << ar[i];
}

}
void insertion_sort(int ar[], int a)
{

int i, k, j;

for (i = 1; i < a; i++)
{
k = ar[i];
j = i-1;

/* Move elements of ar[0..i-1], that are
greater than key, to one position ahead
of their current position */

while (j >= 0 && ar[j] > k)
{
ar[j+1] = ar[j];
}
ar[j+1] = k;
}
}
void selection_sort(int ar[], int a)
{

int k, m, f;

for (int i = 0; i < a - 1; i++)
{

m = i;

for (k = i + 1; k < a; k++)/* Locating smallest int
between possition 1 and i */
{
if (ar[k] < ar[m])

m = k;

if (m != i)
{

f = ar[i];/*Swapping the largest int */
ar[i] = ar[m];

ar[m] = f;

}
}
}

}

Topic archived. No new replies allowed.