1

this is for a CS assignment. I've looked at similar problems/questions, but can't seem to find an answer for this.

A little background info: We need to sort c-strings in a list and count how many times each word occurs. Needed for the problem: Write a program Problem2_A.cpp that inputs several lines of text from the keyboard as C-strings and prints an alphabetical listing of each word in the text and how many times it occurred. To do this, keep a pointer to each word in an array of pointers. Use the qsort() function to sort the array of pointers and then count the number of occurrences of each word. Terminate input by signaling end-of-file from the keyboard. Ignore any case differences (e.g., “Cat” and “cat” are the same word). As a minimum requirement, you may assume there will be no punctuation marks and that exactly one space will separate words in the input lines. You may remove this limitation as an extension.

Edit- I understand I will need to have user input one line with a bunch of words. For now, I will just input each word manually as I am more concerned about accessing the vector and retrieving what I want to retrieve.

Here is what I have so far

Word.H

#pragma once #ifndef __WORD_H__ #define __WORD_H__ #define _CRT_SECURE_NO_WARNINGS class Word { public: Word(char * word); ~Word(); /* Returns the inputted word */ const char* getWord(); private: char word[51]; }; #endif 

Word.cpp

#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include "Word.h" Word::Word(char * word) { strcpy(this->word, word); } Word::~Word() { } const char* Word::getWord() { char* clone = new char[50]; strcpy(clone, word); return clone; } 

Problem2.cpp

#include <iostream> #include <vector> #include "Word.h" using namespace std; const int MAX_WORDS = 2; const int MAX_WORD_LENGTH = 15; char* promptWord(); int main() { char inputWord[MAX_WORD_LENGTH]; vector<Word*> pWordList; pWordList.reserve(MAX_WORDS); cout << "Please type each word and press enter: "; for (int i = 0; i < MAX_WORDS; i++) { Word* newWord = new Word(promptWord()); pWordList.push_back(newWord); } cout << "Printing &pWordList[i]" << endl; for (size_t i = 0; i < pWordList.size(); i++) { cout << &pWordList[i] << endl; } cout << "Printing (void*)pWordList[i]->getWord()" << endl; for (size_t i = 0; i < pWordList.size(); i++) { cout << (void*)pWordList[i]->getWord() << endl; } cout << "Printing pWordList[i]->getWord()" << endl; for (size_t i = 0; i < pWordList.size(); i++) { cout << pWordList[i]->getWord() << endl; } cout << "Printing (*pWordList[i]).getWord()" << endl; for (size_t i = 0; i < pWordList.size(); i++) { cout << (*pWordList[i]).getWord() << endl; } /* Delete our dynamic objects */ while (!pWordList.empty()) { delete pWordList.back(); pWordList.pop_back(); } system("pause"); return 0; } /* Ask the user to enter their desired word @params inputWord[MAX_WORD_LENGTH] -> Desired word to be inputted @return Returns the user's inputted word */ char* promptWord() { char inputWord[MAX_WORD_LENGTH]; cin.getline(inputWord, MAX_WORD_LENGTH); return inputWord; } 

I was never too good with pointers, but if I'm understanding this right, what I currently have is a vector of pointers pointing to the locations of my Word objects, which I have dynamically assigned.

Part of my confusion possibly comes from the question -- Do I need to put objects into the vector of pointers? Or do I make pointers to the objects and put those pointers in the vector of pointers?

Anyways, as you can see i'm trying to figure out the correct way to output the word. When I call it as

cout << &pWordList[i] << endl; 

this outputs a location address for each word (pointer of word?). Using

cout << (void*)pWordList[i]->getWord() << endl; 

will output a different location (pointer to the index of the vector?)

and using

cout << pWordList[i]->getWord() << endl; 

and

cout << (*pWordList[i]).getWord() << endl; 

will print out the same junk.

I am most likely doing this wrong because

pWordList[i]->getWord() 

should print out the c-string in question, but I think it is somewhere getting lost in transit and the pointer location becomes invalid. Really any advice or input would be offered.

Edit2-- As noted by Colin Basnett and T33C, I have changed the function to

/* Ask the user to enter their desired word @return Returns new dynamic char containing inputted word */ char* promptWord() { char* inputWord = new char[MAX_WORD_LENGTH]; cin.getline(inputWord, MAX_WORD_LENGTH); return inputWord; } 

and I am now able to output the right thing. Still wondering about the two different locations coming from &pWordList[i] and (void*)pWordList[i]->getWord()

