runtime error?

why would this test case cause this error

terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr: __pos (which is 18446744073709551615) > this->size() (which is 91)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//libraries
#include <fstream> //file IO
#include <iostream>
using namespace std;

//Programmer defined data types
//NONE

//Special compiler dependent definitions
//NONE

//global constants/variables
//NONE

//Programmer defined functions
void introduction(string obj, string ins);  //user introduction
void readFile(string iFileName); //reads file
string getFileName(string iOf, string dF); //get name of input and output file
int processLine(int atCnt, string lineFromFile); //checks lines for @
bool isValidEmailChar (char chck); //checks char and validates it

//main program
main()
{
  //Data
  string objective = "print any line with an @."; //program objective
  string instructions = "Input file name to print and count any line with @s in it, hit enter to select default file names"; //user instructions
  string iFileName; //input file name
  string dFileName = "fileContainingEmails.txt"; //default file name
  string oFileName; //output file name
  string eKey; //enter key 
  
  //user introduction
  introduction(objective, instructions); 
  
  //input & output file names
  iFileName = (getFileName("input", dFileName)); //set input file based on user input from getFileName subprogram
  if (iFileName == dFileName)  //check if default input name was selected
  dFileName = "copyPasteMyEmails.txt"; //set default output file
  else //if default wasnt chosen
  dFileName = iFileName; //set default output file based on user input from getFileName subprogram
  oFileName = (getFileName("output", dFileName)); //set output file based on user input from getFileName subprogram
  
  //output both file names
  cout <<"Input file:" << iFileName << endl; //output input file name to console
  cout <<"Output file:" << oFileName <<endl; //output output file name to console

  //enter to continune
  cout << endl << "Press ENTER key to continue: " << endl; //output prompt to press enter
  getline(cin, eKey); //user input

  //read input file
  readFile(iFileName);

  //enter to continune
  cout << endl << "Press ENTER key to continue: " << endl; //output prompt to press enter
  getline(cin, eKey); //user input
  
}//main

// user introduction
void introduction(string obj, string ins)
{
  //data
  //obj is the program objective
  //ins is the user instructions

  //output user introduction
  cout << "Objective: This program will " << obj << endl; 
  cout << "Programmer: Prosper\n"; 
  cout << "Editor(s) used: Notepad\n"; 
  cout << "Compiler(s) used: TDM MinGW\n"; 
  cout << "File: " << __FILE__ << endl; 
  cout << "Complied: " << __DATE__ << " at " << __TIME__ << endl; 
  cout << ins << endl << endl;
}//introduction

//getFileName
string getFileName(string iOf, string dF)
{
  //data
  //iOf is input or output label
  //df is default file name
  int iV = 0; //checking in filename is valid, 1 is not valid, 0 is not valid
  string iFileName; //user input

  //output
  do
  {
    cout <<"Enter an " << iOf << " filename [default:" << dF << "]:" ; //output variable prompt
    getline(cin, iFileName); //user input
    cout << endl; //blank line
    
    //input validation
    if (iFileName.length() == 0) //if user pressed enter selecting default
    { 
      iV++; //validate by changing iV to one
    }
    else if (iFileName.length() >= 5 && iFileName.substr(iFileName.length()-4,4)==".txt") //if input is at least 5 digits long and ends in .txt
    {
      dF = iFileName; //set default file name to user input
      iV++; //validate by changing iV to one
    }
    else // if input is not valid
    {
      cout <<"Invalid input. Make sure your file name ends in '.txt'" <<endl; //output user file name error and tryagain
    }
  }while (iV != 1); //while input is not valid
  return dF; //return user input
} //getFileName

//readFile
void readFile(string iFileName)
{
  //data
  //iFileName is the user-specified input file
  string lineFromFile; //current line being checked
  int atCnt; //#@ in the file count
  
  //open input file
  ifstream fin; //reserve "fin" for use
  fin.open(iFileName.c_str()); //open specifed file from user
  if (!fin.good()) throw "I/O error"; //if file isnt open output error to console
  //
  do
  {
    getline(fin, lineFromFile); //input line from file
    atCnt = processLine(atCnt, lineFromFile);  //check the line for @s with processLine subprogram
  }while (fin.good()); //while there are lines in file to be read
  //output # of @s
  cout << "Number of valid emails: " << atCnt <<endl; //output @ count returned from processLine subProgram
}//readFile

//processLine
int processLine(int atCnt, string lineFromFile)
{
  //data
  //atCnt is the # of valid emails in the line being checked
  //lineFromFile is the line from file being checked
  int i; //loop index
  int s;
  int e;
  int dotPos;
  bool hasDot; //checking if input has a dot
  string anEmail;
  
  //do this
  for (i = 0; i < lineFromFile.length(); i++) //loop to traverse the line from file
  {
    if (lineFromFile[i] == '@') //checking if char is a @
    {
      for (s = i - 1; s > -1; s--)
      {
        if (!isValidEmailChar(lineFromFile[s])) 
	{
	  s = s + 1;
	  break;
	}
      }
      hasDot = false;
      for (e = i + 1; e < lineFromFile.length(); e++)
      {
        if (!isValidEmailChar(lineFromFile[e]))
	{
          e = e - 1;
	  break;
	}
	if (lineFromFile[e] == '.')
	{
	  dotPos = e;
	  hasDot = true;
        }
      }
      if (s < i && e > i && hasDot == true && dotPos > i + 1)
      {
        anEmail = lineFromFile.substr(s,e-s);
        cout << anEmail << endl; //output line if @ is found
        atCnt++; //count the found @
      }
    }//if
  }
  return atCnt;
}//processLine

//valid email char
bool isValidEmailChar (char chck)
{
  //data
  //char chck is the current char being checked
  if (chck >= 'a' && chck  <= 'z') return true;
  if (chck >= 'A' && chck  <= 'Z') return true;
  if (chck >= '0' && chck  <= '9') return true;
  if (chck == '@' || chck == '.' || chck == '_' || chck == '+' || chck == '-') return true;
  else return false;
}
Last edited on
First, note that the number 18446744073709551615 is precisely 264 - 1. When an unsigned number goes below 0, it wraps back around to its highest value, which for a 64-bit unsigned integer is 264 - 1.

On line 99, it looks like you're correctly making sure that the length() of the string is at least 5, but your logic in processLine may not be as defensive.

On line 176, when you pass s to substr, it is converted into a size_t, which on your platform is a 64-bit unsigned integer. If s == -1, the -1 will become the highest size_t number possible, which in your case is the 264 - 1 value.

In other words, you need to double-check your logic around line 176 and at the very least make sure you aren't passing in a negative value.
Last edited on
thank you !
Topic archived. No new replies allowed.