The first time you call gcd, x=54 and y=24. The y==0 test fails because y is 24, so gcd is called again with x=54 x=24 and y= (54%24) = 6. The second call to gcd knows nothing about the x and y in the first call, so all it sees are 54 24 and 6. Here, y still is not equal to 0, so gcd is called again with x=54 x=6 and y = 54 24%6 = 0. On the third call, y==0 is true, so the function returns 54 6. Control returns back to the second call, which directly returns the result of the third call (54). Control returns to the first call, which directly returns the result of the second call. Therefore, printf prints "The gcd of 54 and 24 is 54 6."
EDIT: To the OP: I hope I didn't add too much to your confusion! I saw the line gcd(y, x%y) as gcd(x, x%y). Had I considered the meaning of gcd, I might have caught the error. Though the numbers were wrong, the rest of the post holds true.
No matter how many function arguments you have, recursive calls continue until the base condition is met (i.e. when you tell it to). If you did not include the test for y==0 in the function, you would have a case of infinite recursion. Each call has its own copies of the parameters and cannot see the values in the previous calls. When the base condition is met, the function returns all the way back up the call stack. Mechanically, it's the same as a normal function call process. a() calls b() calls c() calls d(), and when d finishes, control returns back up the callstack to a(). The only difference with recursive functions is that it's one function calling itself.
libtcod is a great little ASCII graphics library for this sort of game. It has a lot of stuff built-in besides graphics, but you'll have to implement multiple depth levels yourself. I don't know of any library that does that for you.
A great way to get a feel for engine architecture is to learn from people who have already done it. I would recommend Game Engine Architecture by Jason Gregory as a great place to start. It's full of good advice and examples. Of course, the ultimate teacher is experience. The experience of cobbling an engine together, no matter your approach, will open your eyes to better approaches in a way that you won't be entirely satisfied with the result. Do that a few times and you'll eventually end up with something you really like.
Assuming the map can expand in four directions, you might have a grid of 9 chunks, much like a Tic-Tac-Toe board, loaded into memory at once (if you are only moving in one direction, vertically or horizontally, then 3 or 5 would be a better number). The chunk in which the player currently resides is always at the center. When the player crosses the boundary into another chunk, then you would unload one column or row and load a new one depending on the direction the player moved.
For example, say the player moves north into the chunk directly above the center one. Now, you unload the entire bottom row (three chunks). The center row now becomes the bottom row, the top row now becomes the center row, and you load three new chunks to fill in the top row. If diagonal movement is disallowed, you could simplify it to 5 chunks - the middle, N, S, E and W. You're still loading and unloading the same number of chunks, just in a different pattern. But I'd still go with 9 myself.
You'll want a decent chunk size for this, though. If the chunks are too small, you'll be loading more frequently unless you adapt the algorithm a bit.