• Hey, guest user. Hope you're enjoying NeoGAF! Have you considered registering for an account? Come join us and add your take to the daily discourse.

Couple of programming questions

Status
Not open for further replies.
Hiya, got a couple of questions I came across that I could use a little help with. I've seen a few people about here that are good with this kind of thing.


Question 1:
Imagine you are a software engineer on a game team that is very close to the completion deadline. Playtesting has uncovered a big problem - occasionally the game will unexpectedly crash! What has been observed is:

o - the crash cannot be repeated at will (it seems to 'randomly' appear about once or twice a day through playtesting).
o - When viewing through the debugger, it appears that a certain structure in memory has been overwritten with some invalid data.

Bearing in mind the impending deadline, what steps would you take to resolve this mysterious memory scribble.


Question 2:
Write a function that will reverse a string (i.e. "jim" becomes "mij"). If possible, do this "in place", i.e. without any additional memory allocations. Allow for the terminating NULL as well (which shoiuld be kept at the end).

Function prototype
char* stringReverse(char* string);



And that's that. If anyone can offer some suggestions that would be class. I'm off to work the now but I'll be on after. Cheers for any help in advance.
 

sefskillz

shitting in the alley outside your window
i don't know how in depth these need to be so im just gonna toss out some ideas and you can go the rest of the way if they sound good.

Question 1: since a "certain" structure is being overwritten with invalid data randomly, it shouldn't be an issue to lose the invalid data. so just lock the structure's memory location and not let it be changed unless you want it to.

Question 2: count the number of pointers (or characters in the string) and take the floor of that number / 2... you'll need to do that many swaps starting with the first and last letter and working your way to the middle...

there has to be a better way to do #2 though
 

Pochacco

asking dangerous questions
lochnesssnowman said:
Question 1:
Imagine you are a software engineer on a game team that is very close to the completion deadline. Playtesting has uncovered a big problem - occasionally the game will unexpectedly crash! What has been observed is:

o - the crash cannot be repeated at will (it seems to 'randomly' appear about once or twice a day through playtesting).
o - When viewing through the debugger, it appears that a certain structure in memory has been overwritten with some invalid data.

Bearing in mind the impending deadline, what steps would you take to resolve this mysterious memory scribble.
No idea - but this does need to be fixed.
You would probably have to step through the code, using the debugger, and find out exactly where this memory is being overwritten. Checking what the invalid data is may help..

Question 2:
Write a function that will reverse a string (i.e. "jim" becomes "mij"). If possible, do this "in place", i.e. without any additional memory allocations. Allow for the terminating NULL as well (which shoiuld be kept at the end).

Function prototype
char* stringReverse(char* string);
Just swap the first character with the 2nd last character (since the last character is a \0 NULL character). Then advance cursors (one for the front character, one for the back) to move onto the next pair. If the cursors equal each other (i.e. odd number of characters in the string, do nothing).

Since the question asks to do this "in place", you could even use the null-character's position in the string as a temporary storage when swapping characters (but remember to set the last char in the string back to null after everything is done).
 

Phoenix

Member
lochnesssnowman said:
Hiya, got a couple of questions I came across that I could use a little help with. I've seen a few people about here that are good with this kind of thing.


Question 1:
Imagine you are a software engineer on a game team that is very close to the completion deadline. Playtesting has uncovered a big problem - occasionally the game will unexpectedly crash! What has been observed is:

o - the crash cannot be repeated at will (it seems to 'randomly' appear about once or twice a day through playtesting).
o - When viewing through the debugger, it appears that a certain structure in memory has been overwritten with some invalid data.

Since most games aren't multithreaded this makes it a little easier. What I would do is bring up the stack so I can see what statements are executing before that section of memory become corrupted. (but a watch on that datastructure so you can be notified when it changes, will make playing slower and that may upset your testers, but its better than upsetting your customers).

Since its happening randomly its likely some obscure playtest scenario that isn't normally covered that is causing a malloc or pointer swizzle (or similar depending on your memory manager) into memory that should be protected. I would start looking there too. Its likely somewhere obscure in the code.


Question 2:
Write a function that will reverse a string (i.e. "jim" becomes "mij"). If possible, do this "in place", i.e. without any additional memory allocations. Allow for the terminating NULL as well (which shoiuld be kept at the end).

