You are on page 1of 7

Puzzles : Interesting Blurbs of C

Wyvern Aldinger, A Work In Progress

For the C or C++ programmers out there, heres some cute brain teasers to work through, study, decipher, then use to astound your friends. I present solutions for all of the problems h just ere; look a couple pages forward. Have fun! Note, at this point I only have a few problems. If you know any other good ones, Id love to hear from you. J

Problem 1 The Loop


Heres a few interesting lines of C. Your question, what does this loop do?
int a; /* initialize to something meaningful */ int b = 0; while( a ) { a &= a 1; b ++; }

To me this was non-obvious, though just running through one or two loop iterations should reveal the magic readily enough.

Problem 2 The Macro


One powerful little macro Ive used a number of times is this:
#define FOO(a,b) ((int)(&(((a*)(0))->b)))

No, it isnt lisp, no matter how many parenthesis I put in it. Here are your questions: What does this macro do? Why is it a really cool way to do it?

Problem 3 List Walking


Lets say you have a doubly linked list of a large number of very small nodes. Space is at a premium in this scenario, so you need to minimize how many bytes you take up with your list pointer overhead. Your first implementation is this:
struct ListNode { ListNode * next; ListNode * prev; int payload; };

You show this to a colleague and she says, Well, why dont you use a single pointer to keep track of both the previous and next items? You intelligently reply, Huh? So she makes a challenge out of it. Replace prev and next with a single pointer while still keeping it doubly linked. The new pointer must take up no more space than one of the two old pointers. Write a bit of code to walk the resulting list. What restriction do you end up with that you didnt have before? Remember, this must be universal ISO C code, so taking advantage of platform features like half-sized near pointers is not allowed.

Problem 4 Single Character


You have a friend whos just learning C. He gives you the following block of code, saying it doesnt work.
int i; int n = 20; for( i = 0; i < n; i -- ) printf(-);

The goal is simple: print a minus sign 20 times. Now geek pride says you would love to fix his program by changing only one character. And upon a little thinking, you realize you can do just that. In fact, there are three different ways to change only one character so that the code works like expected. Find these way.

Problem 5 Swapping (open problem)


All coders at some point have to challenge this one. Goal: Write one or more lines of code to swap two integer variables in place. By in place I mean you are not allowed to use any third variable as temporary storage. However, tricking the compiler into implicitly holding a value in a register is fine. My friend and I sat and thought on this one, and came up with three different solutions. Im certain there are probably more out there. Let me know as you find them. ^_^

SOLUTIONS
The next pages show solutions. No cheating now

Solution 1 The Loop


This loop makes most sense if you look at the value of a in binary. Starting with just some nonzero value, lets say 42, heres all the loop iterations:
a a a a = = = = 101010 101000 100000 000000 b b b b = = = = 0 1 2 3

In other words, when the loop terminates, b holds the count of the number of bits that had been set high (1) in the starting value of a. In this example, the number 42 has three high bits.

Solution 2 The Macro


Step by step, heres what the macro does: 1) Type-cast 0, or NULL, into a pointer of type a. So a must be a typename. 2) Member-select b from that pointer. member property. So a must be a structure typename, and b some

3) Take the address of b. Since the a* were using points to address 0, and b is some offset above the start of the a-structure this means were getting the offset of b within a plus the address of a, which is zero. That is, we get the offset of b within a. 4) Typecast that number to an integer. So, in short, a is a type of structure with some member b. This macro returns the byte-offset of b within a.
struct Bar_s { int x, y, z; }; /* For 32 bit integers, FOO( Bar_s, z ) == 12, unless your compiler does odd memory layout optimizations. Hence the reason for using a macro -- it's more portable than trying to guess how your compiler aligns data. */

So why is this a cool way of finding the offset? Note that we dont actually have a real instance of the structure floating around, just the typename. In other words, this whole block of operations is a constant expression and gets reduced to a single constant number by the compiler. There is absolutely no CPU time spent calculating this expression at run-time. Ive found this macro is more quickly recognized by someone whos done embedded systems work, though it came to me by means of game programmers. It can actually be found in one of the MS Windows header files though, which helps to show how generically useful it is.

Solution 3 List Walking


The solution is to use a binay XOR (mathematically , or in C ^) to combine the next and prev pointers into a single sibling pointer. This works because XOR is non-destructive in that, given variables A, B, and C where C = A B, you can XOR any two of the variables to retrieve the third. If C = A B, then A = B C, and B = A C. XOR is also communitive, meaning A B = B A. Alright, translating that from math to a more intuitive gut understanding, this says that we can store in every node a single pointer:
struct ListNode { ListNode * sibling; int payload; }; /* sibling = next ^ prev */

By the rules of XOR above, if you are sitting with a single node, and you know the prev pointer already in some external variable, you can extract the next pointer by this:
next = prev ^ listNode.sibling;

So at what point do you have the next or prev pointer in an external variable? At one of the ends of the list, of course, where NULL is used to terminate the list. And then you can walk along the list in either direction from there, unraveling as you go.
ListNode * head; /* initialize the list */ ListNode * next, * prev, * current; current = head; prev = NULL; while( current != NULL ) { next = current->sibling ^ prev; /* Do what processing you need with the current node */ All three pointers (next, prev, current) are valid right here */ prev = current; current = next; }

So, the added restriction is that your doubly linked list cant be circular. This is a pretty meaningless statement because I never said it was circular in the first place. But ask your geeky

friends this question. In my experience, at least half will hear doubly linked and think circularly doubly linked automatically.

Solution 4 Single Character


The three fixes are enumerated below:
int i; int n = 20; for( i = 0; i < n; n -- ) printf(-); int i; int n = 20; for( i = 0; i + n; i -- ) printf(-); int i; int n = 20; for( i = 0;-i < n; i -- ) printf(-);

Solution 5 Swapping (open problem)


Remember, this is an open problem, so these are not necessarily all the solutions. Assume in all cases the two variables are A and B. 1. XOR
A ^= B ^= A ^= B;

2. Math
A = B A; B = B A; A = B + A;

3. Order of Operations
B = (((A + A) / 2) + (A = B) B);

The trick in this solution is that ((A + A) / 2) y ields the value A without being stored in the variable A anymore. So to this we add (A = B), which in turn evaluates to B. So the total expression has become A + B. To make this only A, we have to subtract off the extra B.

THANKS
In general these problems were presented to me as things for me to solve. Credit though is due to the people who first brought each problem or solution under my nose.

Thanks 1 The Loop


My interviewers when I sought an internship at WRQ, Inc. This was one of the interview problems.

Thanks 2 The Macro


Jan Chong, my friend and office mate during a Microsoft internship.

Thanks 3 List Walking


Reed Townsend, a colleague at Microsoft Corp.

Thanks 4 Single Character


Uri London, a dev lead at Microsoft Corp.

Thanks 5 Swapping (open problem)


Joe Buys, a friend at the U of Washington

All errors are my own. Send comments, complaints, criticisms, or other problems/solutions to me alone: wyvern@dracat.net Thanks for playing. =)

You might also like