Issue with popping stack characters and saving them to a string - c++

I have a bit of trouble with programming sometimes, but I'm generally alright and always have the issue of understanding the concept perfectly, but I hit a brick wall when I attempt to implement an actual program to perform an operation.
I have an assignment to work on, in which I must take an input string, read it character by character into a stack (using a linked list) and then pop that result out of the stack, store it to a new string and then compare the strings to determine if that particular input string is or isn't a palindrome.
The only issue so far that I seem to have ran into is (hopefully) at the very end of the program. When I attempt to pop each character off the stack and store them in a string individually, I get an issue where Visual Studio tells me: "error C2664: 'Stack::pop' : cannot convert parameter 1 from 'unsigned int' to 'char &'"
void Stack::pop(char &input_string) {
StackNode* temp;
if (isEmpty()) {
cout << "The stack is empty." << endl;
}
else {
input_string = top->value;
temp = top->next;
delete top;
top = temp;
}
}
int main () {
Stack stringStack;
string input_string;
string reverse_input;
cout << "Input the desired string to determine if it is a palindrome or not. No spaces please." << endl;
cin >> input_string;
for (unsigned int i=0; i < input_string.length(); i++) {
stringStack.push(input_string[i]);
}
while (!stringStack.isEmpty()) {
for (unsigned int j=0; j < input_string.length(); j++) {
stringStack.pop(j) = reverse_input[j];
}
}
if (reverse_input == input_string) {
cout << "Your input is a palindrome!" << endl;
}
else {
cout << "Your input was not a palindrome, try again!" << endl;
}
system ("PAUSE");
}
I realize that it is telling me that I cannot pass j into the pop function to pop out the values because the pop function I have declared is expecting a char value.
Could this be remedied by changing the input to the pop function to an integer, and then using the pop function to return the char value instead?
I am excluding all other function of the cpp file other than the pop function and the main execution function, let me know if you need to see another part for some reason.
Thanks in advance for the help. It is much appreciated.

In this part:
while (!stringStack.isEmpty()) {
for (unsigned int j=0; j < input_string.length(); j++) {
stringStack.pop(j) = reverse_input[j];
}
}
Assuming that the goal is to take the element at the top of the stack with pop and add it at the end of the string reverse_input so that the resulting reverse_input would be the reverse of input_string, there is one too many loops.
for( unsigned int j = 0; !stringStack.isEmpty() ; j++ ){
//Code Here
}
Or:
while( !stringStack.isEmpty() ){
//Code Here
}
Also stringStack.pop(j) = reverse_input[j]; isn't actually assigning anything, as pop is a void function.
One alternative is the following:
Modify the pop so that it returns the char element at the top.
char Stack::pop() {
StackNode* temp;
char mychar = '\0';
if (isEmpty()) {
cout << "The stack is empty." << endl;
}
else {
mychar = top->value;
temp = top->next;
delete top;
top = temp;
}
return mychar;
}
Then:
reverse_input = ""; //To make sure it is empty
while( !stringStack.isEmpty() ){
reverse_input += stringStack.pop();
}

Related

Trying to update an array with huffman string code

My current program creates a huffman tree filled with nodes of ascii characters that are being read from a text file along with the amount of time they appear in the text file (frequency). In addition, it outputs unique codes for each character read based on frequency, this is done using my traverse function.
My problem: I have this string array that can hold codes for all 256 ascii values in my huffman function that by default is set to an empty string for each element. I have been trying to update my array by passing a parameter to my traverse function but it gives me an error.
Code E0413 - "No suitable conversion from std::string to char exists"
Parts of my code below along with some explanation of what the variables in my traverse function are:
'character' is the char that has been found in the text file
'frequency' gives the number of times a character is read in the text file
'traversecode' is the huffman code being generated by the traverse function
I have also commented out lines in my traverse function where I get the error.
struct node {
int frequency;
char character;
const node *child0;
const node *child1;
node(unsigned char c = 0, int i = -1) {
character = c;
frequency = i;
child0 = 0;
child1 = 0;
}
node(const node* c0, const node *c1) {
character = 0;
frequency = c0->frequency + c1->frequency;
child0 = c0;
child1 = c1;
}
bool operator<(const node &a) const {
return frequency > a.frequency;
}
void traverse(string codearray[256], string traversecode = "") const {
if (child0) {
child0->traverse(traversecode + '0'); // one line throwing the error
child1->traverse(traversecode + '1'); // second line that throws me the error
}
else {
codearray[int(character)] = traversecode;
cout << " " << character << " ";
cout << frequency;
cout << " " << traversecode << endl;
}
}
};
huffman function (function that contains array I would like to get updated)
void huffman(string code[256], const unsigned long long frequency[256]) {
priority_queue < node > q;
for (unsigned i = 0; i < 256; i++) {
if (frequency[i] == 0) {
code[i] = "";
}
}
for (int i = 0; i < 256; i++)
if (frequency[i])
q.push(node(i, frequency[i]));
while (q.size() > 1) {
node *child0 = new node(q.top());
q.pop();
node *child1 = new node(q.top());
q.pop();
q.push(node(child0, child1));
}
cout << "CHAR FREQUENCY HUFFMAN CODE" << endl;
q.top().traverse(code);
}
When you make the recursive call to traverse, you need to provide both parameters.
child0->traverse(codearray, traversecode + '0');
You're currently trying to pass what should be the second parameter as the first.
One other possible issue is that your code assumes that char is unsigned. If a char is signed, the access to codearray[int(character)] will access outside the bounds of codearray if the character is "negative" (or in the upper half of the ASCII table when using unsigned characters).