Function prototype
char* stringReverse(char* string);

char* first = string;
char* last = first + strlen(first) - 1;

for(; first < last; ++first, --last)
{
*first = *first + *last;
*last = *first - *last;
*first = *first - *last;
}

return string;
 

Pochacco

asking dangerous questions
char* first = string;
char* last = first + strlen(first) - 1;

for(; first < last; ++first, --last)
{
*first = *first + *last;
*last = *first - *last;
*first = *first - *last;
}

return string;
Hehe, that's awesome...
 

Scrow

Still Tagged Accordingly
lochnesssnowman said:
Question 1:
Imagine you are a software engineer on a game team that is very close to the completion deadline. Playtesting has uncovered a big problem - occasionally the game will unexpectedly crash! What has been observed is:

o - the crash cannot be repeated at will (it seems to 'randomly' appear about once or twice a day through playtesting).
o - When viewing through the debugger, it appears that a certain structure in memory has been overwritten with some invalid data.

Bearing in mind the impending deadline, what steps would you take to resolve this mysterious memory scribble.
If it's a PC game ignore the bug until after launch, and then sometime later release a patch for it.
 

rastex

Banned
For question 1 setup a hardware breakpoint at the location in memory that is being overwritten. I just found out about hardware breakpoints in the past couple of months, they're very cool, too bad they're a pain in the ass to setup in Visual Studio.
 

SteveMeister

Hang out with Steve.
darscot said:
My bet would be an uninitlized variable

Yep. Crashes like that are very frequently due to uninitialized variables. Debuggers usually initialize all uninitialized variables to zero, but release builds don't do that and you end up with garbage data. Hard to check for a null pointer in those cases :)
 

Phoenix

Member
SteveMeister said:
Yep. Crashes like that are very frequently due to uninitialized variables. Debuggers usually initialize all uninitialized variables to zero, but release builds don't do that and you end up with garbage data. Hard to check for a null pointer in those cases :)

I use gdb, it doesn't initialize anything :)
 

aaaaa0

Member
SteveMeister said:
Yep. Crashes like that are very frequently due to uninitialized variables. Debuggers usually initialize all uninitialized variables to zero, but release builds don't do that and you end up with garbage data. Hard to check for a null pointer in those cases :)

This is why you should get in the habit of initializing every single variable you declare, immediately when you declare it.

DWORD dwFoo = 0;
DWORD *pdwFoo = NULL;

The optimizer will take out unnecessary initializations, while doing this will prevent cases in which you forget and you need it.

Oh, and debuggers won't initialize to NULL, I believe it's the debug build/heap manager that will do it.

One useful thing to do (on platforms that support it) is turn on the debug heap manager. Debug heap managers will fill all allocations with a head, tail, and freed patterns, so it's easier to recognize when someone's overwritten something, or tried to use freed memory, etc.

Windows in particular supports this thing called the "page heap", which will pad every allocation with a no-access page at the end or beginning of it, depending on the settings. This will cause an immediate exception if the app tries to write beyond the end of an allocation. I've found this really useful as well.

http://msdn.microsoft.com/library/en-us/appverif/appverif/detect_heap_corruptions.asp?frame=true

Windows also supports something called the App Verifier, which will instrument a bunch of APIs to catch common coding mistakes. I've found this quite a useful tool as well.

http://www.microsoft.com/windows/appcompatibility/appverifier.mspx
 

aaaaa0

Member
rastex said:
For question 1 setup a hardware breakpoint at the location in memory that is being overwritten. I just found out about hardware breakpoints in the past couple of months, they're very cool, too bad they're a pain in the ass to setup in Visual Studio.

Yup. Set a hardware break on access write, you'll catch the culprit red-handed.

Not all hardware has hardware breakpoints though. :(
 
aaaaa0 said:
This is why you should get in the habit of initializing every single variable you declare, immediately when you declare it.

DWORD dwFoo = 0;
DWORD *pdwFoo = NULL;

The optimizer will take out unnecessary initializations, while doing this will prevent cases in which you forget and you need it.

Hungarian notation makes baby jesus cry.
 

aaaaa0

Member
Mister Zimbu said:
Hungarian notation makes baby jesus cry.

I used to hate Hungarian as well.

But after I got in the habit of using it, I really like it now. It means that I can be scanning some code, and just by looking at the name of a variable, I know if it's a pointer, and what type it is. (I don't use all of Hungarian notation, just the well known types.)

