The reason you're getting the same TID for each thread is that you're calling syscall(SYS_gettid) from the main thread each time, rather than from within the new thread you create.  You need to call it from inside your thread function and then provide a way to pass the information back to the main thread if it's needed there.  
As an example of one way to do it (some error checking omitted):
Create a struct to hold a mutex, condition, the TID, and a flag to indicate when the TID is valid.
struct s_threadId {
  pthread_mutex_t   mtx;    /* mutex & condition to allow main thread to
                               wait for the new thread to  set its TID */
  pthread_cond_t    cond;   /* '' */
  pid_t             id;     /* to hold new thread's TID */
  int               ready;  /* to indicate when 'id' is valid, in case
                               the condition wait gets interrupted */
};
Then change your thread function to lock, set, and signal (and move it so that it's declaration is visible before spawnThreads()):
void *foo(void *arg)
{
  struct s_threadId *thId = arg;
  /* Lock mutex... */
  pthread_mutex_lock(&thId->mtx);
  /* Get and save TID and ready flag.. */
  thId->id = syscall(SYS_gettid);
  thId->ready = 1;
  /* ..and signal main thread that we're ready */
  pthread_cond_signal(&thId->cond);
  /* ..then unlock when we're done. */
  pthread_mutex_unlock(&thId->mtx);
  /* ... */
  return NULL;
}
...and modify your spawnThreads function to initialize/cleanup the struct members and get the TID once the thread sets it:
void spawnThreads(unsigned int n)
{
  pthread_t thread; /* reused for each thread, since they run 1 at a time */
  /* struct to pass back TID */
  struct s_threadId threadId;
  pthread_cond_init(&threadId.cond, NULL);  /* init condition */
  pthread_mutex_init(&threadId.mtx, NULL);  /* init mutex */
  int i;
  for (i = 0; i < n; i++) {
    /* lock mutex *before* creating the thread, to make the new thread
       wait until we're ready before signaling us */
    pthread_mutex_lock(&threadId.mtx);
    /* clear ready flag before creating each thread */
    threadId.ready = 0;
    /* create threads and pass address of struct as argument */
    if (pthread_create(&thread, NULL, foo, &threadId)) {
      printf("pthread error!\n");
    } else {
      /* Wait on the condition until the ready flag is set */
      while (!threadId.ready) {
        pthread_cond_wait(&threadId.cond, &threadId.mtx);
      }
      /* Now we have the TID... */
      printf("%d %d\n", i, threadId.id);
      printf("I just created thread %d\n", i);
    }
    /* ..and unlock the mutex when done. */
    pthread_mutex_unlock(&threadId.mtx);
    pthread_join(thread, NULL);
  }
  /* When we're completely done with the struct we need to clean up the
     mutex and condition variable */
  pthread_mutex_destroy(&threadId.mtx);
  pthread_cond_destroy(&threadId.cond);
}
In the above, the mutex and condition wait are needed to make sure that the main thread doesn't try to print the TID until the new thread has had a chance to set it.  The main thread starts the new one and then waits, and the new thread signal when it's done storing the TID so the main thread can continue.