【问题标题】:While loop is causing a stack dump and the program to crash in C++While 循环导致堆栈转储和程序在 C++ 中崩溃
【发布时间】:2013-07-25 20:16:19
【问题描述】:

我刚刚重新开始使用 C++ 进行编程。我编写了一个程序,该程序应该从文件中读取十六进制颜色,将它们与程序中标识的颜色数组进行数学比较,以确定哪个颜色最接近,然后将原始颜色和最接近的颜色写入文件。出于某种原因,在编写了大约 62,000 行左右之后,该程序以堆栈转储方式退出。我正在读取的文件中有大约 1600 万种颜色。我希望有人能用我的代码为我指出正确的方向来解决这个问题。

代码如下,我没有粘贴红色、绿色、蓝色或 pantonehexcode 的数组;但您可以假设它们分别是具有数字和十六进制字符串值的数组。

    string line;
string hexcolor, r_hex, g_hex, b_hex;

const char delim[] = " ;";
float *cie1 = new float[3];
float *cie2 = new float[3];

float r ;
float g ;
float b ;
float currentClosestVal = 1000000;
float challengeClosestVal;
int currentClosestIndex;

    ifstream file ("hexcolormaplist.txt");
if (file.fail()) 
        {cout << "Error opening infile file"; return 0;}
ofstream ofile("tpxmap.txt");
if (ofile.fail()) 
        {cout << "Error opening ofile file"; return 0;}

bool newline = true;
//Comparing colors variables
int i, k;
double Kl, K1, K2, Sl, SC, SH, dL, dA, dB, dC, dH, c1, c2;

getline (file,line);
char * cline = new char [line.length()+1];



while(newline == true){

    currentClosestVal = 1000000;
    std::strcpy (cline ,line.c_str());
    hexcolor = strtok(cline, delim);
    r_hex = strtok(NULL, delim);
    g_hex = strtok(NULL, delim);
    b_hex = strtok(NULL, delim);


    r = (float)atof(r_hex.c_str());
    g = (float)atof(g_hex.c_str());
    b = (float)atof(b_hex.c_str());

    cie1 = rgb2lab (r, g, b);



    for (i = 0; i < 2100; i++)
    {
        cie2 = rgb2lab (red[i], green[i], blue[i]);
        //challengeClosestVal = pow(cie1[0] - cie2[0], 2.0) + pow(cie1[1] - cie2[1], 2.0) + pow(cie1[2] - cie2[2], 2.0);
        dL = cie1[0] - cie2[0];
        dA = cie1[1] - cie2[1];
        dB = cie1[2] - cie2[2];
        c1 = sqrt(cie1[1] + cie1[2]);
        c2 = sqrt(cie2[1] + cie2[2]);
        dC = c1 - c2;
        dH = sqrt(pow(dA, 2) + pow(dB,2) - pow(dC,2));
        Kl = 2;
        K1 = .048;
        K2 = .014;
        Sl = 1;
        SC = 1 + K1*c1;
        SH = 1 + K2*c1;

        challengeClosestVal = sqrt(pow(dL/(Kl*Sl), 2) + pow(dC/(Kl*SC),2) + pow(dH/(Kl*SH), 2));


        if(challengeClosestVal < currentClosestVal){
            currentClosestIndex = i;
            currentClosestVal = challengeClosestVal;
        }
    }

    ofile << hexcolor <<"; " << pantoneHexCodes[currentClosestIndex] <<";"<<endl; // prints The pantone color comparator
    line = "";
    newline = getline (file,line);

}//end of while loop

//close files
file.close();
ofile.close();
return 0;
}

float *rgb2lab (float r, float g, float b){

    float var_r, var_g, var_b;
    double X, Y, Z, var_X, var_Y, var_Z;
    float ref_X =  95.047;  //Observer= 2°, Illuminant= D65
    float ref_Y = 100.000;
    float ref_Z = 108.883;
    double cieL, cieA, cieB;
    float *cie = new float[3];



    //Convert RGB to XYZ
    //First set RGB values between 0-1
    var_r = r/255;
    var_g = g/255;
    var_b = b/255;

    if ( var_r > 0.04045 )
            var_r = pow( ( var_r + 0.055 ) / 1.055 , 2.4);
    else
            var_r = var_r / 12.92;

    if ( var_g > 0.04045 )
            var_g = pow( ( var_g + 0.055 ) / 1.055 , 2.4);
    else
            var_g = var_g / 12.92;
    if ( var_b > 0.04045 )
            var_b = pow( ( var_b + 0.055 ) / 1.055 , 2.4);
    else
            var_b = var_b / 12.92;

    var_r = var_r * 100;
    var_g = var_g * 100;
    var_b = var_b * 100;

    //Convert RGB to XYZ
    //Observer. = 2°, illuminant = D65
    X = var_r * 0.4124 + var_g * 0.3576 + var_b * 0.1805;
    Y = var_r * 0.2126 + var_g * 0.7152 + var_b * 0.0722;
    Z = var_r * 0.0193 + var_g * 0.1192 + var_b * 0.9505;

    //cout << "X: "<<X  <<"  Y: "  <<Y <<"  Z: "<<Z << endl;


    // Convert XYZ to CIELab
    var_X = X / ref_X;          //ref_X =  95.047   Observer= 2°, Illuminant= D65
    var_Y = Y / ref_Y;          //ref_Y = 100.000
    var_Z = Z / ref_Z;          //ref_Z = 108.883
    //cout << "var_X: "<<var_X  <<"  var_Y: "  <<var_Y <<"  var_Z: "<<var_Z << endl;

    if ( var_X > 0.008856 ) {
            var_X = pow(var_X, .3333333); }
    else
            var_X = ( 7.787 * var_X) + ( 16 / 116 );
    if ( var_Y > 0.008856 ){
            var_Y = pow(var_Y, .3333333); }
    else
            var_Y = ( 7.787 * var_Y) + ( 16 / 116 );
    if  ( var_Z > 0.008856 ){
            var_Z = pow(var_Z,  .3333333); }
    else
            var_Z = ( 7.787 * var_Z) + ( 16 / 116 );


    cieL = ( 116 * var_Y ) - 16;
    cieA = 500 * ( var_X - var_Y );
    cieB = 200 * ( var_Y - var_Z );

    //cout << "L: "<<cie[0]  <<"  a: "  <<cie[1] <<"  b: "<<cie[2] << endl;
    cie[0] = cieL;
    cie[1] = cieA;
    cie[2] = cieB;
    //cout << "L: "<<cie[0]  <<"  a: "  <<cie[1] <<"  b: "<<cie[2] << endl;
    return cie;

}

