C++ 尝试检查char*是否为double时发生访问冲突

C++ 尝试检查char*是否为double时发生访问冲突,c++,access-violation,C++,Access Violation,大家好。我在运行时出错。我正在尝试检查令牌是否为双精度令牌,但收到错误“错误:0x40516B处的访问冲突:读取地址0x0”。。什么原因导致错误?我可以做些什么来防止错误?有没有其他方法可以检查令牌是双精度的还是字母数字的?谢谢 #include <iostream> #include <conio> #include <string> #include <ctype> #include <stdlib> char statement

大家好。我在运行时出错。我正在尝试检查令牌是否为双精度令牌,但收到错误“错误:0x40516B处的访问冲突:读取地址0x0”。。什么原因导致错误?我可以做些什么来防止错误?有没有其他方法可以检查令牌是双精度的还是字母数字的?谢谢

#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();
}
#包括
#包括
#包括
#包括
#包括
char语句[256];
字符串语句;
字符串变量名[5];
双值[5];
int计数器=0;
双结果=0;
字符串stmtFormat=“”;
字符*代币;
字符串新闻字符串;
布尔值是双倍的(字符*toCheck)
{
bool valid=true;
对于(int i=0;i
错误的原因是什么

在while循环开始时执行两次
tokens=strtok(NULL,“”;
看起来非常错误:

 tokens = strtok (statement," ");
 while(tokens!= NULL)
 {
     tokens = strtok(NULL ," "); // tokens might become NULL here!
IMHO将其放入
for
循环中更具可读性和安全性:

 for(tokens = strtok (statement," "); tokens != NULL; strtok (NULL ," "))
 {
    // ...
 }
请注意,
tokens
在while循环中调用后可能会变为
NULL
,并未经检查传递给
else
部分中的
isDouble()
。这很可能是您的问题

我能做些什么来防止这个错误呢


在取消引用之前,请始终检查非空值的指针。<>代码> ISALPHA/<代码>,<代码> ISDigi> <代码>,或<代码> ISALNUM < /C> >可以在循环中的特定字符中使用,但我会使用<代码> STD::String ,如果可能的话,使用更多的C++。 也就是说,您的AV是由这样一个事实造成的:您最终将没有更多的字符串令牌可检索,
strtok
将返回NULL,并且您不希望使用
operator[]
访问NULL ptr……您可以在isDouble方法中添加NULL检查作为一种快速破解:

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;
}

有许多问题:

1:一开始,全局变量似乎是个好主意。
他们不是,把他们赶走

2:您正在修改的变量与您在
isDouble
中想象的不同
内部声明隐藏了外部声明

3:您正在将
字符*
与文字进行比较。
不要这样做,这是指针比较。没有一个比较是正确的

4:在检查结果是否为
NULL

(一个常见的初学者误解是,一旦条件为假,循环就会停止。它不会停止。)
最后一次,当它为
NULL
时,可能是您崩溃的时候。

将调用移到循环内,使其成为最后一个而不是第一个。

读取地址0x0
表示您正在尝试取消引用
null
指针。为什么要使用
tokens=strtok(null,”)
标记上的
?此外,
检查语法
无法比较两个符号为
=
的字符串:使用
strcmp()
相反。您提出了一个模糊的问题,在这里丢弃了大量代码,并且没有提供导致失败的输入。您甚至没有费心去修剪代码中不相关的部分。您得到的任何回答都将是一种极端慷慨的行为。
  char* tokens = strtok (statement, " ");
  while (tokens != NULL)
  {
    // do stuff
    tokens = strtok (NULL, " ");
  }