User Input That Involves A ' ' Causes A Substring Out Of Range Error

Posted by Greenhouse Gases on Stack Overflow See other posts from Stack Overflow or by Greenhouse Gases
Published on 2010-04-18T21:27:27Z Indexed on 2010/04/18 21:33 UTC
Read the original article Hit count: 454

Filed under:

Hi Stackoverflow people. You have already helped me quite a bit but near the end of writing this program I have somewhat of a bug. You see in order to read in city names with a space in from a text file I use a '/' that is then replaced by the program for a ' ' (and when the serializer runs the opposite happens for next time the program is run). The problem is when a user inputs a name too add, search for, or delete that contains a space, for instance 'New York' I get a Debug Assertion Error with a substring out of range expression.

I have a feeling it's to do with my correctCase function, or setElementsNull that looks at the string until it experiences a null element in the array, however ' ' is not null so I'm not sure how to fix this and I'm going a bit insane. Any help would be much appreciated. Here is my code:

// U08221.cpp : main project file.

#include "stdafx.h"

#include <_iostream>
#include <_string>
#include <_fstream>
#include <_cmath>

using namespace std;


class locationNode
{
public:
    string nodeCityName;
    double nodeLati;
    double nodeLongi;

    locationNode* Next;

    locationNode(string nameOf, double lat, double lon)
    {
        this->nodeCityName = nameOf;
        this->nodeLati = lat;
        this->nodeLongi = lon;
        this->Next = NULL;
    }

        locationNode() // NULL constructor
    {
    }

    void swapProps(locationNode *node2)
    {
        locationNode place;

        place.nodeCityName = this->nodeCityName;
        place.nodeLati = this->nodeLati;
        place.nodeLongi = this->nodeLongi;

        this->nodeCityName = node2->nodeCityName;
        this->nodeLati = node2->nodeLati;
        this->nodeLongi = node2->nodeLongi;

        node2->nodeCityName = place.nodeCityName;
        node2->nodeLati = place.nodeLati;
        node2->nodeLongi = place.nodeLongi;

    }

    void modify(string name)
    {
        this->nodeCityName = name;
    }

    void modify(double latlon, int mod)
    {
        switch(mod)
        {
        case 2:
        this->nodeLati = latlon;
        break;

        case 3:
        this->nodeLongi = latlon;
        break;
        }
    }


void correctCase() // Correct upper and lower case letters of input
    {

        int MAX_SIZE = 35;
        int firstLetVal = this->nodeCityName[0], letVal;
        int n = 1; // variable for name index from second letter onwards


        if((this->nodeCityName[0] >90) && (this->nodeCityName[0] < 123)) // First letter is lower case
        { 
             firstLetVal = firstLetVal - 32; // Capitalise first letter
             this->nodeCityName[0] = firstLetVal;
        }

        while(this->nodeCityName[n] != NULL)
        {
            if((this->nodeCityName[n] >= 65) && (this->nodeCityName[n] <= 90))
            {
                if(this->nodeCityName[n - 1] != 32)
                {
                letVal = this->nodeCityName[n] + 32;
                this->nodeCityName[n] = letVal;
                }
            }
            n++;
        }

    }



};

Here is the main part of the program:

// U08221.cpp : main project file.

#include "stdafx.h"
#include "Locations2.h"
#include <_iostream>
#include <_string>
#include <_fstream>
#include <_cmath>

using namespace std;

#define pi 3.14159265358979323846264338327950288
#define radius 6371
#define gig 1073741824  //size of a gigabyte in bytes

int n = 0,x, locationCount = 0, MAX_SIZE = 35 , g = 0, i = 0, modKey = 0, xx; 
string cityNameInput, alter;
char targetCity[35], skipKey = ' ';
double lat1, lon1, lat2, lon2, dist, dummy, modVal, result;
bool acceptedInput = false, match = false, nodeExists = false;// note: addLocation(), set to true to enable user input as opposed to txt file

locationNode     *temp, *temp2, *example, *seek, *bridge, *start_ptr = NULL;


