2

I have this piece of code which keeps throwing a 'buffer too small' error during debug.

        geoGraph.size=limit;
        CString xAxis ="X axis: ",yAxis="Y axis: ";

        for (int x = 0; x < limit; x++)
        {

            xAxis.Format(_T("%s%i  "),xAxis,(x+1));
            yAxis.Format(_T("%s%s  "),yAxis,dialog_test.str[x]);

        }

        xAxis.Format(_T("%s \n%s  "),xAxis,yAxis);// <---Error thrown

        d.SetWindowTextA(xAxis);

I came into the conclusion that the error was due to the fact that the Cstring xAxis is too small to contain the new text, am I correct and if so, how do I remedy it?


Thanks.

Edit: I'm curios as to why this error is only shown during debugging and not when I'm running the application with 'start without debugging' (I use VS2008).

4

4 回答 4

10

No! The real problem was:

  1. xAxis Format starts and sees that there is need for more room. Based on the calculation of all the parameters given to Format.
  2. Now xAxis storage is reallocated. The old pointer gets invalid and in the debug Version frees and overwrites it. So there is no 0 terminator any more. The memory is filled with a standard value for free Memory.
  3. Format starts and collects from the old pointer (The Contents where it Points to just changed) and copies garbage and finds no 0 terminator.

Never use a CString in Format as target AND source! This might work in the Release Version, because the Memory MIGHT not be changed, but if it is changed the behaviour is undefined. But it is a real bad coding bug.

于 2013-10-08T06:01:18.463 回答
2

The documentation for CStringT::Format contains the following remark:

The call will fail if the string object itself is offered as a parameter to Format. For example, the following code will cause unpredictable results:

CAtlString str = _T("Some Data");
str.Format(_T("%s%d"), str, 123);
// Attention: str is also used in the parameter list.

To work around this, you can either create a copy for the argument, or - in this specific case - call the CStringT::AppendFormat class member instead:

geoGraph.size = limit;
CStringW xAxis = L"X axis: ",
         yAxis = L"Y axis: ";

for ( int x = 0; x < limit; ++x ) {
    xAxis.AppendFormat( L"%i  ", x + 1 );
    yAxis.AppendFormat( L"%s  ", dialog_test.str[x].GetString() );
}

xAxis.AppendFormat( L" \n%s  ", yAxis.GetString() );

Note in particular, that this implementation calls CSimpleStringT::GetString to retrieve a C-style string for use with the %s format specifier. Passing a CString object for a %s placeholder is not documented to work*.

Also observe, that this implementation uses explicit wide character versions of CString objects, as well as wide character string literals. All supported versions of Windows use Unicode (UTF-16) as their native encoding. Using Unicode in applications is thus a natural choice.


* All currently supported versions of ATL/MFC implement CString in a way that allows to pass a CString object anywhere a C-style character string is expected. This also works for variable argument lists. The latter is an implementation detail, and not part of the documented contract. It should not be relied upon.

于 2016-07-27T11:56:25.593 回答
1

If your objective is to reuse the variables, you can do:

    geoGraph.size=limit;
    CString xAxis ="X axis: ",yAxis="Y axis: ";

    for (int x = 0; x < limit; x++)
    {

        xAxis.Format(_T("%s%i  "), CString(xAxis),(x+1));
        yAxis.Format(_T("%s%s  "), Cstring(yAxis),dialog_test.str[x]);

    }

    xAxis.Format(_T("%s \n%s  "), CString(xAxis),yAxis);

    d.SetWindowTextA(xAxis);

I had a similar situation and it worked, because I am now using a copy of the xAxis variable instead of it directly.

于 2015-07-10T13:28:37.863 回答
-1

Problem solved. Used;

xAxis.AppendFormat(_T("\n%s  "),yAxis);
于 2013-10-08T03:10:37.067 回答