在 C++ 中使用 istringstream 进行字符串到双重转换的意外结果

Posted

技术标签:

【中文标题】在 C++ 中使用 istringstream 进行字符串到双重转换的意外结果【英文标题】:Unexpected results using istringstream for string to double conversion in C++ 【发布时间】:2009-11-08 23:11:59 【问题描述】:

我目前正在尝试获取一个字符串 ("0.1") 并在 10.6 和 gcc4.2 的 Xcode 中使用 C++ 将其转换为双精度。

我正在使用从another question 中提取的函数,但是当我尝试使用该函数时,根据gdb 的输入是(字符串)“0.1”,但我的输出是(双)2.1220023981051542e-314。

这是我的 sn-p 直接复制出来的代码:

double strToDouble(std::string const &numberString)

    istringstream inStream(numberString);
    double doubleValue;
    inStream >> doubleValue;
    if(!(inStream && (inStream >> std::ws).eof()))
    
        return 0.0;  
    

    return doubleValue;
;

我使用的是 C++ 而不是 Obj-C,因为它最终可能必须在 *nix 或 windows 机器上编译。

我天生就是一个 php 程序员,但是我需要一些数字运算来加快速度,所以我用编译语言来做。大学处理低级语言已经很久了=P。所以,如果有人有想法,将不胜感激......

德鲁·J·索恩。

完整代码:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

/*
 * @var delimiters the string to define a break by
 * @var str the string to break
 * @var tokens where to store the broken string parts.
 */
void explode(const string& delimiters, const string& str, vector<string>& tokens)

    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    
;

/*
 * @var numberString double to be converted as a string.
 */
double strToDouble(std::string const &numberString)

    istringstream inStream(numberString);
    double doubleValue;
    inStream >> doubleValue;
    if(!(inStream && (inStream >> std::ws).eof()))
    
        return 0.0;  
    

    return doubleValue;
;

class Cluster 
private:
    vector<double> latStore;
    vector<double> lngStore;
public:
    Cluster(int,string,string);
;

/*
 * @var latString a comma seperated list of doubles for the latitudes.
 * @var lngString a comma separated list of doubles for the longitudes.
 */
Cluster::Cluster(int newLocationLength, string latString, string lngString)

    // mark our vectors
    vector<string> latStoreString;
    vector<string> lngStoreString;

    // Explode our input strings.
    explode(",", latString, latStoreString);
    explode(",", lngString, lngStoreString);

    for( int i = 0; i < latStoreString.size(); i++)
    
        // Grab the latitude and store it.
        string tempLat = latStoreString[i];
        double latDouble = strToDouble(tempLat);
        latStore.push_back( strToDouble(tempLat) );

        // Grab the longitude and store it.
        string tempLng = lngStoreString[i];
        lngStore.push_back( strToDouble(tempLng) );
    


int main (int argc, char * const argv[]) 

    Cluster *rect = new Cluster("0.1,0.4","0.1,0.4");

    return 0;

【问题讨论】:

奇数。当我针对 10.6 Debug 运行此代码时,我得到了从 if 检查返回的 0.0。如果我编译 10.6 Release,一切正常。以 10.5 为目标适用于 Debug 和 Release。不知道是什么问题。 太棒了。谢谢安东尼。当我将其更改为 10.5 时,它在这里工作。我什至从来没有想过。 10.5 是然后。如果你把它作为答案,我可以标记它是正确的,你可以获得更多的 BrowniePoints™。 =P 很高兴它能让你跑步。问题的原因似乎如 cdespinosa 的回答所示。我会将其标记为已接受的答案。 【参考方案1】:

这可能是由 STL 调试模式引起的。在目标的预处理器宏构建设置中删除 _GLIBCXX_DEBUG 宏。

C++ Debug builds broke in Snow Leopard X-Code

【讨论】:

【参考方案2】:

为什么不使用 atof() 代替呢? link

【讨论】:

我查看了 atof,但后来我必须使用 c 字符串,而不是字符串对象。在字符串到双精度转换之后,双精度被转储回向量并使用 char* 和字符串似乎使水变得浑浊。所以我猜......“我可以使用 char* 和向量吗?”是另一个问题... 你可以使用你的字符串对象并调用 .c_str() 来传递给 atof。【参考方案3】:

我看不出您的代码片段有什么问题。你能显示你用来输出结果的代码

【讨论】:

【参考方案4】:

正如 Myles 所建议的, atof() 可能更简单。您可以通过调用 c_str() 成员函数将字符串对象转换为 c 字符串:

double result = atof(inputString.c_str()); // 0.0 if a double couldn't be read

