Question

Currently I am getting an runtime "assertation error"

Here is the error:

enter image description here

I'm reading words from a text file into dynamically allocated arrays. this block of code is where I am filling the new arrays.

I know the problem is being caused by this block of code and something about my logic is off just can't see what it is.

  //fill new arrays
    for( int y = 0; y < new_numwords; y++)
    {
        for( int i = 0; i < NUM_WORDS; i++)
        {
            if (!strcmp(SentenceArry[i], EMPTY[0]) == 0)
            {
            New_SentenceArry[y] = SentenceArry[i];
            New_WordCount[y] = WordCount[i];
            y++;
            }
        }
    }

Also how would I pass this dynamically allocated 2D array to a function? (the code really needs to be cleaned up as a whole)

char** SentenceArry = new char*[NUM_WORDS]; //declare pointer for the sentence
for( int i = 0; i < NUM_WORDS; i++)
{
SentenceArry[i] = new char[WORD_LENGTH];
}

Here is the full extent of the code.. help would be much appreciated!

Here is what is being read in:enter image description here

and the current output (the output is how it's suppose to be ):enter image description here

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
#include <iomanip>

using std::setw;
using std::left;

using std::cout;
using std::cin;
using std::endl;

using std::ifstream;


int main()
{

const int NUM_WORDS = 17;//constant for the elements of arrays 
const int WORD_LENGTH = 50;//constant for the length of the cstrings (NEED TO GIVE THE VALUE ZERO STILL!)
short word_entry = 0; //declare counter
short new_numwords= 0; //declare new word count
char EMPTY[1][4]; //NULL ARRAY
EMPTY[0][0] = '\0';//define it as null


char** SentenceArry = new char*[NUM_WORDS]; //declare pointer for the sentence
for( int i = 0; i < NUM_WORDS; i++)
{
SentenceArry[i] = new char[WORD_LENGTH];
}

int WordCount[NUM_WORDS];//declare integer array for the word counter

for(int i = 0; i < NUM_WORDS; i++)//fill int array
{
WordCount[i] = 1;
}

int New_WordCount[NUM_WORDS] = {0};

ifstream read_text("DataFile.txt"); //read in our text file

    if (read_text.is_open()) //check if the the file was opened
    {
        read_text >> SentenceArry[word_entry];

        //REMOVE PUNCTUATION BEFORE BEING READ INTO THE ARRAY
        while (!read_text.eof()) 
        {

        word_entry++; //increment counter
        read_text >> SentenceArry[word_entry]; //read in single words of the text file into the array SentenceArry

        char* ptr_ch;//declare our pointer that will find chars

        ptr_ch = strstr( SentenceArry[word_entry], ",");//look for "," within the array

        if (ptr_ch != NULL)//if true replace it with a null character
            {
            strncpy( ptr_ch, "\0" , 1);
            }//end if
                else
                    {

                    ptr_ch = strstr( SentenceArry[word_entry], ".");//look for "." within the array

                        if (ptr_ch != NULL)//if true replace it with a null character
                            {
                            strncpy( ptr_ch, "\0" , 1);
                            }//end if
                    }//end else
            } //end while
    }//end if

    else 
    {
        cout << "The file could not be opened!" << endl;//display error message if file doesn't open
    }//end else

read_text.close(); //close the text file after eof



//WORD COUNT NESTED FOR LOOP
for(int y = 0; y < NUM_WORDS; y++)
{
    for(int i = y+1; i < NUM_WORDS; i++)
    {
        if (strcmp(SentenceArry[y], EMPTY[0]) == 0)//check if the arrays match
        {
            y++;

        }
        else
        {
            if (strcmp(SentenceArry[y], SentenceArry[i]) == 0)//check if the arrays match
            {
                WordCount[y]++;
                strncpy(SentenceArry[i], "\0" , 3);
            }//end if
        }//end if
    }//end for
}//end for


//find how many arrays still contain chars
for(int i = 0; i < NUM_WORDS; i++)
{
    if (!strcmp(SentenceArry[i], EMPTY[0]) == 0) 
    {
    new_numwords++;
    }
}


//new dynamic array
char** New_SentenceArry = new char*[new_numwords]; //declare pointer for the sentence
for( int i = 0; i < new_numwords; i++)
{
New_SentenceArry[i] = new char[new_numwords];
}



//fill new arrays
for( int y = 0; y < new_numwords; y++)
{
        for( int i = 0; i < NUM_WORDS; i++)
        {
        if (!strcmp(SentenceArry[i], EMPTY[0]) == 0)
        {
        New_SentenceArry[y] = SentenceArry[i];
        New_WordCount[y] = WordCount[i];
        y++;
        }
    }
}

//DISPLAY REPORT
cout << left << setw(15) << "Words" << left << setw(9) << "Frequency" << endl;
for(int i = 0; i < new_numwords; i++) //compare i to the array constant NUM_WORDS
{
cout << left << setw(15) << New_SentenceArry[i] << left << setw(9) << New_WordCount[i] << endl; //display the contents of the array SentenceArry
}


//DEALLOCATION
for( int i = 0; i < NUM_WORDS; i++)//deallocate the words inside the arrays
{
    delete [] SentenceArry[i];
}

for(int i = 0; i < new_numwords; i++)
{
delete [] New_SentenceArry[i];
}

delete [] SentenceArry; //deallocate the memory allocation made for the array SentenceArry
delete [] New_SentenceArry;//deallocate the memory allocation made for the array New_SentenceArry

}//end main
Was it helpful?

Solution

There are several issues with the code, not withstanding that this could be written using C++, not C with a sprinkling of C++ I/O..

Issue 1:

Since you're using c-style strings, any copying of string data will require function calls such as strcpy(), strncpy(), etc. You failed in following this advice in this code:

for( int y = 0; y < new_numwords; y++)
{
    for( int i = 0; i < NUM_WORDS; i++)
    {
        if (!strcmp(SentenceArry[i], EMPTY[0]) == 0)
        {
            New_SentenceArry[y] = SentenceArry[i]; // This is wrong
            New_WordCount[y] = WordCount[i];   
            y++;
        }
    }
}

You should be using strcpy(), not = to copy strings.

strcpy(New_SentenceArry[y], SentenceArry[i]);

Issue 2:

You should allocate WORD_LENGTH for both the original and new arrays. The length of the strings is independent of the number of strings.

char** New_SentenceArry = new char*[new_numwords]; //declare pointer for the sentence
for( int i = 0; i < new_numwords; i++)
{
    New_SentenceArry[i] = new char[new_numwords];
}

This should be:

char** New_SentenceArry = new char*[new_numwords]; //declare pointer for the sentence
for( int i = 0; i < new_numwords; i++)
{
    New_SentenceArry[i] = new char[WORD_LENGTH];
}

Issue 3:

Your loops do not check to see if the index is going out of bounds of your arrays.

It seems that you coded your program in accordance to the data that you're currently using, instead of writing code regardless of what the data will be. If you have limited yourself to 17 words, where is the check to see if the index goes above 16? Nowhere.

For example:

while (!read_text.eof() )

Should be:

while (!read_text.eof() && word_entry < NUM_WORDS) 

Issue 4:

You don't process the first string found correctly:

read_text >> SentenceArry[word_entry];  // Here you read in the first word
while (!read_text.eof() ) 
{
     word_entry++; //increment counter
     read_text >> SentenceArry[word_entry]; // What about the first word you read in?

Summary:
Even with these changes, I can't guarantee that the program won't crash. Even it it doesn't crash with these changes, I can't guarantee it will work 100% of the time -- a guarantee would require further analysis.

The proper C++ solution, given what this assignment was about, is to use a std::map<std::string, int> to keep the word frequency. The map would automatically store similar words in one entry (given that you remove the junk from the word), and would bump up the count to 1 automatically, when the entry is inserted into the map.

Something like this:

#include <string>
#include <map>
#include <algorithm>

typedef std::map<std::string, int> StringMap;
using namespace std;

bool isCharacterGarbage(char ch)
{ return ch == ',' || ch == '.'; }

int main()
{
   StringMap sentenceMap;
   //...
   std::string temp;
   read_text >> temp;
   temp.erase(std::remove_if(temp.begin(), temp.end(), isCharacterGarbage),temp.end());
   sentenceMap[temp]++;
   //...
}

That code alone does everything your original code did -- keep track of the strings, bumps up the word count, removes the junk characters from the word before being processed, etc. But best of all, no manual memory management. No calls to new[], delete[], nothing. The code just "works". That is effectively 5 lines of code that you would just need to write a "read" loop around.

I won't go through every detail, you can do that for yourself since the code is small, and there are vast amounts of resources available explaining std::map, remove_if(), etc.

Then printing out is merely going through the map and printing each entry (string and count). If you add the printing, that may be 4 lines of extra code. So in all, practically all of the assignment is done with effectively 10 or so lines of code.

OTHER TIPS

Remove below code.

for(int i = 0; i < new_numwords; i++)
{
 delete [] New_SentenceArry[i];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top