Edit3-- Here is my method containing my non-working map. It should sort the vector and create a map with the word (which is actually the pointer to the word) and the amount of times it occurrs. However, it just sorts it. It prints out each word with an occurrence of 1, even if the same word was entered multiple times. This is because it's actually inserting the pointer to the word, not the word itself, into the key section.

void measureVector(vector<Word*> ourVector, int numOfElements) { int count = 0; bool isDone = false; qsort(&ourVector[0], ourVector.size(), sizeof(Word*), wordCompare); map<Word*, int> wordCount; for (int i = 0; i < ourVector.size(); i++) { wordCount[ourVector[i]]++; } for (auto const& wc : wordCount) { cout << wc.first->getWord() << " appears " << wc.second << " times." << endl; } } 

I have tried changing

for (int i = 0; i < ourVector.size(); i++) { wordCount[ourVector[i]]++; } 

to

for (int i = 0; i < ourVector.size(); i++) { wordCount[ourVector[i]->getWord()]++; } 

However, that gives an error stating

'[': no operator found which takes a right-hand operand of type 'const char *' (or there is no acceptable conversion) 

Edit4-- I emailed my professor again seeing if creating a map of strings and converting the char* to a string and he said that I could, so here is the updated measureVector method incase anyone else was following this.

/* Sorts our vector of pointers and puts all words into a map and keeps track of each word's occurrence. @params inputVector -> The vector of pointers to utilize. */ void measureVector(vector<Word*> inputVector) { /* Sort our vector of pointers */ qsort(&inputVector[0], inputVector.size(), sizeof(Word*), wordCompare); map<string, int> wordCount; string ourString; /* For each word in our vector, insert it into our map. */ for (auto word : inputVector) { ourString = word->getWord(); wordCount[ourString]++; } /* For each unique word in our map, print out the word and how many times it occurred.*/ for (const auto &p : wordCount) { cout << p.first << " appears " << p.second << " time" << (p.second > 1 ? "s." : ".") << endl; } } 

Thanks for the guidance, all!

4
  • You've misunderstood the requirements. The user should be able to enter a string of arbitrary length with multiple words, not just one word at a time. Work on that first, then you can get to dealing with the myriad other problems with the code. Commented May 6, 2016 at 20:30
  • I will worry about that later. For now, my main question is regarding the accessing of the vector because when I cut up the c-string later on, they will eventually still be put into the vector. I input them as single works just for simplicity for now. Commented May 6, 2016 at 20:35
  • 1
    Your promptWord function is returning a pointer to a stack location, so the value is going to be garbage as soon as the stack unwinds. You'll want to return a new'd char array from that function. Commented May 6, 2016 at 20:46
  • Thanks, that worked. Now given this, why does &pWordList[i] and (void*)pWordList[i]->getWord() output two different address while (*pWordList[i]).getWord() and pWordList[i]->getWord() return the same word? Commented May 6, 2016 at 21:00

1 Answer 1

2

There are many issues in this code but key to your question is that you are returning a pointer to a buffer on the stack which no longer exists after the function returns. Function returns unwind their stack frame.

char* promptWord() { char inputWord[MAX_WORD_LENGTH]; cin.getline(inputWord, MAX_WORD_LENGTH); return inputWord; } 

I hesitate to say declare the buffer on the heap and return a pointer to that because the whole code is quite far from where it should be for modern C++.

I recommend using:

  1. std::string and returning that instead of a char*
  2. never use new outside of a smart pointer (or something that will guarantee to call delete) see std::unique_ptr but std::string will be a better option in your case.

All the best with your studies.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. Colin Basnett pointed this out and I got it to output the word correctly. I cannot use std::string as the words must be a c-string, granted by the requirements. I understand the code is "primitive", but I am doing everything that we have learned in the course so far. Keep in mind this is a first level C++ course. I have taken some things from doing research, but most of it is how it was taught to us
@Carousser - you are welcome, thanks for accepting my answer. You can get a pointer to a C string from std::string by calling the c_str() method which returns a const char*. C++ has undergone many change recently making it a much safer and easier language to programme. I highly recommend reading Scott Meyers and Bjarne Stroustrup's latest books and keeping ahead of the competition! :)
I emailed my professor asking if I could do that, and he said we could not. However, I got it all to work and sorts the vector of pointers. My last thing is counting the occurrences, and I looked into maps, but I'm having a tough time counting the actual occurrence of the word, and not just the pointer. I'm going to update the main thread. If you have a moment, could you offer more insight into that? And I will definitely add that book to my list!
@Carousser - store the occurrence count in the value of the map. If the pointers are sorted then why not iterate through the vector and just count how many consecutive words are the same?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.