Archived

This topic is now archived and is closed to further replies.

Orpheum

Problems with new and scope

Recommended Posts

Orpheum    122
Heres a rather perplexing one... I have an object which contains many char* variables, which are ''new''ed in the initialize() function when variable strings are read in from a file. Stepping through the function in the debugger, I can see that the memory is being allocated and that the strings are being copied from the file into my new buffers. The problem is, once the flow of execution leaves the scope of that function, the variables are gone! When the flow is in main(), I test for a.fre_prefix and it says "CXX0030: Error: Expression cannot be evaluated". When the flow has entered the next function, testing for fre_prefix has the same result. I have no idea why this is happening... when in initialize(), the ''this'' tab of the debugger watch window has everything filled in, but once you step out of the function... blammo! Everything is gone. It is almost like the initialize function is using its own object with function scope! initialize() has no parameters, and no objects are declared in the function. The variables are defined like so in the private section of the object: char* chk_prefix; char* fre_prefix; char* chk_wks_suffix; char* chk_srv_suffix; char* fre_wks_suffix; char* fre_srv_suffix; Then in initialize(), they are allocated this way: if(stricmp(szVariable, "PathToFreBuilds") == 0) { fre_prefix = new char[strlen(szData) + 1]; strcpy(fre_prefix, szData); } else if(stricmp(szVariable, "PathToChkBuilds") == 0) { chk_prefix = new char[strlen(szData) + 1]; strcpy(chk_prefix, szData); } else if(stricmp(szVariable, "SuffixForFreWks") == 0) { fre_wks_suffix = new char[strlen(szData) + 1]; strcpy(fre_wks_suffix, szData); } etc etc... I think I''ve put enough info up here to be helpful... if you guys need anymore, just ask.... I''m anxious to move beyond this problem so I will be checking the boards regularly. Thanks!!

Share this post


Link to post
Share on other sites
dbrooking    122
OK. I remember my prof going over this exact thing in class a few semesters ago so let''s see how much I remember.

I think, and a confirmation from someone else would be nice, that when you use the new operator, the scope of that variable is only within the current function and any functions you pass it to. So when you leave the function, the char* cannot be seen. They still exist just aren''t in scope. Hope thats right and hope that helps. and I am 99% sure thats right, but someone else saying so would be great.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Well, it really has nothing to do with the new operator. The problem is that fre_prefix is declared in the PRIVATE section of the class. This means that the variable is visible ONLY inside class methods, even to the debugger. It still exists in memory, you just can''t access it.

It''s a completely different issue about the "this" pointer, though. The reason you can''t look at it after the function returns is because it only exists INSIDE the function. The data it points to still exists in memory somewhere, but the actual variable named "this" exists only within the scope of the method. Think of it this way: When you call the function, the variable "this" is created on THE STACK. When you return from that function the stack frame is now completely different and the "this" variable ceases to exist.

Share this post


Link to post
Share on other sites
Orpheum    122
Hmm... well every function used in the program is a method of the same class, so you would think that when the flow enters another of the class''s functions, you could see the variables. So if really is limited to scope, how would you suggest that I allocate these char*''s so that they stay there and can be used later in the program? I have done this many times before, and have had no problems... I have no idea what is different this time.

Share this post


Link to post
Share on other sites
Stoffel    250
Both of the previous responders are incorrect. You can view private member variables with the debugger (you just have to have an object obj->m_private, or just m_private if you''re in a class function). New''d variables DO NOT leave scope. The only thing that ever leaves scope are things that are declared within that scope (including parameters). Things that are new''d must be delete''d explicitly--there''s no automatic deallocation. The pointer that points to that memory may go away if it was declared in scope, but the memory is still allocated (that''s what happens when memory leaks).

I suspect something else is going wrong here; maybe your pointers are being overwritten by something else? Look at the variable that gives you the problem, note the address that''s returned by new and make sure that variable has the same address when it''s used.

Also, maybe something somewhere is deleting this associated memory? I used to be in the habit of assigning a pointer to NULL every time I deleted its contents, and it''s a good habit to have (I''ve unfortunately grown out of it). This way you can tell if you get to the function and the pointer = NULL that it''s been deleted.

Just make sure that the pointer is in fact the problem. It looks from your description like you''re doing the right thing.

BTW, it should go without saying that these member variables should all be initialized to NULL in the constructor to show that no memory has been allocated to them yet. But there, I just said it anyway.

P.S.: why do people respond with incorrect information? Either you''re sure you know something that''s false (in which case I pity you), or you''re not sure what you''re talking about and you feel like responding anyway. Please, don''t.

Share this post


Link to post
Share on other sites
jaxson    127
quote:
Original post by Stoffel

P.S.: why do people respond with incorrect information? Either you''re sure you know something that''s false (in which case I pity you), or you''re not sure what you''re talking about and you feel like responding anyway. Please, don''t.