class Menu
{

int junction;

public:

/* Convert decimal degrees to radians */
public:
void setElementsNull(char cityParam[])
{
    int y=0;
    while(cityParam[y] != NULL)
    {
        y++;
    }

    while(y < MAX_SIZE)
    {
        cityParam[y] = NULL;
        y++;
    }
}

void correctCase(string name) // Correct upper and lower case letters of input
    {

        int MAX_SIZE = 35;
        int firstLetVal = name[0], letVal;
        int n = 1; // variable for name index from second letter onwards


        if((name[0] >90) && (name[0] < 123)) // First letter is lower case
        { 
             firstLetVal = firstLetVal - 32; // Capitalise first letter
             name[0] = firstLetVal;
        }

        while(name[n] != NULL)
        {
            if((name[n] >= 65) && (name[n] <= 90))
            {
                letVal = name[n] + 32;
                name[n] = letVal;
            }
            n++;
        }

        for(n = 0; targetCity[n] != NULL; n++)
        {
        targetCity[n] = name[n];
        }
    }

bool nodeExistTest(char targetCity[]) // see if entry is present in the database
{

    match = false;

    seek = start_ptr;

    int letters = 0, letters2 = 0, x = 0, y = 0;


    while(targetCity[y] != NULL)
    {
        letters2++;
        y++;
    }



while(x <= locationCount) // locationCount is number of entries currently in list
{
    y=0, letters = 0;
    while(seek->nodeCityName[y] != NULL) // count letters in the current name
    {
        letters++;
        y++;
    }


    if(letters == letters2) // same amount of letters in the name
    {
        y = 0;

            while(y <= letters) // compare each letter against one another
                {

                    if(targetCity[y] == seek->nodeCityName[y])
                        {
                            match = true;
                            y++;
                                }
                    else
                    {
                    match = false;
                    y = letters + 1; // no match, terminate comparison
                    }
                }


    }
    if(match)
    {

        x = locationCount + 1; //found match so terminate loop

    }

    else{
        if(seek->Next != NULL)
        {
        bridge = seek; 
        seek = seek->Next;
        x++;
        }
        else
        {
            x = locationCount + 1; // end of list so terminate loop
        }
    }

}
  return match;
}


double deg2rad(double deg) {
return (deg * pi / 180);
}

/* Convert radians to decimal degrees */
double rad2deg(double rad) {
return (rad * 180 / pi);
}


/* Do the calculation */

double distance(double lat1, double lon1, double lat2, double lon2, double dist) {

dist = sin(deg2rad(lat1)) * sin(deg2rad(lat2)) + cos(deg2rad(lat1)) * cos(deg2rad(lat2)) * cos(deg2rad(lon1 - lon2));
dist = acos(dist);
dist = rad2deg(dist); 
dist = (radius * pi * dist) / 180;
return dist;
}

    void serialise()
    {
        // Serialize to format that can be written to text file

    fstream outfile;

    outfile.open("locations.txt",ios::out);
    temp = start_ptr;

    do
    {
    for(xx = 0; temp->nodeCityName[xx] != NULL; xx++)
    {
        if(temp->nodeCityName[xx] == 32)
        {
            temp->nodeCityName[xx] = 47;
        }
    }
      outfile << endl  << temp->nodeCityName<< " ";
      outfile<<temp->nodeLati<< " ";
      outfile<<temp->nodeLongi;
      temp = temp->Next;
    }while(temp != NULL);

    outfile.close();

    }

    void sortList() // do this
{   

    int changes = 1;
    locationNode *node1, *node2;
    while(changes > 0) // while changes are still being made to the list execute
    {
        node1 = start_ptr;
        node2 = node1->Next;
        changes = 0;
    do
    {
        xx = 1;

        if(node1->nodeCityName[0] > node2->nodeCityName[0]) //compare first letter of name with next in list
        {
        node1->swapProps(node2); // should come after the next in the list
        changes++;
        }
        else if(node1->nodeCityName[0] == node2->nodeCityName[0])  // if same first letter
        {
        while(node1->nodeCityName[xx] == node2->nodeCityName[xx]) // check next letter of name
        {
            if((node1->nodeCityName[xx + 1] != NULL) && (node2->nodeCityName[xx + 1] != NULL)) // check next letter until not the same
            {
            xx++;
            }
            else break;
        }
        if(node1->nodeCityName[xx] > node2->nodeCityName[xx])
        {
            node1->swapProps(node2); // should come after the next in the list
            changes++;
        }
    }

        node1 = node2;
        node2 = node2->Next; // move to next pair in list
    }
    while(node2 != NULL);
    }

}
    void initialise()
    {
        cout << "Populating List...";
    ifstream inputFile;
    inputFile.open ("locations.txt", ios::in);

    char inputName[35] = " ";
    double inputLati = 0, inputLongi = 0;

    //temp = new locationNode(inputName, inputLati, inputLongi);
    do
    {

      inputFile.get(inputName, 35, ' ');

     inputFile >> inputLati;
    inputFile >> inputLongi;



        if(inputName[0] == 10 || 13) //remove linefeed from input
        {
            for(int i = 0; inputName[i] != NULL; i++)
            {
                inputName[i] = inputName[i + 1];
            }
        }



        for(xx = 0; inputName[xx] != NULL; xx++)
        {

            if(inputName[xx] == 47) // if it is a '/'
            {
                inputName[xx] = 32; // replace it for a space
            }

        }
    temp  = new locationNode(inputName, inputLati, inputLongi);

    if(start_ptr == NULL){ // if list is currently empty, start_ptr will point to this node

    start_ptr = temp;
}

else
       { temp2 = start_ptr;
         // We know this is not NULL - list not empty!
         while (temp2->Next != NULL)
           {  
               temp2 = temp2->Next; // Move to next link in chain until reach end of list
           }

         temp2->Next = temp;
       }

++locationCount; // increment counter for number of records in list

 }
  while(!inputFile.eof());



  cout << "Successful!" << endl << "List contains: " << locationCount << " entries" << endl; 


  inputFile.close();
  cout << endl << "*******************************************************************" << endl << "DISTANCE CALCULATOR v2.0\tAuthors: Darius Hodaei, Joe Clifton" << endl;

    }