Of course, poorly written Hungarian is much worse than no Hungarian -- good Hungarian notation requires discipline and consistency to be of any use at all.
 

rastex

Banned
aaaaa0 said:
Yup. Set a hardware break on access write, you'll catch the culprit red-handed.

Not all hardware has hardware breakpoints though. :(

I guess ProDG and the T10K isn't THAT bad...
 

Lathentar

Looking for Pants
aaaaa0 said:
Of course, poorly written Hungarian is much worse than no Hungarian -- good Hungarian notation requires discipline and consistency to be of any use at all.
The main problem I have with hungarian is if you change the type of your variable, you need to change the variable name EVERYWHERE.
 

Phoenix

Member
Lathentar said:
The main problem I have with hungarian is if you change the type of your variable, you need to change the variable name EVERYWHERE.


Not a big deal if you have an IDE which supports refactoring.
 

Lathentar

Looking for Pants
SteveMeister said:
Or if you use good OOP practices.
I can understand the Refactoring... but how would you explain this.

While you might just have a file or two which you reference the variable, you might have referenced it a hundred times. OOP design shouldn't change that. Of course if you're using Objects you never put the type in front of the variable so all the problems are solved.
 

aaaaa0

Member
Lathentar said:
I can understand the Refactoring... but how would you explain this.

While you might just have a file or two which you reference the variable, you might have referenced it a hundred times. OOP design shouldn't change that. Of course if you're using Objects you never put the type in front of the variable so all the problems are solved.

A good editor will have a function like "Smart Rename", which will let you quite easily rename a variable at any time.

I use Source Insight.

http://www.sourceinsight.com/features.html

Context-Sensitive Smart Rename
Source Insight’s indexes allow you to effortlessly rename variables, functions, and other identifiers in one simple step. Source Insight’s context-sensitive smart matching feature is smart enough to rename local scope variables, as well as global or class scope identifiers.

Ctrl-' is your friend. :)

I think VC2005 also has such features.
 

SteveMeister

Hang out with Steve.
Lathentar said:
I can understand the Refactoring... but how would you explain this.

While you might just have a file or two which you reference the variable, you might have referenced it a hundred times. OOP design shouldn't change that. Of course if you're using Objects you never put the type in front of the variable so all the problems are solved.

First, you rarely if ever use global variables, so for the few you have you don't have to change them in too many places (and it's probably better to define static accessor functions for globals, anyway).

Second, if you always use accessor functions to get at data members of a class, you only ever need to change the data member names in a few places within the class itself.

So pretty much all that's left are local variables, and those only need to be changed within scope.
 

darscot

Member
The problem is when the variable changes the access functions parameters changes too. So you still need to change it everywhere. How often do you every change a type anyway.
 

Lathentar

Looking for Pants
darscot said:
The problem is when the variable changes the access functions parameters changes too. So you still need to change it everywhere. How often do you every change a type anyway.

Or you could just do the easy thing and use a typedef and only have to ever change it once.
 

maharg

idspispopd
An overly strong focus on type in C++ can lead to brittle code, imo. C++ is type safe and allows an incredible amount of flexibility in type synthesis (without losing the safety), so beyond being concerned as to whether something is a pointer or not, I generally feel there is little need for hungarian in a fully C++ program.

C is another matter.
 

aaaaa0

Member
maharg said:
An overly strong focus on type in C++ can lead to brittle code, imo. C++ is type safe and allows an incredible amount of flexibility in type synthesis (without losing the safety), so beyond being concerned as to whether something is a pointer or not, I generally feel there is little need for hungarian in a fully C++ program.

Ick, implicit type conversions tend to lead to the compiler going though all sorts of temporary objects, and crazy operator and cast searches, which can lead to some magical and mysterious bugs.

In robust ship-quality code I definitely prefer to manually control everything.

Call me old-school, but my experience has been that going overboard with OOP, STL, templates and these kinds of things generally leads to grief later on debugging a mysterious crash 50 levels down inside a library somewhere.