这里有更多信息:http://www.cplusplus.com/reference/clibrary/cstdlib/atof/

【讨论】:

【参考方案5】:
#include <iostream>
#include <sstream>

double strToDouble(std::string const &numberString)

    std::istringstream inStream(numberString);
    double doubleValue;
    std::cout << doubleValue << '\n';
    inStream >> doubleValue;
    if(!(inStream && (inStream >> std::ws).eof()))
    
        return 0.0;  
    

    return doubleValue;
;

int main()

    std::cout << strToDouble("0.1") << '\n';

    return 0;

上面的代码给了我以下输出: -2.36907e-39 0.1

你是不是偶然在返回之前检查了 doubleValue 的值?


Cluster::Cluster(string latString, string lngString)

    // mark our vectors
    vector<string> latStoreString;
    vector<string> lngStoreString;

    // Explode our input strings.
    explode(",", latString, latStoreString);
    explode(",", lngString, lngStoreString);

    for( int i = 0; i < latStoreString.size(); i++)
    
        // Grab the latitude and store it.
        string tempLat = latStoreString[i];
        std::cout << "tempLat=" << tempLat << '\n';
        double latDouble = strToDouble(tempLat);
        std::cout << "latDouble=" << latDouble << '\n';
        latStore.push_back( strToDouble(tempLat) );

        // Grab the longitude and store it.
        string tempLng = lngStoreString[i];
        lngStore.push_back( strToDouble(tempLng) );
    


int main (int argc, char * const argv[]) 

    Cluster *rect = new Cluster("0.1,0.4","0.1,0.4");

    return 0;

输出: tempLat=0.1 latDouble=0.1 tempLat=0.4 latDouble=0.4

你能用这些修改运行代码吗(你没有在 ctor 中使用 int 参数,所以我只是删除了它)。我还使用 valgrind 运行了您的代码,没有出现错误(只有内存泄漏)。

【讨论】:

忘了提及编译器信息:g++ (Gentoo 4.3.4 p1.0, pie-10.1.5) 4.3.4 ...当我运行该代码时,我得到:6.95322e-310 0 现在我真的很困惑。 当我将其作为 10.6 运行时(请参阅对问题的评论),它可以工作,但作为 10.5,它仍然会吐出 0。我认为这是我的 IDE 的错误。 只是为了好玩,您可以尝试使用终端进行编译吗?可以将错误追溯到传递给 g++ 的特定参数。 有趣... 192-168-1-100:桌面绘制$ g++ -o test -isysroot /Developer/SDKs/MacOSX10.6.sdk main.cpp 192-168-1-100:桌面绘制$ ./test tempLat=0.1 latDouble=0.1 tempLat=0.4 latDouble=0.4 和 XCode 在下一条消息中...【参考方案6】:

看起来您没有得到关于您的实施问题的答案。其他人建议使用 atof()。如果您想在实现中解决问题,请查看以下代码。不要使用vector to explode方法,而是放置vector以避免冗余代码。我也更改了 strToDouble 中的代码。

void explode(const string& delimiters, const string& str, vector<double>& tokens)
    
     // Skip delimiters at beginning.   
     string::size_type lastPos = str.find_first_not_of(delimiters, 0);   
     // Find first "non-delimiter".    
     string::size_type pos = str.find_first_of(delimiters, lastPos);
     while (string::npos != pos || string::npos != lastPos)   
             
              // Found a token, add it to the vector.       
             string temp = str.substr(lastPos, pos - lastPos);
             tokens.push_back(strToDouble(temp));    
             // Skip delimiters.  Note the "not_of"        
            lastPos = str.find_first_not_of(delimiters, pos);        
            // Find next "non-delimiter"        
            pos = str.find_first_of(delimiters, lastPos);    
     


double strToDouble(std::string const &numberString)
  
   istringstream inStream(numberString);    
   int pos = numberString.find_first_not_of("1234567890.", 0);

   if (string::npos != pos)
   
       return 0.0;
   
   else
   
      double doubleValue;   
      inStream >> doubleValue;        
      return doubleValue;
  

【讨论】:

以上是关于在 C++ 中使用 istringstream 进行字符串到双重转换的意外结果的主要内容,如果未能解决你的问题,请参考以下文章

c++中istringstream及ostringstream超详细说明

C++ 中的流类型,如何从 IstringStream 中读取?

C++ 使用 istringstream 将整数读取为无符号字符

C++中的 istringstream 的用法

C++ ifstreamostringstream istringstream 读取并输出文件中的string

C++ ifstreamostringstream istringstream 读取并输出文件中的string