So I am debugging a runtime error I am getting. "string subscript out of range".
I know where the problem is and what is causing it, yet I am looking for a possible solution that will perform in a similar or identical manner without giving me the error.
Here is the code snippet to where the error occurs. Correct me if I am wrong, the problem is occurring because I am declaring a 0 length string then trying to manipulate an nth element.
std::string VsuShapeLine::GetRunwayNumber()
{
std::string name, nbstr, newnbstr, convnbstr;
int idx,idx2, num, count, pos;
char buf[3];
int idx3=-1;
name = this->GetName();
idx = name.find("ALight");
if (idx == -1)
{
idx = name.find("Lights");
idx3 = name.find_last_of("Lights");
}
idx2 = name.find('_');
idx2 +=3;
nbstr = name.substr(idx2, idx-idx2);
if (idx3 != -1)
idx3++;
else
idx3 = idx+6;
if (name.at(idx3) == 'N')
{
pos = nbstr.length();
if (isalpha(nbstr[idx-1]))
nbstr[pos-1] = _toupper(nbstr[pos-1]);
return (nbstr);
}
else if (name.at(idx3) == 'F')
{
convnbstr = nbstr.substr(0,2);
num = atoi(convnbstr.data());
num +=18;
_itoa(num, buf, 10);
newnbstr = buf;
count = nbstr.size();
if (count > 2)
{
if (nbstr.at(2) == 'l' || nbstr.at(2) == 'L')
newnbstr += 'r';
else if (nbstr.at(2) == 'r'|| nbstr.at(2) == 'R')
newnbstr += 'l';
else if (nbstr.at(2) == 'c' || nbstr.at(2) == 'C')
newnbstr += 'c';
}
pos = newnbstr.length();
if (isalpha(newnbstr[pos-1]))
newnbstr[pos-1] = _toupper(newnbstr[pos-1]);
return (newnbstr);
}
return ("");
}
Btw for whoever is interested the problem was at this line:
if (isalpha(nbstr[idx-1])
At this point nbstr is a string of length 3 and idx' value, the way my program works, is always either 9 or 10.
Also as Retired Ninja mentioned checks should be done after using the string::find function.
Related
https://leetcode.com/problems/regular-expression-matching
I was doing this practice problem (cpp) and while faster solutions are in the comments, I would like to understand why my code isn't working. This fails with s = "mississippi" and p = "mis*is*p*.". Tracing through the code, I figured it would correctly remove the first two letters, then when seeing the s* it would go through the s in the string (two of them), then remove the i in both, remove all the s (again 2) then remove all the p's (which is none, because it's compared against the i in the first string, so it should not modify that string). Finally, the '.' would match with the first p and remove both. So the final string should be "pi" and return false when the length is compared to zero.
class Solution {
public:
bool isMatch(string s, string p) {
while (s.length() > 0){
if (p.length() == 0){
return false;
}else if (p.length() == 1){
return p.compare(s) == 0 || p.at(0) == '.';
}else{
if (p.at(1) == '*'){
char c = p.at(0);
p = p.substr(2);
if (c == '.'){
return true;
}
int spot = 0;
while(spot < s.length() && s.at(spot) == c){
spot++;
}
if (spot != 0){
s = s.substr(spot);
}
}else{
if (s.at(0) != p.at(0) && p.at(0) != '.'){
return false;
}
s = s.substr(1);
p = p.substr(1);
}
}
}
return s.length() == 0;
}
};
Your logic is faulty here
return p.compare(s) == 0 || p.at(0) == '.';
That should be
return p.compare(s) == 0 || (s.length() == 1 && p.at(0) == '.');
That took me five minutes to find, two minutes looking at the code without seeing the problem, and then three minutes using a debugger to track down the logic error. You really should learn to use a debugger, much more efficient than asking on SO.
Some tips here.
I'm trying to write a function that takes 4 characters,with the first and third characters being numbers,and the second and fourth characters being operators,the function converts the the first and third characters into integers,and calculates the output based on the operator between them (or doesn't do that,if the operator stored in the fourth character has a higher priority).
This is my attempt:
#include <iostream>
#include<string>
using namespace std;
string calculate(char ch1,char ch2,char ch3,char ch4);
int main() {
int i = 1;
string input = "4/1+1-2*2" ;
string part;
int leng;
while(1){
char cha1 = input[i - 1];
char cha2 = input[i];
char cha3 = input[i + 1];
char cha4 = input[i + 2];
part = calculate(cha1,cha2,cha3,cha4);
if (part == "NULL") {
i += 2;
}
else{ input = input.replace((i-1),3,part); }
leng = input.size();
if (i == leng - 1) {
i = 1;
}
}
}
string calculate(char ch1, char ch2, char ch3, char ch4){
int in1;
int in3;
int result;
string part;
if (ch2 == '-') {
if (ch4 == '*') {
part = 'NULL';
}
else if (ch4 == '/') {
part = "NULL";
}
else {
in1 = stoi(ch1);
in3 = stoi(ch3);
result = in1 - in3;
part = to_string(result);
}
}
else if (ch2 == '+') {
if (ch4 == '*') {
part = "NULL";
}
else if (ch4 == '/') {
part = "NULL";
}
else {
in1 = stoi(ch1);
in3 = stoi(ch3);
result = in1 + in3;
part = to_string(result);
}
}
else if (ch2 == '*') {
if (ch4 == '*') {
part = "NULL";
}
else if (ch4 == '/') {
part = "NULL";
}
else {
in1 = stoi(ch1);
in3 = stoi(ch3);
result = in1 * in3;
part = to_string(result);
}
}
else if (ch2 == '/') {
if (ch4 == '*') {
part = "NULL";
}
else if (ch4 == '/') {
part = "NULL";
}
else {
in1 = stoi(ch1);
in3 = stoi(ch3);
result = in1 * in3;
part = to_string(result);
}
}
return part;
}
The program probably won't work as intended in it's current state,but I'll worry about that later,for now I want to deal with the stoi() function,because for every line that contains this function,I get the error in the title.
I want to know what I'm doing wrong,and what this error message exactly means to avoid getting it in the future.
Thank you in advance.
std::stoi expects a std::string as argument, but you are giving it a single char.
There is no direct conversion from char to std::string, so you need to be explicit about it:
stoi(string(1, ch1));
Here string(1, ch1) creates a string of length 1 containing only the character ch1.
Alternatively, if you are sure that ch1 is a digit at that point (stoi will throw if it isn't) you can simply subtract '0', since the digits are guaranteed to be correctly ordered in the character set:
ch1 - '0'
Or rather, you probably want to pass a std::string directly to your function, instead of multiple individual chars. You can use the .substr member function to get substrings from a string.
std::stoi takes a std::string as its argument, but you are giving it a char.
You can directly convert char's to ints via a cast like this:
int num = ch1 - '0';
(You may want to write a function to do this, and use proper c++ style casts)
Or, covert the char to a string, or use strings to start with
Example:
int main() {
char ch1 = '9';
int in1 = ch1 - '0';
std::cout << in1 << "\n";
}
I am using the following code to break apart a line of text.
A line of text, such as
"adduser john -u 2001 -g 1002 -p john123 -c Project Work"
is passed to the constructor.
I am trying to separate the text by the commands "-u, -g, -p, -c"
"john" will be saved as name,
"2001" will be saved as UID,
"1002" will be saved as GID, etc.
AccountInfo::AccountInfo(char* line){
_line = line;
char bufferLine[256];
unsigned int length1 = 0;
unsigned int tempLength1 = 0;
//find length of line of text
while (_line[length1] != '\0'){
length1++;
}
//separate the text by white space
// start at 8 because adduser is not a command
for (int i = 8; i < length1 + 1; i++){
bufferLine[tempLength1 + 1] = '\0';
printf(bufferLine);
if (_line[i] == ' ')
{
if (bufferLine[0] == '-')
{
//test only u and c commands for now
if (bufferLine[1] == 'u'){
bufferLine[0] = '\0'; //clear contents of array
tempLength1 = 0;
while (!_line[i] == '-'){
bufferLine[tempLength1] = _line[i];
i++;
tempLength1++;
}
bufferLine[tempLength1] = '\0';
printf(bufferLine);
printf("\n This is UID \n");
setUID((unsigned int)bufferLine);
}
else if (bufferLine[1] == 'c'){
bufferLine[0] = '\0';
tempLength1 = 0;
while (!_line[i] == '\0'){
bufferLine[tempLength1] = _line[i];
i++;
tempLength1++;
}
bufferLine[tempLength1] = '\0';
printf(bufferLine);
printf("\n this is gecos \n");
setGecos(bufferLine);
}
}
else{
//is name
bufferLine[tempLength1] = '\0';
setName(bufferLine);
printf("\n I am the user's name\n");
printf(bufferLine);
printf("\n");
}
bufferLine[0] = '\0'; //reset buffer line
tempLength1 = 0; // reset incrementation for buffer line
}
else{
bufferLine[tempLength1] = _line[i];
tempLength1++;
}
}
}
I am working on functionality of the -u command. It reaches the
if (bufferLine[1] == 'u') portion of the code, but always bypasses the while loop following it
while (!_line[i] == '-') I have tried changing the '-' to exit the while loop with ' ' and even any letter 'a' 'g' 'd', however nothing works except '\0'. This is only acceptable for the -c command, as everything after it should be printed.
The -c command works as it should, as does saving the name. However, none of the other commands will work because it does not make it to the loop.
I have been thinking about this problem for a while and I believe it should work, however the code never makes it through the while loop. Is there a problem with the syntax? Or is there something I am missing about nested loops?
Thanks
This expression
while (!_line[i] == '-'){
evaluates as (see operator precedence):
while ((!(_line[i])) == '-') { // because ! has higher precedence than ==
while (false == '-') { // because _line[i] == ' ', !' ' is false
while (false) {
You probably meant
while (_line[i] != '-') {
while (!_line[i] == '-') is essentially while ((!_line[i]) == '-') (note the operators precedence).
What you possibly want is while (! (_line[i] == '-')) { or, simpler, while (_line[i] != '-'){.
!_line[i] == '-'
! has lower precedence than == and is evaluated as
(!_line[i]) == '-'
and this will never be true
http://en.cppreference.com/w/cpp/language/operator_precedence
For some reason this snippet of code keeps returning 0 even though the token actually equals any specified characters of length 1--either 'M', 'T', 'W', 'R'. Any ideas?
int storeDay(char *token, struct Section s)
{
int length = strlen(token);
cout << "length of token: " << *token << " " << length << endl;
if(length == 2)
{
if(token[0] == 'M' && token[1] == 'W')
{
s.constraints.days[0] = 1;
s.constraints.days[2] = 1;
}
else if(token[0] == 'T' && token[1] == 'R')
{
s.constraints.days[1] = 1;
s.constraints.days[3] = 1;
}
else
return 0;
}
else if(length == 1)
{
if(*token == 'M')
s.constraints.days[0] = 1;
else if(*token == 'T')
s.constraints.days[1] = 1;
else if(*token == 'W')
s.constraints.days[2] = 1;
else if(*token == 'R')
s.constraints.days[3] = 1;
else
return 0;
}
}
The question seems unclear. You are asking why it returns 0 in every case, but you do not have a return statement in every conditional path. It is more important to note whether or not the respective 'constraints' member is being set correctly. Of course, you won't be able to tell that from outside of the function because you're taking the Section object by value. Thereby, s is a copy of whatever you called storeDay with and you don't see the change in the original object.
On a test data set the following code works, but when I change to a second test set with a similar size it overflows.
To change a string of tokens into an associated new string of tokens I use this vector lookup function
//looks for input string in vector and returns output, 'c' is check row, 'r' is return row
string vectorSearch(string &check, int &direction, int n, int c, int r, int level)
{
if ((direction == 1 && check.length() <= 1) || n == list.size()-1 ||(direction == 0 && check.length() > 1)) { //if reading and string is 1 char then pass over
if (direction == 1){ //convert '???' into '?'
string temp = "";
bool wildToken = false;
for (unsigned int i = 0; i < check.length(); i++) {
temp+='?';
if (check.compare(temp) == 0) { check = '?'; wildToken = false; } //done,'???" case, return '?' token
else if (check[i] == '?') wildToken = true; //not done searching
}
}
return check;
} else {
if (list[n][c] == check || list[n][c] == ('0'+check)) //add dummy '0'
return list[n][r];
else
return vectorSearch (check, direction, n+1, c, r, level);
}
}
After working fine for a dozen conversions the stack overflows
vectorSearch is called from this function
//this function takes an ontology and direction==1 (default) changes from string
//to single char or if direction==0 takes single char and converts to string representation
string Lexicon::convertOntology(string input, int level, int direction, string out, string temp)
{
if (input == "" && temp == "")
return out; //check for completed conversion
else {
if (direction == 0 || input[0] == '.' || input[0] == '-' || input == "" ) { //found deliniator or end
if (temp == "") temp = input[0]; //condition for reverse w/o deleniators
if (input != "") return convertOntology(input.substr(1), level+1, direction,
out+=vectorSearch(temp, direction, 0, direction, 1-direction, level));
else {
string empty = "";
return convertOntology(empty, level+1, direction, out+=vectorSearch(temp, direction, 0, direction, 1-direction, level));
}
} else
return convertOntology(input.substr(1), level, direction, out, temp+=input[0]); //increment and check
}
}
The call stack is a finite resource and can be exhausted like any other. The larger your function is (with respect to creation of local variables you create inside it) the larger the amount of space each call uses on the stack. It is something that is unavoidable with recursion unless you can restrict the number of recursive calls in some way.
You can only go so deep with recursion before running out of stack space. Luckily, any recursive function can be re-written to be iterative. I believe the below is a correct iterative implementation of your vectorSearch, I'll leave the latter one to you.
string vectorSearch(string &check, int &direction, int n, int c, int r, int level)
{
while(true)
{
if ((direction == 1 && check.length() <= 1) || n == list.size()-1 ||(direction == 0 && check.length() > 1)) { //if reading and string is 1 char then pass over
if (direction == 1){ //convert '???' into '?'
string temp = "";
bool wildToken = false;
for (unsigned int i = 0; i < check.length(); i++) {
temp+='?';
if (check.compare(temp) == 0) { check = '?'; wildToken = false; } //done,'???" case, return '?' token
else if (check[i] == '?') wildToken = true; //not done searching
}
}
return check;
} else if (list[n][c] == check || list[n][c] == ('0'+check)) {//add dummy '0'
return list[n][r];
}
n++;
}
}
thank you to the reviews and comments.
The functions are fine - this recursive function bundle requires that the string exists in the database it acts an, and the string checks prior to these incorrectly recognized a special condition and inserted a dummy char. There is the recursive function that precedes these two - I did not correctly see that I had written a bundle of three recursive functions - and that one was searching within parameters for a string longer than what exists in the database; apparently the parameters were wider than the stack. Checked into the parameters and one was not updated and was not controlling.
I fixed the special condition, the strings are now the same length and the search parameters are fixed.
the functions posted are not too complex.