    void menuInput()
    {
        char menuChoice = ' ';
    while(menuChoice != 'Q')
    {
    // Menu
        if(skipKey != 'X') // This is set by case 'S' below if a searched term does not exist but wants to be added
        {
    cout << endl << "*******************************************************************" << endl;
    cout << "Please enter a choice for the menu..." << endl << endl;
    cout << "(P) To print out the list" << endl << "(O) To order the list alphabetically" << endl << "(A) To add a location" << endl << "(D) To delete a record" << endl << "(C) To calculate distance between two points" << endl << "(S) To search for a location in the list" << endl 
         << "(M) To check memory usage" << endl << "(U) To update a record" << endl << "(Q) To quit" << endl;
    cout << endl << "*******************************************************************" << endl;
    cin >> menuChoice;

    if(menuChoice >= 97)
    {
        menuChoice = menuChoice - 32; // Turn the lower case letter into an upper case letter
    }
        }
        skipKey = ' '; //Reset skipKey so that it does not skip the menu
    switch(menuChoice)
    {
        case 'P':
            temp = start_ptr; // set temp to the start of the list
do
  {  if (temp == NULL)
  {
       cout << "You have reached the end of the database" << endl;
  }
     else
       {  // Display details for what temp points to at that stage
          cout << "Location : " << temp->nodeCityName << endl;
          cout << "Latitude : " << temp->nodeLati << endl;
          cout << "Longitude : " << temp->nodeLongi << endl;
          cout << endl;

          // Move on to next locationNode if one exists
          temp = temp->Next;
       }
  }
while (temp != NULL);
        break;

        case 'O':
            {   

                    sortList(); // pass by reference???



                cout << "List reordered alphabetically" << endl;
            }
        break;


        case 'A':

char cityName[35];
double lati, longi;

cout << endl << "Enter the name of the location: ";
cin >> cityName;

for(xx = 0; cityName[xx] != NULL; xx++)
        {

            if(cityName[xx] == 47) // if it is a '/'
            {
                cityName[xx] = 32; // replace it for a space
            }

        }
if(!nodeExistTest(cityName))
{

cout << endl << "Please enter the latitude value for this location: ";
cin >> lati;
cout << endl << "Please enter the longitude value for this location: ";
cin >> longi;
cout << endl;

temp  = new locationNode(cityName, lati, longi);
temp->correctCase();

//start_ptr allignment
if(start_ptr == NULL){ // if list is currently empty, start_ptr will point to this node

    start_ptr = temp;
}

else
       { temp2 = start_ptr;
         // We know this is not NULL - list not empty!
         while (temp2->Next != NULL)
           {  
               temp2 = temp2->Next; // Move to next link in chain until reach end of list
           }

         temp2->Next = temp;
       }

++locationCount; // increment counter for number of records in list

cout << "Location sucessfully added to the database! There are " << locationCount << " location(s) stored" << endl;

}
else
{
    cout << "Node is already present in the list and so cannot be added again" << endl;
}
        break;

        case 'D':
            {
            junction = 0;
    locationNode *place;
    cout << "Enter the name of the city you wish to remove" << endl;
    cin >> targetCity;

    setElementsNull(targetCity);
    correctCase(targetCity);
    for(xx = 0; targetCity[xx] != NULL; xx++)
    {
        if(targetCity[xx] == 47)
        {
            targetCity[xx] = 32;
        }
    }

if(nodeExistTest(targetCity)) //if this node does exist
{
    if(seek == start_ptr) // if it is the first in the list
    {
        junction = 1;
   }

    if(seek->Next == NULL) // if it is last in the list
    {
        junction = 2;
   }


switch(junction) // will alter list accordingly dependant on where the searched for link is
{
case 1:
    start_ptr = start_ptr->Next;
        delete seek;
        --locationCount;
            break;

case 2:

        place = seek;
        seek = bridge;
        seek->Next = NULL;
        delete place;
        --locationCount;
            break;

default:
    bridge->Next = seek->Next;
    delete seek;
    --locationCount;
    break;
}
cout << endl << "Link deleted. There are now " << locationCount << " locations." <<  endl;
}

else 
{   cout << "That entry does not currently exist" << endl << endl << endl;
    }
            }
break;

        case 'C':
            {
char city1[35], city2[35];

    cout << "Enter the first city name" << endl;
    cin >> city1;
    setElementsNull(city1);
    correctCase(targetCity);

if(nodeExistTest(city1))
{
lat1 = seek->nodeLati;
lon1 = seek->nodeLongi;
cout << "Lati = " << seek->nodeLati << endl << "Longi = " << seek->nodeLongi << endl << endl;
}


    cout << "Enter the second city name" << endl;
    cin >> city2;
    setElementsNull(city2);
    correctCase(targetCity);


if(nodeExistTest(city2))
{
lat2 = seek->nodeLati;
lon2 = seek->nodeLongi;
cout << "Lati = " << seek->nodeLati << endl << "Longi = " << seek->nodeLongi << endl << endl;
}

result = distance (lat1, lon1, lat2, lon2, dist);
cout <<  "The distance between these two locations is " << result << " kilometres." << endl;
            }
        break;

        case 'S':
                {
            char choice;
    cout << "Enter search term..." << endl;
    cin >> targetCity;
    setElementsNull(targetCity);
    correctCase(targetCity);

    if(nodeExistTest(targetCity))
    {
        cout << "Latitude: " << seek->nodeLati << endl << "Longitude: " << seek->nodeLongi << endl;
    }
    else
    {
        cout << "Sorry, that city is not currently present in the list." << endl << "Would you like to add this city now Y/N?" << endl;
        cin >> choice;

        /*while(choice != ('Y' || 'N'))
        {
            cout << "Please enter a valid choice..." << endl;
            cin >> choice;
        }*/

        switch(choice)
        {
        case 'Y':
            skipKey = 'X';
            menuChoice = 'A';
            break;

        case 'N':
            break;

        default :
            cout << "Invalid choice" << endl;
        break;
    }
    }
    break;
                }
        case 'M':
            {

                cout << "Locations currently stored: " << locationCount << endl <<
                    "Memory used for this: " << (sizeof(start_ptr) * locationCount) << " bytes" << endl << endl
                    << "You can store " << ((gig - (sizeof(start_ptr) * locationCount)) / sizeof(start_ptr)) << " more locations" << endl ;
                break;
            }

        case 'U':
            {   

            cout << "Enter the name of the Location you would like to update: ";
            cin >> targetCity;
            setElementsNull(targetCity);
            correctCase(targetCity);

            if(nodeExistTest(targetCity))
            {
            cout << "Select (1) to alter City Name, (2) to alter Longitude, (3) to alter Latitude" << endl; 
            cin >> modKey;

                switch(modKey)
                {
                case 1:
                cout << "Enter the new name: ";
                cin >> alter;
                cout << endl;
                seek->modify(alter);
                    break;

                case 2:
                cout << "Enter the new latitude: ";
                cin >> modVal;
                cout << endl;
                seek->modify(modVal, modKey);
                    break;

                case 3:
                cout << "Enter the new longitude: ";
                cin >> modVal;
                cout << endl;
                seek->modify(modVal, modKey);
                    break;

                default:
                    break;
                }

            }
            else cout << "Location not found" << endl;
                break;
            }

    }
        }
        }
};






int main(array<System::String ^> ^args)
{
Menu mm;
//mm.initialise();
mm.menuInput();
mm.serialise();
    }

© Stack Overflow or respective owner

Related posts about c++