Click here to Skip to main content
15,885,767 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
EDIT#3:

It seems that after using wstring the problem was in the buffer overflow.

After changing the code like below ( putting 48 instead of 50 ), everything seems to work fine:
C++
wchar_t temp[50], destination[50];

GetDlgItem( ... , temp, 48 );

swprintf_s( destination, 50, L"%s", temp );


This is directed to those members who observed that my code is more C than C++:

You are right, it is so because I use pure Win32 API, and all examples are in C.

To use it in C++ I need to know MFC, which I don't at this moment.

For all those who tried to help, you get +5 from me.

I have tried your answers and they all worked, but the best advice is just to use wstring.

I was afraid to do that since I am a beginner, but thanks to the help of the community I think I have managed to learn something new.

Thank you all, again.

The last thing I ask for is if somebody can explain me briefly why the above code, when number 48 is substituted with 50, creates buffer overflow ?

Thank you all again.

Regards.

EDIT#2:

Replaced vectors of wchar_t pointers with vectors of wstring, but crash still occurs.

Still, performance is better. After I isolate the problem I will update my question again.

Thanks to all members who posted their answers and comments, they are highly appreciated.

Regards.

EDIT#1:

EDITED QUESTION TO CORRECT TYPOS THAT APPEARED IN CODE SNIPPETS ( thank you Mr. pwasser for pointing them out ).

NECESSARY INFORMATION:
-------------------------------------
NOTE:

This is a simplified description, in order to keep this question as short as possible.

For further information ask additional questions, and I will provide more information.

I have a dialog box with 2 edit controls, 2 buttons and combo box.

On dialog creation, in WM_INIDIALOG, a connection is established with a database, which holds data about monthly salary of employees on a year basis.

Then primary keys of the employees are loaded into combo box.

Tables look like this:

SQL
Table_Employee < #primary_key, ...> 
Table_Salary < #pk_salary, $primary_key, January, February, ..., Year>


Relationship is one to many, since one employee has data about monthly salary for every year, like this:

SQL
|  January | ... | Year | #pk_salary| $primary_key|
|  1000.51 | ... | 2012 | 100025558 | 48089989891 |
|  2000.51 | ... | 2013 | 552025558 | 48089989891 |
...


Once a user selects a primary key from combo box , he is able to change the data about monthly salary by typing it in first edit control, and he must type in the year in the second edit control.

Entered data is held in a vectors declared like this:

C++
INT_PTR CALLBACK dlgProcedure(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	static vector< wchar_t* > ee; // vector for monthly salaries and a year

	static vector< vector< wchar_t* > >  Pee; // this vector holds data for all the years
	...
	case WM_INITDIALOG:
		{
		    // 12 months + 1 year = vector of 13 to store data 

		    ee.assign( 13, LoadedValue ); 
                                  
		    ...


After user pushes the first button , data for the month is saved in the above vector like this:

C++
case IDC_BUTTON_MONTH:
	{
	    wchar_t *temp = new wchar_t[50]; // needed, since we have vector of wchar_t*
 
            GetDlgItemInt( ... , temp, ... );

            UINT i = // ordinal of the month taken from checkbox

	    ee[ i ] = temp;


Then user must enter year, and after pushing the second button it is stored like this:

C++
case IDC_BUTTON_YEAR:
	{
		wchar_t *temp = new wchar_t[50]; // needed, since we have vector of wchar_t*
 
                GetDlgItemInt( ... , temp, ... );

		ee[12] = temp;

		// This means that all the data is collected

		// so we can store this year’s data in the vector for years

		Pee.push_back(ee);


This way, vector Pee holds data for all the years ( 2012, 2013, ... ), and vector ee holds the specifics ( monthly salary for a certain year ).

THE PROBEM:
------------------------------

After selection in the combo box changes, I must clear all vectors, in order for new data to be stored.

When I do that, I get the error, and my program snaps. Crash occurs also when I try to close the window.

If I comment out the section of the code that clears vectors, my program works, but then I can not use it to store new data, since vectors are not cleared properly.

IMPORTANT INFORMATIONS:

--------------------------

Once I start program and change selection in combo box,a dialog box pops up, with 2 debuggers offered, and this message:
An unhandled exception occurred in SomeProgramName.exe[3300].


In Debug, in MS Visual Studio 2008, I have clicked on Exceptions, and checked
everything.

After I start the program in Debug mode, I get the dialog box with following message:

This may be due to a corruption of the heap, which indicates a bug in MyProgramName.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while MyProgramName.exe has focus.

The output window may have more diagnostic information.

As I have said above, after I comment out the cleanup code, error no longer occurs.

That is why I am very sure that there lies my problem.


PROBLEMATIC CODE SNIPPETS:

----------------------

Handler for WM_CLOSE:

C++
case WM_CLOSE:
	{
		// cleanup 
				
		for( vector< wchar_t* >::size_type i = 0; i < ee.size(); i++)
			delete[] ee[i];

		ee.clear();

		for( vector< vector< wchar_t* > >::size_type i = 0; i < pee.size(); i++)
			for( vector< wchar_t* >::size_type j = 0; j < pee[i].size(); j++)
				delete[] pee[i][j];

		pee.clear();
		DestroyWindow( hDlg );
	}
	return TRUE;


Handler for combo box:

C++
case IDC_COMBO12:
	{
	    if(HIWORD(wParam) == CBN_SELCHANGE )
	    {
		// cleanup 

		for( vector< wchar_t* >::size_type i = 0; i < ee.size(); i++)
		    delete[] ee[i];

		ee.clear();

		for( vector< vector< wchar_t* > >::size_type i = 0; i < pee.size(); i++)
			for( vector< wchar_t* >::size_type j = 0; j < pee[i].size(); j++)
			    delete[] pee[i][j];

		pee.clear();

		// assign neutral values to vectors

		ee.assign( 13, L"-1" );

		for( int i = 2012; i < currentYear; i++ )
			Pee.push_back(ee);

		// other commands, like loading data from database and so on...


THE QUESTION:
--------------------------

Since I have a vector of pointers ( vector < wchar_t* > ) , I believe that I can’t just use clear() method to empty the vector since it would cause memory leaks.

That is why, in my opinion, I must delete pointer first, and only then use clear() method.

This is my first time using vector of wchar_t*, so I ask the community what am I doing wrong here?

How should I correctly reset those vectors in my handlers ?

I use MS Visual Studio C++, and pure WIN32. Ask for additional information, I will gladly provide them.
Posted
Updated 8-Sep-13 22:13pm
v8
Comments
[no name] 9-Sep-13 3:21am    
In q3 are you talking about GetDlgItemText(). What do you mean by "creates buffer overflow". Use Getlasterror() to find out details.

BTW in regards to another comment - Win32 and c++ are not in some way mutually exclusive.
AlwaysLearningNewStuff 9-Sep-13 4:15am    
I agree with the second part of the comment.

As for the first part, I have updated the question.

Thank you.

Regards.

Looks like a double delete problem to me. Since you are loading the ee object, then adding it to pee, deleting the contents of pee will do something with ee as well.

One of the things I always do when deleting a pointer is immediately set it to NULL. I believe this will fix your crash problem here. In other words:

C++
for( vector< wchar_t* >::size_type i = 0; i < ee.size(); i++)
{
    delete[] ee[i];
    ee[i] = NULL;
}


... but this admittedly doesn't fix the problem that you are deleting the same objects twice. Think about what the pee object contains.

By the way, I'd suggest different variable names. You seem enamoured with the name 'temp' and likewise ee/pee are not that descriptive.
 
Share this answer
 
Comments
Ron Beyer 8-Sep-13 23:43pm    
Am I the only one who laughed when I read:
pee.Clear() and
pee.push_back(ee)
?
AlwaysLearningNewStuff 8-Sep-13 23:52pm    
I am glad that I can make someone laugh...

Can you help me out then, since I am a beginner?

For starters, why is it so funny to you ?

Can you please help me, by explaining me that, since I want to learn from my mistakes.

Thank you.

Regards.
H.Brydon 8-Sep-13 23:54pm    
No, I didn't laugh. I was too busy stepping out of the way in case of a bucket split or an overflow of some kind.
AlwaysLearningNewStuff 9-Sep-13 3:10am    
Thank you so much, it seems it works now.

I have changed my code to use wstrings, though, since I believe it is a smart thing to do.

+5 from me, as a small token of gratitude.

I have updated my question at the top, can you give it a quick look ?

I am very interested in an answer to the short question posted there ?

Regards, and thanks again.
AlwaysLearningNewStuff 9-Sep-13 0:01am    
Thank you Mr. Brydon.

I am using vectors for the first time.

After doing a little research, I think I should replace wchar_t pointers with wstring, so this is what I am currently trying.

I just do not know how to store the text from combo box and edit control into wstring, so I ask you to help me with some instructions if you do not find it too hard for you.

Also, I believe that the reason for my mistake lies in the statement ee.assign( 13, L"-1" ) as it stores constant wstring, instead of a pointer.

Since it is not on heap, I believe that delete[] statement causes a crash because of that.

That is why I have decided to use wstring instead of wchar_t*, but as I have said, I do not know how to store text from edit control and from combo box into wstring.

Again, if you could find some good will to help me out, I would be very grateful.

Thank you for your answer.

Regards.
C++
static vector< wchar_t* > ee(12, NULL); // vector for monthly salaries (init as NULL to avoid a delete blow up if not used)

static vector< vector< wchar_t* > >  Pee; // this vector holds data for all the years


for(int nn = 0; nn < 20; nn++)
{
    for(int n=0; n <12; n++)
    {
        wchar_t *temp = new wchar_t[50];

        swprintf(temp, 50, L"%s%i", L"test", n);

        ee[n] = temp;
    }

    Pee.push_back(ee);
}


for( vector< vector< wchar_t* > >::size_type i = 0; i < Pee.size(); i++)
{
    for( vector< wchar_t* >::size_type j = 0; j < Pee[i].size(); j++)
    {
        delete[] Pee[i][j];
        Pee[i][j] = NULL; // overkill
    }
    Pee[i].clear(); // This step optional here - if used then need resize()
}

Pee.clear();


This example shows how I would suggest it is done. If temp buffer is reused then when it comes time to clear the entries using delete you will delete an already deleted pointer. ****As has been pointed out this can be protected against by nulling the pointer after deletion.****
{Edit] This cannot be protected against and so should be avoided. If temp is reused without a new allocation then all the members of ee will point to the same place and this will blow up. There must be a new temp buffer each time as shown in my snippet. wstring is the way to go.

Also to avoid errors have only one function for clearing and call as required.
 
Share this answer
 
v6
Comments
H.Brydon 9-Sep-13 1:50am    
I agree, I like your code better, although there are still some other issues. The values ee and Pee should be class variables (not static) and the cleanup stuff should really be in destructors instead of being reused.

What we have ended up with here is a C program written using some C++ features.
[no name] 9-Sep-13 2:50am    
Sure - I am only addressing the unhandled exception with an example. Design of the program is up to the OP. I am happy to do this bit for free. A class with constructor and destructor definitely advisable.
AlwaysLearningNewStuff 9-Sep-13 3:09am    
Thank you so much, it seems it works now.

I have changed my code to use wstrings, though, since I believe it is a smart thing to do.

+5 from me, as a small token of gratitude.

I have updated my question at the top, can you give it a quick look ?

I am very interested in an answer to the short question posted there ?

Regards, and thanks again.
pasztorpisti 9-Sep-13 6:01am    
+5
It is bad practice to use new.
Use wstring instead of wchar_t*.
This way you do not have to worry about memory allocations and deallocations.

You can have containers like these -
vector<wstring>
vector<vector<wstring>>
 
Share this answer
 
Comments
AlwaysLearningNewStuff 9-Sep-13 3:09am    
Thank you so much, it seems it works now.

I have changed my code to use wstrings.

+5 from me, as a small token of gratitude.

I have updated my question at the top, can you give it a quick look ?

I am very interested in an answer to the short question posted there ?

Regards, and thanks again.
pasztorpisti 9-Sep-13 6:04am    
Take advantage of RAII whenever possible in C++. Code that doesn't contain malloc(), free(), and lot of delete and delete[] statements (because of RAII usage) generally have better quality and less bugs. When raw memory allocation (malloc, new[]) must be used then pack this piece of code into a class and then use the class in the rest of your code (applying RAII). This way the destructor of your class does the cleanup (free, delete[]) and you have raw memory manager code only in one place.
pasztorpisti 9-Sep-13 6:03am    
+5
[no name] 9-Sep-13 6:19am    
This the elegant way. 5.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900