Shifting an array of structs C++

I am quite new to c++ programming and data structures and really need some help. I am working on an assignment where I have a text file with 100 lines and on each line there is an item, a status(for sale or wanted), and a price. I need to go through the text file and add lines to an array of structs and as I add lines I need to compare the new information with the previously submitted information. If there is a line that is wanted and has a price higher than a previously input item that is for sale then the item would be removed from the struct and the array of structs shifted.
The place that I am having trouble is in actually shifting all the structs once a line that satisfies the condition is found.
My issue is that when I try to shift the array of structs using the second for loop nothing happens and I just get null structs and nothing seems to move.
Please if you guys can offer any help it would be greatly appreciated.
Below is the code of the text file and my current code.
#include<iostream>
#include<fstream>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;
struct items
{
string type;
int status;
int price;
} itemArray [100];
int main(int argc, char *argv[]) {
int x = -1;
//int chickenCount = 0;
int counter = 0;
int itemsSold = 0;
int itemsRemoved = 0;
int itemsForSale = 0;
int itemsWanted = 0;
string itemType;
int itemStatus = 0;
int itemPrice = 0;
int match = 0;
ifstream myReadFile( "messageBoard.txt" ) ;
std::string line;
//char output[100];
if (myReadFile.is_open()) {
while (!myReadFile.eof()) {
getline(myReadFile,line); // Saves the line in STRING.
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
//cout<<line<<endl; // Prints our STRING.
x++;
std::string input = line;
std::istringstream ss(input);
std::string token;
while(std::getline(ss, token, ',')) {
counter++;
//std::cout << token << '\n';
if (counter>3){
counter =1;
}
//cout << x << endl;
if (counter == 1){
itemType = token;
//cout<< itemType<<endl;
}
if (counter == 2){
if (token == "forsale"){
itemStatus = 1;
//itemsForSale++;
}
if (token == "wanted"){
itemStatus = 0;
//itemsWanted++;
}
//cout<< itemStatus<<endl;
}
if (counter == 3){
itemPrice = atoi(token.c_str());
//cout<< itemPrice<<endl;
}
//cout<<"yo"<<endl;
}
if (x >= 0){
for (int i = 0; i<100;i++){
if (itemArray[i].type == itemType){
//cout<<itemType<<endl;
if(itemArray[i].status != itemStatus){
if (itemArray[i].status == 1){
if(itemPrice>=itemArray[i].price){
itemsSold++;
match =1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i =i-1;
break;
}
}
if (itemArray[i].status == 0){
if(itemArray[i].price>=itemPrice){
itemsSold++;
match = 1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i=i-1;
break;
}
}
}
}
}
}
if (counter == 3 && match == 0){
itemArray[(x)].type = itemType;
itemArray[(x)].status = itemStatus;
itemArray[(x)].price = itemPrice;
}
match = 0;
// cout << itemArray[x].type << " " << itemArray[x].status<<" "<<itemArray[x].price<<endl;
}
for(int i=0;i<100;i++){
cout<<itemArray[i].type<< " "<<itemArray[i].status<<" "<<itemArray[i].price<<endl;
}
//cout<<itemArray[1].price<<endl;
cout << itemsSold<<endl;
}
myReadFile.close();
return 0;
}
text file: https://drive.google.com/file/d/0B8O3izVcHJBzem0wMzA3VHoxNk0/view?usp=sharing
Thanks for the help
I see several issues in the code, but without being able to test it, I think the main problem is that you always insert new elements at position 'x' which correspond to the currently line read from the file, without taking into account any shift of elements done. You should insert the new element at the first empty slot (or just overwrite the old element instead of shifting everything).
An other issue is that you do not initialize the status and price in your array.
The best way would be to rewrite the code by using more standard C++ features, for example:
replace the items structure by a class with a constructor defining default values
use object copy (there is no need to copy a struct element by element)
use standard C++ containers like a list (see http://www.cplusplus.com/reference/list/list/) which has insert and erase methods

How to get the base address of a pointer to a dynamically allocated object

I have defined a struct above main() called "Pieces"
struct Pieces {
char *word;
int jump;
}
In my main() I have:
int main() {
Pieces *pieceptr;
readFile(preceptor);
cout << (*pieceptr).word << endl; //SEGFAULT occurs here
return 0;
}
And in readFile() I have:
void readFile(Pieces *&pieceptr) {
ifstream fin;
fin.open("data");
int pieceCount;
if(fin.is_open()) {
fin >> pieceCount;
pieceptr = new Pieces[pieceCount];
for (int i = 0; i < pieceCount; i++) {
char *tempWord = new char[20];
fin >> tempWord >> (*pieceptr).jump;
(*pieceptr).word = new char[stringLength(tempWord)];
stringCopy((*pieceptr).word, tempWord);
delete []tempWord;
tempWord = NULL;
pieceptr++;
}
} else {
cout << "Error opening file." << endl;
}
fin.close();
}
The constraints for this project are:
Create my own string functions
Square brackets should only be used when declaring or deallocating an array dynamically.
Do not use pointer arithmetic, besides ++ and -- or setting back to home pointer.
Do not use arrow (->) notation with your pointers.
I have tested the readFile() function extensively and it is functioning as I want it to (it populates the Pieces array correctly), but after I call readFile() in main() I need to access the first element of the array again. As the code is now, I get a segfault due to the fact that the pointer has been incremented out of the bounds of the array. How would I reset the pointer to point back to the first element inside the array without using pointer arithmetic?
Multiple pointers can point to same point of memory. Pointers can also be copied. Easiest solution to yours problem is to create another pointer and do all increasing on it.
void readFile(Pieces *&pieceptr) {
ifstream fin;
fin.open("data");
int pieceCount;
if(fin.is_open()) {
fin >> pieceCount;
pieceptr = new Pieces[pieceCount];
Pieces* pieceIterator = pieceptr;
for (int i = 0; i < pieceCount; i++) {
char *tempWord = new char[20];
fin >> tempWord >> (*pieceIterator).jump;
(*pieceIterator).word = new char[stringLength(tempWord)];
stringCopy((*pieceIterator).word, tempWord);
delete []tempWord;
tempWord = NULL;
pieceIterator++;
}
} else {
cout << "Error opening file." << endl;
}
fin.close();
}

reverse string bus error

I'm doing some basic c++ and decided to implement a revStr method.
But for some reason every time I execute the method, I get a bus error caused by the assignments in the while loop but I can't understand why.
Anybody got any clues? Any help would be much appreciated.
char* reverseStr(char* s){
if(!s){
cout << "Void!"<<endl;
return s;
}
char* end, *start;
end = s;
start = s;
while(*(end) != '\0'){
end++;
}
end--;
while(start < end){
char temp = *start;
cout << temp <<endl;
*start = *end;
*end = temp;
start++;
end--;
}
cout << "The reversed string is: " << s <<endl;
return s;
}
Apologies.. I have added the driver program below:
int main(int argc, char** argv) {
assert(reverseChar("hello") == "olleh");
return 0;
}
If you're passing a string literal it should not compile as your func (correctly) takes non-const.
Unless, of course, you force cast it... so don't remove the const but strdup() it instead.
What could also be happening is that the loop runs forever. You can test it with a debugger.
The reason is that pointers cannot be properly compared for less, or greater then. Only for equality. You have to change your < to !=
Unable to reproduce problem ... code works as expected.
My Test (showing how I created "forwardCharStar[100]);")
int t282(void)
{
std::string forwardStr = "abcdefghijklmnopqrstuvwxyz";
size_t sz = forwardStr.size();
assert(sz < 100); // check fit
// ^^^-----------vvv
char forwardCharStar[100];
for (size_t i = sz-1; i < 100; ++i) forwardCharStar[i] = 0;
for (size_t i = 0; i < sz; ++i) forwardCharStar[i] = forwardStr[i];
std::string rS = reverseStr(forwardCharStar);
std::cout << "The reversed string is: " << rS << std::endl;
return (0);
}
Note: filled tail of forwardCharStar[100] with '\0'
- null terminator is important in c-style strings
Note: then transferred 26 chars from 'forwardStr' to front of forwardCharStar
Output:
The reversed string is: zyxwvutsrqponmlkjihgfedcba
Note: I commented out the char by char output from
2nd line of while loop
// std::cout << temp << std::endl;
Note: forwardCharStar[100] matches the reversed string, the code modifies its input string.

C++ Deque implementation with character arrays

So I'm writing a program that takes in a string of characters in a command line statement, and breaks up the word into two or three pieces (2 for even, first half and second half, 3 for odd, first "half", middle letter, and second "half), and reverses the characters of the first and second halves and re concatenates the characters into a single string htat is outputted. It gets a little uglier than that, as I have to use a deque and use push and pop functions to move around the characters. So I have a few problems I don't really understand. First off, the ABottom integer for some reason is blowing up to outrageously large values, which makes no sense as it is supposed to stay fixed at 0. Secondly, when I pop from A, I get an empty string, and when I pop from B, it alternates every other character from the deque. But the loops in the .h file that put the characters in the deque seems to be working exactly as I anticipated. Any suggestions about the ABottom, or why the pops aren't working?
File 1:
// Kevin Shaffer TwoStackKAS.h
#include<iostream>
#include<string>
#include<vector>
#ifndef TWOSTACKKAS_H_
#define TWOSTACKKAS_H_
using namespace std;
class TwoStacks {
char elements[];
int Abottom, Bbottom;
int AtopSpace, BtopSpace;
int totalSize;
public:
TwoStacks(int maxAdds) {
totalSize = 2*maxAdds +1;
char elements[totalSize];
const int Bbottom = totalSize-1; //bottom for both stacks!
const int Abottom = 0;
AtopSpace= 0;
BtopSpace = totalSize-1; //top for both stacks!
cout<<"Stack Size: "<<totalSize<<endl;
}
virtual bool empty() const {
return Abottom == AtopSpace && Bbottom==BtopSpace;
}
virtual bool full() const { return AtopSpace==BtopSpace;}
virtual int stackSize() {
cout<<Abottom<<" Abottom"<<endl;
return (AtopSpace - Abottom +Bbottom -BtopSpace);
}
virtual char popA() {
if (empty()){
cerr << "Attempting to pop Empty stack!"<< endl;
return ' '; //prepare EmptyQexceptiin
} else {
cout << elements[--AtopSpace] << " testpopA"<< endl;
return elements[--AtopSpace];
}
}
virtual char popB() {
if (empty()){ //later EmptyQException
cerr <<"Attempting to pop an empty stack!" << endl;
return ' ';
} else {
//cout <<elements->at(++BtopSpace) << endl;
cout << elements[++BtopSpace] << " test"<< endl;
return elements[++BtopSpace];
}
}
virtual void pushB(char newItem){
elements[BtopSpace--] = newItem;
}
virtual void pushA(char newItem){
elements[AtopSpace++] = newItem;
}
virtual string toString() const {
string out = "";
for (int i = 0 ; i<=Bbottom; i++) {
out += elements[i];}
return out;
}
};
#endif
And file 2:
/** Kevin Shaffer
* Given an input string, reverse each half of the string;
* pivot on the middle element if it exists.
* uses double ended stack in twoStackKAS.h*/
#include<string>
#include "TwoStackKAS.h"
#include<iostream>
#include<string>
using namespace std;
int main (int argc, char* argv[]){
if (argc<=1){return 0;}
string word = argv[1];
int length = word.size(); // gets length of word
int half = length/2;
TwoStacks* sd = new TwoStacks(length/2);
//cout<<sd->stackSize()<<endl;
for(int i = 0; i < length/2; i++){
sd->pushA(word[i]);
cout << word[i] << endl;
}
for(int i = length; i >= length/2; i--){ //Second half of word
sd->pushB(word[i] ); //has been pushed
cout << word[i] << endl; //in reverse order.
}
//cout << word << endl;
//Recombine word
if(length%2==1){ word = word[length/2];}
else{ word = "";}
cout<<sd->stackSize()<<endl;
string leftHalf; string rightHalf;
string myWord; //new word (shuffled)
for(int i=0; i< half; i++) {
leftHalf += sd->popA();
rightHalf += sd->popB();
}
//cout<<"Stack: "<<sd->toString()<<endl;
cout << rightHalf << endl;
cout << leftHalf << endl;
myWord = leftHalf + word + rightHalf;
cout<<myWord<<endl;
return 0;
}
ABottom is not growing... it is never initialized!
Look at your constructor. You're not assigning Abottom, but you're defining a new variable that masks the member variable. You do that multiple times.
And as VS2015 actually did not accept char elements[]; : "Incomplete type is not allowed", it's probably better it use std::string instead of char*
A better constructor would be something like.
class TwoStacks
{
private:
// totalSize has to be assigned before assigning dependent variables
int totalSize;
string elements;
int Abottom, Bbottom;
int AtopSpace, BtopSpace;
public:
TwoStacks(int maxAdds)
: totalSize(2 * maxAdds + 1)
, elements(totalSize, ' ')
, Abottom(0)
, Bbottom(totalSize - 1)
, AtopSpace(0)
, BtopSpace(totalSize - 1)
{
// preferably don't cout in a constructor
cout << "Stack Size: " << totalSize << endl;
}