I think that sometimes, people aren''t 100% sure, but they like to be as helpful as possible. For example, dbrooking flat out said that he wasn''t sure about what he was saying. Nothing wrong with that. The reader just needs to take it with a grain of salt.

Anyway... as far as your problem, Orpheum, if you haven''t figured it out yet, why don''t you post some more of your code to the initialize function (or all of it, if that is practical). Or maybe you could post the section of code where it is getting used? It is possible that you are somehow ending up with a different instance of your class that hasn''t been initialized? Of the top of my head, I can''t think of an instance where that could happen on accident, but who knows?

Share this post


Link to post
Share on other sites
Orpheum    122
Thanks for your help so far guys... we will get to the bottom of this Im sure. Because this is such a fucked up problem, I will post all of my class header, initialize function, and my main function so everyone can see what I''m doing.

**installer.h**

#ifndef installer_h
#define installer_h


#include
#include
#include
#include
#include
#include
#include

#include "file_parser.h"


class installer
{
public:
installer();
~installer();

bool initialize(); //reads in settings from user.ini
void input_build(); //display and get build #
void input_version(); //display and get version type
void input_drive(); //display and get target drive
void finish(); //clean up temp files, start install

/*****Utility Functions*****/

void format(int* drives, int count); //format drive menu/function
void output_file(char* build, char* mach_name); //output answer file
void parse(int sel); //parse a file
void reset_loop();
void title(void); //display the banner

private:
/*****Path Strings*****/

char path_buffer[_MAX_PATH];

char* chk_prefix;
char* fre_prefix;
char* chk_wks_suffix;
char* chk_srv_suffix;
char* fre_wks_suffix;
char* fre_srv_suffix;
char* temp_drive_path;
char* unattend_path;

/******User Variables*****/

char build[5];
bool chk; //chk or fre
char drive; //what drive to install on to
char* domain; //the domain to be joined
char* user; //user name for domain
char* pass; //password for domain
char* mach_name; //get the machine name
bool more_loop; //loop control
char os; //wks ''P'', srv ''S''
};

#endif


**installer::initialize()**

