Domanda

Good day everyone. I'm having an error at runtime. I'm trying to check if the token is double but I'm receiving an error "Fault: access violation at 0x40516B: read of address 0x0".. What causes the error and what can I do to prevent the error? is there any other way to check if a token is double or alphanumeric? thanks..

#include <iostream>
#include <conio>
#include <string>
#include <ctype>
#include <stdlib>

char statement[256];
string strStatement;
string variableName[5];
double values[5];
int counter = 0;
double result=0;
string stmtFormat =" ";
char * tokens;
string newString;

bool isDouble(char *toCheck)
{
  bool valid = true;
  for(int i=0 ; i <(sizeof(toCheck)/sizeof(toCheck[0]));i++)
  {
    if((i!=0 && toCheck[i]=='-')||(toCheck[i]!='0'||toCheck[i]!='1'||toCheck[i]!='2'||toCheck[i]!='3'||toCheck[i]!='4'||toCheck[i]!='5'||toCheck[i]!='6'||toCheck[i]!='7'||toCheck[i]!='8'||toCheck[i]!='9'))
    {
      bool valid = false;
      cout<<"invalid number";
      break;
    }
  }
  return valid;
}

void checkGrammar(string strStatement)
{    
  if(strStatement == "print;")
  {
    cout<<"-----Output of the program-----"<<endl;
    cout<<"The result is "<<result;
  }
  else
  {
    tokens = strtok (statement," ");
    while(tokens!= NULL)
    {
      tokens = strtok(NULL ," ");
      if (tokens == "    " ){stmtFormat = stmtFormat+"<opr>";}
      else if (tokens == "-" ){stmtFormat = stmtFormat+"<opr>";}
      else if (tokens == "*" ){stmtFormat = stmtFormat+"<opr>";}
      else if (tokens == "/" ){stmtFormat = stmtFormat+"<opr>";}
      else if (tokens == "^" ){stmtFormat = stmtFormat+"<opr>";}
      else if (tokens == ";"){stmtFormat = stmtFormat+"<end>";}
      else //not operands or end
      {
        if (isDouble(tokens)){stmtFormat = stmtFormat+"<val>";}
        else{}
      }
    }
  }
}

main(void)
{
  cout <<"\nInstructions: you can declare up to 5 variables. use this syntax: \n \"num var_name = value ; \" (without the \"\")    "<<endl;
  cout <<"use , instead of . for decimals.   \n";
  cout <<"Afterwards, type the expression that you want."<<endl;
  cout <<"To print;, just type: print"<<endl;
  cout <<"Let's start!\n\n";
  while(strStatement != "print;")
  {
    cout<< ">";
    cin    getline(statement, 256);
    strStatement = statement;
    checkGrammar(strStatement);
  }
  getch();
}
È stato utile?

Soluzione

What causes the error

Doing tokens = strtok(NULL ," "); twice at the beginning of the while loop looks pretty wrong:

 tokens = strtok (statement," ");
 while(tokens!= NULL)
 {
     tokens = strtok(NULL ," "); // tokens might become NULL here!

IMHO it's better readable and more safe to put this in a for loop:

 for(tokens = strtok (statement," "); tokens != NULL; strtok (NULL ," "))
 {
    // ...
 }

Note that tokens may become NULL after the call inside the while loop, and is passed unchecked to isDouble() in the else part. This might quite probably be your problem.

and what can I do to prevent the error?

Always check pointers for non NULL values before dereferencing them.

Altri suggerimenti

isalpha, isdigit, or isalnum in <cctype> can be used for specific characters in a loop like you have but I'd use std::string and more C++ if possible.

That said your AV is caused by the fact the you will eventually have no more string tokens to retrieve and strtok will return NULL and you don't want to be accessing a nullptr with operator[] ... you can add a null check in your isDouble method as a quick hack:

bool isDouble(char *toCheck)
{
  bool valid = toCheck != 0;
  if ( valid ) {
   for(int i=0 ; i <(sizeof(toCheck)/sizeof(toCheck[0]));i++)
   {
    if((i!=0 && toCheck[i]=='-')||(toCheck[i]!='0'||toCheck[i]!='1'||toCheck[i]!='2'||toCheck[i]!='3'||toCheck[i]!='4'||toCheck[i]!='5'||toCheck[i]!='6'||toCheck[i]!='7'||toCheck[i]!='8'||toCheck[i]!='9'))
      {
        bool valid = false;
         cout<<"invalid number";
         break;
      }
   }}
   return valid;
}

however catching it in the loop may be better

  char* tokens = strtok (statement, " ");
  while (tokens != NULL)
  {
    // do stuff
    tokens = strtok (NULL, " ");
  }

There are a number of problems:

1: Global variables usually seem like a good idea at first.
They're not. Get rid of them.

2: You're modifying a different variable than you think in isDouble.
The inner declaration hides the outer one.

3: You're comparing a char* to a literal.
Don't do that, it's a pointer comparison. None of the comparisons will be true.

4: You're calling strtok after checking if the result was NULL.
(A not uncommon beginners' misunderstanding is that a loop will stop as soon as the condition is false. It won't.)
The last time, when it is NULL, is probably when you crash.
Move the call inside the loop so it's last instead of first.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top