0

I'm attempting to take an input from the command line and then convert it to lower case. To do this, I've written:

istream& operator>>(istream& is, Card& c)
{
    static map<string,Card::Rank> mr = createmr();
    static map<string,Card::Suit> ms = createms();

    string srank, c1, ssuit;

    if (is >> srank >> c1 >> ssuit)
    {
        if (c1 == "of")
        {
            string nsrank;
            string nssuit;
            for(unsigned int i = 0; i < srank.length(); i++) {
                char temp = srank[i];
                nsrank[i] = tolower(srank[i]);
            }

It fails on the second iteration of that for loop (more precisely, it fails on nsrank[i] = tolower(srank[i]);). The error that is displayed is "string substring out of range" but I don't understand how this could be the case as there are definitely still characters left in the string.

To give an example: If I enter "Ace of Spades" then it will iterate through the first time (when i=0) and transfer the 'a' fine. However, it then goes back through with i equaling 1 (which should refer to the 'c') but instead it tells me the substring is out of range (even though the assignment to the char temp works fine). During debugging, "nsrank" claims a size of 15 so I don't see how that could be out of range either....

Kyle Hale
  • 7,912
  • 1
  • 37
  • 58
The General
  • 1,239
  • 2
  • 17
  • 28
  • 2
    I'd say the problem is in the `nsrank[i]` the `string nsrank` [creates an empty string](http://www.cplusplus.com/reference/string/string/string/). – jsantander Apr 11 '14 at 07:04
  • In addition of @jsantander comment, you really have the problem in all interations (in despite the runtime only detected it at the second one): `nsrank[i]` is an out of range access for all `i`, since `nsrank` is not initialized, so its size is 0. – Gonmator Apr 11 '14 at 07:09

2 Answers2

2

The problem is that nsrank is an empty string, so accessing with operator[]....

If pos is not greater than the string length, the function never throws exceptions (no-throw guarantee). Otherwise, it causes undefined behavior.

This one worked for me: http://ideone.com/3LcYqv

#include <iostream>
using namespace std;

int main() {
    string srank="Ace of Spades";
    string nsrank;

    nsrank.resize(srank.length());

            for(unsigned int i = 0; i < srank.length(); i++) {
                char temp = srank[i];
                nsrank[i] = tolower(srank[i]);
            }
    cout << nsrank << endl;
    return 0;
}

The key is the resize to make nsrank the same size as srank.

Edit: Added compact solution

From many places, among them from this answer

#include <algorithm>
#include <string>

string srank="Ace of Spades";
string nsrank=srank;
std::transform(nsrank.begin(), nsrank.end(),nsrank.begin(), ::toupper);
Community
  • 1
  • 1
jsantander
  • 4,972
  • 16
  • 27
0

resize nsrank to match size of srank before entering the loop

Dr. Debasish Jana
  • 6,980
  • 4
  • 30
  • 69