bool installer::initialize()
{
char szBuffer[BUFSIZ];
char szVariable[64];
char szData[256];
int i = 0,
j = 0;

/******Clean Buffers******/

for(i = 0; i <= BUFSIZ; i++)
szBuffer = ''\0'';

for(i = 0; i < 65; i++)
szVariable[i] = ''\0'';

for(i = 0; i < 257; i++)
szData[i] = ''\0'';

i = 0;


//read in .ini file

ifstream in("Installer.ini", ios::nocreate);

if(!in)
{
cerr << endl << endl << "Installer.ini not found! Verify the file exists and is in the root directory." << endl << endl;

return false;
}

while(in.getline(szBuffer, BUFSIZ, ''\n''))
{
if((szBuffer[0] != ''['') && (szBuffer[0] != '' '') && (szBuffer[0] != ''\0'') && (szBuffer[0] != ''/''))
{
while(szBuffer[i] != '' '')
{
szVariable[i] = szBuffer[i];
i++;
}

i += 3; //move i to the other side of " = "

while(szBuffer[i] != ''\0'' && szBuffer[i] != '' '')
{
szData[j] = szBuffer[i];
i++;
j++;
}

//all these are ok when flow in inside initialize()
if(stricmp(szVariable, "PathToFreBuilds") == 0)
{
fre_prefix = new char[strlen(szData) + 1];
strcpy(fre_prefix, szData);
}
else if(stricmp(szVariable, "PathToChkBuilds") == 0)
{
chk_prefix = new char[strlen(szData) + 1];
strcpy(chk_prefix, szData);
}
else if(stricmp(szVariable, "SuffixForFreWks") == 0)
{
fre_wks_suffix = new char[strlen(szData) + 1];
strcpy(fre_wks_suffix, szData);
}
else if(stricmp(szVariable, "SuffixForFreSrv") == 0)
{
fre_srv_suffix = new char[strlen(szData) + 1];
strcpy(fre_srv_suffix, szData);
}
else if(stricmp(szVariable, "SuffixForChkWks") == 0)
{
chk_wks_suffix = new char[strlen(szData) + 1];
strcpy(chk_wks_suffix, szData);
}
else if(stricmp(szVariable, "SuffixForChkSrv") == 0)
{
chk_srv_suffix = new char[strlen(szData) + 1]; strcpy(chk_srv_suffix, szData);
}
else if(stricmp(szVariable, "Domain") == 0)
{
domain = new char[strlen(szData) + 1];
strcpy(domain, szData);
}
else if(stricmp(szVariable, "User") == 0)
{
user = new char[strlen(szData) + 1];
strcpy(user, szData);
}
else if(stricmp(szVariable, "Pass") == 0)
{
pass = new char[strlen(szData) + 1];
strcpy(pass, szData);
}

/******Clean Buffers******/

for(i = 0; i <= BUFSIZ; i++)
szBuffer[i] = ''\0'';

for(i = 0; i < 65; i++)
szVariable[i] = ''\0'';

for(i = 0; i < 257; i++)
szData[i] = ''\0'';

i = 0;
j = 0;
}
}

in.close();

return true;
}


**main()**

#include "installer.h"

int main()
{
installer a;

/*
if(a.initialize() == false) //wtf is wrong here!?!?
exit(1);
*/
a.initialize(); //as soon as the flow leaves here, poof!
a.title(); //a.fre_wks says nothing!!

a.input_build();
a.reset_loop();
a.input_version();
a.reset_loop();
a.input_drive();

a.finish();

return 0;
}

Share this post


Link to post
Share on other sites
Llamasoft.net    122
top tip, when posting code, put it in the [ / source ] and [ / source ] tags, minus the spaces, naturally
at least then we can read it

Nick - Head Designer, Llamasoft.net

--
Visit our website...

Llamasoft.net
Games, goodies and ingenuity

Edited by - Llamasoft.net on July 21, 2000 7:43:49 PM

Share this post


Link to post
Share on other sites
Stoffel    250
Found two things: one thing you're doing wrong, and one thing you're doing poorly.

First, what you're doing wrong is writing outside of memory that's assigned to you. When you declare these local variables:

char szBuffer[BUFSIZ];
char szVariable[64];
char szData[256];

...the number of bytes assigned to each is BUFSIZ, 64 and 256, respectively. But when you clear the data, you're clearing one too many bytes. The code here:

for(i = 0; i <= BUFSIZ; i++)
szBuffer[ i ] = '\0';
for(i = 0; i < 65; i++)
szVariable[ i ] = '\0';
for(i = 0; i < 257; i++)
szData[ i ] = '\0';

...writes one too many zeros. I guarantee that it's overwriting something important in memory, which is why your data "disappears" after you leave the function. Those loops should really be as follows:

for(i = 0; i < BUFSIZ; i++)
szBuffer[ i ] = '\0';
for(i = 0; i < 64; i++)
szVariable[ i ] = '\0';
for(i = 0; i < 256; i++)
szData[ i ] = '\0';


I copied your program, made these changes, and it worked for me.

Second, the thing that you're doing poorly is that you don't even need these loops. szBuffer is initialized completely by getline: that is, getline will make sure that szBuffer is a null-terminated character array, so it will be safe to use with string functions. szVariable is almost able to be used as-is, except for the fact that you don't explicitly put a null character on the end of it. If you do this, you don't need to clear all of szVariable each time either:

i = 0; // set i to 0 right before you use it instead of at
// the bottom of the loop; makes the code easier to read
while(szBuffer[ i ] != ' ')
{
szVariable[ i ] = szBuffer[ i ];
i++;
}
szVariable[ i ] = '\0'; // add this line to null-terminate

The exact same thing can be done with szData; right after you manually copy each character, set the next variable to '\0' and it will all work for you.

Also, I noticed that the variable j isn't used at all. It can be removed.

That should do it for you. Be careful: you have no safeguards in your code against this kind of line in your .ini file:

this_is_some_bogus_variable_stoffel_put_in_just_to_overflow_your_sixty-four_character_variable_buffer = gotcha!


Edited by - Stoffel on July 24, 2000 1:56:39 PM

Share this post


Link to post
Share on other sites
Orpheum    122
Thanks for your input! I will give it a try ASAP... hopefully I wont have to continue this thread. Thanks for pointing out that I didn''t need to clean the buffers... I wasn''t sure if that was necessary or not, but it is always best to err on the side of caution dont you think? My 64 byte array should have some protection, but in reality, users of my program arent as devious as your average programmer so I was just being conservative (why I dont know, all our machines have 64-128 MB of RAM anyway). And for variable j, if you look more closely, you''ll see the line:

    

szData[j] = szBuffer<i>; =P



If all goes well, that should be a source box. =)

Share this post


Link to post
Share on other sites
Stoffel    250
Ahh, you are correct. In that case, let me again suggest you put the initialization (j = 0) right before you use it, to make your code easier to follow.

The reason for the <i>'s in the source is because [ i ] (no spaces) is interpretted as the hyperlink tag for italics in this software. I think the angle-brackets are a work-around. Don't sweat it, we all know what you mean.

BTW, you should look at strtok. It's a complicated function, but some of these copying procedures you do can be done with a strtok command instead.

Edited by - Stoffel on July 24, 2000 2:53:02 PM

Share this post


Link to post
Share on other sites
Orpheum    122
I use strtok() heavily in another portion of this porgram... its just such a bear to work with sometimes, so it was easier doing it this way for this situation. I tried your idea of i < 64 instead of 65... it didnt work... I noticed that the BUFSIZ statement had a <= instead of <. Now that I look, you put that too, but it is wierd that a single \0 can toast a whole object. Thanks Stoffel!!

Share this post


Link to post
Share on other sites