【问题讨论】:

  • 代码缩进。请使用它。
  • 您应该学习如何阅读故障转储以及如何调试。
  • 你用调试符号编译了吗?如果有,是否有核心文件?您是否使用调试器检查过所述核心文件?崩溃是可重复的吗?每次都发生在同一个迭代中吗?如果您在 linux 上,编译器的 -g 标志将添加调试符号,并检查内核 - gdb &lt;executable file&gt; &lt;core file&gt;
  • 很抱歉。我清理了一下,我以前从来没有在这里粘贴过代码。
  • 是的,它似乎每次都发生在同一个迭代中

标签: c++ colors while-loop filestream stack-dump


【解决方案1】:

在您的rgb2lab 函数中,您创建一个new float[3]。每次调用此函数时都会发生这种情况。查看您的代码,我看不到任何地方调用delete 来释放内存。

每个new 都与delete 配对是一种很好的编程习惯。如果使用new 创建某些内容,则在程序的每个执行路径中都调用delete 也是更重要的。

您的代码中发生的情况是,对于写入文件的每一行,您的 rgb2lab 函数都会被调用 2100 次。您是说您的程序在将大约 62000 行写入文件后出现问题。在这种情况下,rgb2lab 函数被调用了 130,200,000 次,并且每次都在泄漏内存。

编辑:

您有几个地方调用new,而您应该调用delete,但最大的问题是2100 迭代for 循环一遍又一遍地调用rgb2lab 函数。由于您使用的是函数返回的动态分配数组,因此在使用完毕后释放内存即可。

for (i = 0; i < 2100; i++)
{
    cie2 = rgb2lab (red[i], green[i], blue[i]);
    //challengeClosestVal = pow(cie1[0] - cie2[0], 2.0) + pow(cie1[1] - cie2[1], 2.0) + pow(cie1[2] - cie2[2], 2.0);
    dL = cie1[0] - cie2[0];
    dA = cie1[1] - cie2[1];
    dB = cie1[2] - cie2[2];
    c1 = sqrt(cie1[1] + cie1[2]);
    c2 = sqrt(cie2[1] + cie2[2]);
    dC = c1 - c2;
    dH = sqrt(pow(dA, 2) + pow(dB,2) - pow(dC,2));
    Kl = 2;
    K1 = .048;
    K2 = .014;
    Sl = 1;
    SC = 1 + K1*c1;
    SH = 1 + K2*c1;

    challengeClosestVal = sqrt(pow(dL/(Kl*Sl), 2) + pow(dC/(Kl*SC),2) + pow(dH/(Kl*SH), 2));


    if(challengeClosestVal < currentClosestVal){
        currentClosestIndex = i;
        currentClosestVal = challengeClosestVal;
    }
}
delete [] cie2;  // <-- Free up the memory here!

【讨论】:

  • 谢谢,我很感激。如果我想在删除之前返回我创建的数组,我会将删除放在哪里?
  • 避免使用newdelete,通过值或引用传递。
  • 您应该在使用完返回的数组后放置delete []。分配和删除数组会减慢你的程序。
【解决方案2】:

我不明白您为什么要使用 new 运算符(除非您来自 Java 或 C# 背景)。您可以在不使用 new 运算符的情况下传递结果。

例如:

void rbg_to_lab (float r, float g, float b,
                 float& cie[3])
{
 // ...
}

通过将cie 数组作为引用传递,您可以直接修改调用者的变量,分配任何new 内存对象(也不必delete 内存。)。

另一种解决方案是为cie 值创建一个结构并返回该结构:

struct Cie_Values
{
  float cie_1;
  float cie_2;
  float cie_3;
};

Cie_Values rgb_to_lab(float r, float g, float b)
{
   Cie_values cie;
   // Perform conversion
   return cie;
}

【讨论】:

  • 谢谢托马斯,感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 2020-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-07
相关资源
最近更新 更多