The behavior you observed :
The real confusing part is that it doesn't reinitialize it to 0 every time the recursive function calls itself. It's like this whole line of code static int i = 0; is skipped?
is exactly what you are asking for with static. A local static variable is initalized the first time its definition (i.e, the line static int i = 0;) is reached.
In your case it means it will be set to zero only on the first call ever to this method during the whole runtime of your program. There is no notion of multiple recursive calls to the same function, so it will make no difference if the method is invoked by itself (the multiple recursive call you are referring to) or if you are starting a whole new stack of recursion somewhere else in your client code.
Possible solution
To go back on your description, it will only work with i being static (for n!=1) because, if your removed static keyword, then i would be initialized to zero each time the method is entered (a different local instance of i for each invocation of the method). Thus in your condition
if(++i == n)
++i would always evaluate to 1, independently of the recursion depth.
If you want the static i to be reinitialized each time you call your method in your client code (i.e. to start a new stack of recursion), you could write it like :
void printNthFromLast(Node* head, int n, bool reinit=true)
{
static int i = 0;
if(reinit)
{
i=0;
}
if(head == nullptr)
return;
printNthFromLast(head->next, n, false);
if(++i == n)
cout << head->data;
}
Thread safe with tail call optimization
A cleaner solution would be to have i as a mutable parameter to the function, so your function would be thread-safe. And with a better ordering of the operation, you do not need to save the previous invocation frame, thus enjoying tail call optimization offered by most of recent compilers.
EDIT : As pointed by Matthieu, my original implementation printed the Nth element instead of the Nth from last element. Fixing while enabling TCO is less elegant, but can be done as follows :
/// n==1 means printing the last element here
static void printNthFromLastImpl(const Node* currentNode, const Node* offsetNode, const int n, int currentDepth)
{
// n == 0 will never print in the original example by op, so forbid it
assert(n);
if(++currentDepth > n)
{
offsetNode = offsetNode->next;
}
if(currentNode->next)
{
currentNode = currentNode->next;
}
else
{
if(currentDepth >= n)
{
cout << offsetNode->data;
}
return;
}
return printNthFromLastImpl(currentNode, offsetNode, n, currentDepth);
}
/// \brief : code to call from client
static void printNthFromLast(const Node* head, const int n)
{
if (head)
{
printNthFromLastImpl(head, head, n, 0);
}
}