views:

215

answers:

2

I have the following code, m_edit is a MFC CEdit (I know I would never use MFC but project demanded it).

It's a simple loop, that gets the text from a text edit, converts it to integer after getting the first line, then stores it in m_y vector.

LPTSTR szTemp;
vector<int> m_y;
for(int i = 0; i < m_edit->GetLineCount(); i++){
  szTemp = s_y.GetBuffer(0); 
  m_edit->GetLine(i, szTemp); // get line text store in szTemp
  y = atoi(szTemp);
  m_y.push_back(y);
  szTemp = "";
  y = 0;
 }

IMPORTANT EXAMPLE: So let's say the CEdit has 6 numbers:

  • 0
  • 5
  • 2
  • 5
  • 18
  • 6

If you use Visual Studio's debugger you will notice an anomaly!! Here's what it shows:

  • y = 0
  • y = 5
  • y = 2
  • y = 5
  • y = 18
  • y = 68

Do you see that? szTemp when inserted into atoi, it returns the number 6, but concatenates the 2nd digit of the last number!!! This is why I did szTemp = "";, but the problem persists. Also, let's say the last number was 17 (not 18), then this time debugger would say y = 67, so it is definitely this problem.

However, Visual Studio debugger, when you hover over szTemp during this iteration, it says '6' <--- not '68' inside szTemp. So somehow atoi is ruining it.

Am I suppose to concatenate a \0 into szTemp before putting it into atoi? How do I solve this easily?

+4  A: 

From the MFC CEdit::GetLine documentation:

Remarks: The copied line does not contain a null-termination character.

So you need to pay attention to GetLine's return value to determine how many bytes were copied into the buffer and then add your own NUL-terminator.

Also, I would recommend that you pass in the buffer size to make sure you don't have a potential buffer overflow.

jamesdlin
This is what I am using above. Apparently, what this does, is it takes the CEdit's text, and puts it into the CString, then I use GetBuffer(0) to grab all the text so that it allocates enough memory for the LPTSTR. CString s_y;m_edit->GetWindowText(s_y);The problem is, I suppose the NULL terminator, but how do I add my own null terminator? strcat (well strcat_s) doesn't seem to work (crashes). Can you show an efficient way to code the solution?
Dexter
@Dexter: `int n = m_edit->GetLine(i, szTemp); szTemp[n] = '\0';`. Also, there's no way `GetBuffer(0)` can allocate "enough memory" unless it has psychic powers, and there's no way for `GetLine` to know how big the buffer is unless you tell it.
jamesdlin
@Dexter: Also, now that i know that `s_y` is a `CString`, I don't know how you think `GetBuffer(0)` is safe either. I don't see anything in the `CString::GetBuffer` documentation that indicates it allocates *anything*. It sounds like you're also overwriting memory (although that's a separate issue).
jamesdlin
@Dexter: P.S. I hope you understand why you can't add a NUL-terminator with `strcat`. How would `strcat` know where the end of the first string is? Even if it did, the second string would be the empty string, so `strcat` wouldn't do anything.
jamesdlin
Yes, I was thinking that these functions were a lot more complex than they were. Thank you I will give this a shot and let you know.
Dexter
How do I allocate the memory? CWin32Heap? Also this site says that GetBuffer can be used with CString and does allocate memory dynamically: http://vcfaq.mvps.org/mfc/9.htm
Dexter
szTemp = s_y.GetBuffer(s_y.GetLength()); bytes = m_Yedit->GetLine(i, szTemp); szTemp[bytes] = '\0'; y = _tstoi(szTemp);This seems to work very well and doesn't seem to cause any memory problems. Do I still need ReleaseBuffer?
Dexter
@Dexter: `s_y.GetBuffer(s_y.GetLength())` is completely meaningless. The old length of `s_y` isn't related to the size of the buffer you'll need! `CString` does allocate memory dynamically, but it can't magically do this when writing directly to the result of `GetBuffer`. *You* must specify an appropriate buffer size. And please, you really need to pass the buffer size to `GetLine` to avoid overflow. I personally would do: `TCHAR buf[256]; int n = m_edit->GetLine(i, buf, _countof(buf));`.
jamesdlin
I don't know if you understood my code correctly. CString contains the WHOLE text of CEdit, when I GetBuffer I am simply converting it to LPTSTR so that I can use GetLine. The memory is already allocated and transferred to szTemp (Otherwise the program wouldn't work, but it does work without errors). This is one of the common ways to allocate memory dynamically and store in LPTSTR.
Dexter
@Dexter: I can't understand code that you haven't provided. If `s_y` was was already storing the entire string from `CEdit`, maybe it's fine. (Note that your program could *seem* to work even if insufficient memory were allocated.) At least pass along the buffer size to `GetLine`, please. There's no harm in doing so, and you eliminate any risk of buffer overflow.
jamesdlin
Ok I will definitely include buffer size in GetLine. I'm sorry my code wasn't clear enough.
Dexter
A: 

I think you should specify a buffer size for GetBuffer

e.g.

szTemp = s_y.GetBuffer(MY_MAX_STRLEN);

having GetBuffer(0) allocates a 0 sized buffer since CString is (presumably) empty.

Anders K.
I found GetBuffer(0) that someone had used, I assumed, when 0 is inserted, it grabs the whole string from s_y.
Dexter
But CString isn't empty either. So I assumed it was allocating enough memory by the use of GetWindowText (so it grabs all the numbers and uses the length of that as buffer I thought)
Dexter
@Dexter: You're not grabbing a string from `s_y`. You're grabbing a string from the `CEdit` control and storing it in `s_y`'s buffer. And what does `GetWindowText` have to do with anything?
jamesdlin
s_y contains the whole text (via GetWindowText) of CEdit. Then I use that buffer and insert parts via GetLine, so that I can divide it individually, another way would be to use GetWindowText and then split at \r\n.
Dexter