And I will shoot anyone who uses anything more than simple classes in a kernel driver. :)
 

maharg

idspispopd
We aren't all kernel programmers.

And I disagree, but that much is obvious. I also didn't say type conversion anywhere in there. Implicit type conversions should be avoided at all costs, but implicit code paths based on type are one of the best things about C++. I'm aware of very few languages with a type dispatch mechanism as flexible and obvious (and more importantly, safe) as C++'s.

I don't really consider what you're talking about to be the same language. Or at least not the same dialect. If you're basically coding like it's C, but with more powerful structs, it's not the same as 'modern C++' (where templates are used -- not necessarily as far as the same-titled book describes it, mind you), and mixing the two is absolutely a terrible idea. Inconsistency is death to a C++ program. Like a Quebecer talking to a Frenchman. They understand each other, but think the other gutteral.

But if you know what you're doing in either one, you can do it well.
 

darscot

Member
Lathentar said:
Or you could just do the easy thing and use a typedef and only have to ever change it once.

Your kidding right your going to typdef every time you declare a variable just in case you may change it one day. Sorry but I have better thigns to do with my time and search and replace does wonders. For these rare problems.
 

Phoenix

Member
No I think he's talking about typdefing LONGTYPE to DWORD so that if you have to changet he type of LONGTYPE that's the only place you do it. Its ALL OVER DirectX, OpenGL, and Java and I figured it was common practice everywhere.
 

Lathentar

Looking for Pants
darscot said:
Your kidding right your going to typdef every time you declare a variable just in case you may change it one day. Sorry but I have better thigns to do with my time and search and replace does wonders. For these rare problems.
If its something that might be changed in the future, you should typedef it. Of course you aren't going to go around typedefing bool.

I typedef all the containers I use and all the keys, value_type, etc... because I know I might very well change the container.
 
Just back in from work. Good job GA.

With the second question I did what most people suggested and counted from the second last character backwards swapping with the first onwards. But, I like Pheonix' suggestion. Very cool.

When I was asked the first question, your man asked if I knew of any tools (not just debuggers) that might help. He seemed to want tools which could be used on consoles as well as PC, something quite general and/or portable.

Thanks for all the help so far.
 

maharg

idspispopd
lochnesssnowman said:
With the second question I did what most people suggested and counted from the second last character backwards swapping with the first onwards. But, I like Pheonix' suggestion. Very cool.

That's exactly what his suggestion does, except that it exploits a tricky optimization (more or less the same as a xor swap, except with addition and subtraction instead of xor). If this is for a class, I'd suggest you not use it unless you want your teacher to always expect you to come up with clever optimizations. Keep it in mind for the coolness factor, but it's not really something you should be doing all the time.
 

aaaaa0

Member
maharg said:
And I disagree, but that much is obvious.

I'm not saying that there's no place for this stuff, I'm just saying my personal preference is towards more direct control.

implicit code paths based on type are one of the best things about C++.

While I agree implicit code paths are extremely useful, like all language features, you have to know when and how often to use them, and it's a good idea to have a good idea of what's going on underneath the covers.

I'm not disagreeing with you, I'm just saying you have to be careful (but of course you already knew that).

Implicit code paths scare me because unfortunately a lot of people don't pay attention to how much stuff is going on underneath, and the result ends up being bloated and slow code, and/or bugs and crashes.

When a simple statement like "a = b + c;" can result in (at least) three implicit cast operators and two overloaded operator invocations, my worry is that 6 months from now, the person maintaining the code is not going to remember what's going on underneath the covers, resulting in a hard to find bug that someone will sit down and waste hours on.

I don't really consider what you're talking about to be the same language. Or at least not the same dialect. If you're basically coding like it's C, but with more powerful structs, it's not the same as 'modern C++' (where templates are used -- not necessarily as far as the same-titled book describes it, mind you), and mixing the two is absolutely a terrible idea.

Absolutely agreed.

Inconsistency is death to a C++ program.

Heh. Inconsistency is death to any developer in nearly any language. Except maybe Intercal, where complete unreadability and inconsistency is a design goal. :)

But if you know what you're doing in either one, you can do it well.

True, I absolutely agree with that. Right tool for the job, and all that.
 
Status
Not open for further replies.
Top Bottom