Solutions

(credit to Franco Callari for all of these problems and solutions; some of his solutions have been modified for pedagogical purposes)
1.
#include <stdio.h>

int main(int argc, char *argv[]) 
{
   printf("hello, world\n");
}

2.

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) 
{
   char str[] = "hello, world";
   char *c = strchr(str, '\0'); /* const strings end with \0 */
    
    do 
      putchar(*(--c));
    while(c>str);
    putchar('\n');
}

3.

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) 
{
   char str[] = "hello, world";
   char *c = str;
   int j;

   for (j=1; j<=10; j++) {
      c=str;

      do 
	putchar(*c);
      while(*(++c));
      putchar('\n');

      do 
	putchar(*(--c));
      while(c>str);
      putchar('\n');
   }
}

4.

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) 
{
   char str[] = {104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 0};
   char *c = str;
   
   do 
      putchar(*c);
   while(*(++c));
   putchar('\n');
}

5.

#include <stdio.h>
#include <string.h>

void hello(char *c)
{
   do 
      putchar(*c);
   while(*(++c));
   putchar('\n');
}
    
/*
 * need to pass a pointer to the start of string 
 * (which we will call "stop"!) so we know when to 
 * stop
 */
void olleh(char *c, char *stop)
{
   do 
      putchar(*(--c));
   while(c>stop);
   putchar('\n');
}
    
int main(int argc, char *argv[]) 
{
   char str[]="hello, world";
   void hello(char *);
   void olleh(char *, char *);

   hello(str);
   olleh(str+strlen(str), str);	/* another way to find the end of string */
}

6.

#include <stdio.h>
#include <string.h>

/*
 * At this point, we will ignore the earlier prohibition
 * against maintaining the string anywhere in the source.
 * After all, we've already shown how to do so...
 */
void hello(void)
{
    printf("hello, world\n");     
}

void olleh(void)
{
    printf("dlrow ,olleh\n");     
}

/*
 * Note: for more serious parsing of command line arguments, 
 * see getopt(3) as this makes life a lot easier...
 */
int main(int argc, char *argv[]) 
{
   int r;
   char str[] = "hello, world";
   void hello(void);
   void olleh(void);

   while (1) {
      puts("Enter one of\nF: Forward\nB: Backward\nQ: Quit");
      r = getchar();
      switch (r) {
         case 'F':
         case 'f':
            hello();
            break;
         case 'B':
         case 'b':
            olleh();
            break;
         case 'Q':
         case 'q':
            exit(0);
      }

      getchar();  /* do this to get rid of straggling new line */
   }
}

7.

/* This is a very basic context switcher
 * using the alarm(2) routine to interrupt (after one second)
 * the two routines that print the strings (and never return).
 */
 
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <setjmp.h>

#define DELAY 1  
#define HELLO 1
#define OLLEH 2

/* SIGINT handler */
void terminator(int sig) 
{
   printf("All done!\n");
   exit(0);
}

/*
 * introduce this silly loop because machines nowadays are
 * so bloody fast that they will generate way too much output
 * in the one second DELAY period that we won't be able to see
 * the effects of the switch
 */
void idler() {
	int i, a;

	for (i = 0; i < 1000000; i++)
		a = (a + i)/2;
}

void hello(void)
{
    while (1) { printf("hello, world\n"); idler(); }
}

void olleh(void)
{
    while (1) { printf("dlrow ,olleh\n"); idler(); } 
}

jmp_buf main_loop; /* jump buffer: saves current state of program. */
int whichone;      /* HELLO or OLLEH */

/*
 * SIGALRM handler: switches routine to run next, rearms
 * alarm clock, then longjmps back.  Read the man pages
 * on setjmp(3) and longjmp (3) for further details.
 */
void switcher(int sig) 
{        
    extern jmp_buf main_loop;
    extern int whichone;

    /* Switch routine to run next. */
    whichone = whichone == HELLO ? OLLEH : HELLO;
    
    /* Rearm alarm */
    signal(SIGALRM, switcher);
    alarm(DELAY);

    /* All set. Back to main. */
    longjmp(main_loop, whichone);
}


int main(int argc, char *argv[]) 
{
    extern int whichone;
    extern jmp_buf main_loop;
    void hello(void);
    void olleh(void);
    void terminator(int);
    
    printf("Starting switcher (hit CTRL-C) to quit\n");
    sleep(3); /* Give the user a chance to read this message! */

    switch(setjmp(main_loop)) {
      case 0:           /* First time initialization. */
        signal(SIGINT, terminator); /* CTRL-C terminator */
        whichone = OLLEH;           

	/*
	 * We will force the OS to switch between tasks every second
	 * by installing a signal handler on SIGALRM (the alarm signal).
	 * Then, to get things going, send ourselves the alarm.
	 * Since some UNIX systems don't support raise(2), use the
	 * generic kill(2) command.  Note that there is no need for
	 * break statements following each case, since control will
	 * not return to the caller if the task handlers are called.
	 */
        signal(SIGALRM, switcher);  /* Install switcher */
	kill (getpid(), SIGALRM);   /* send myself the alarm to activate */

      case HELLO:
        hello();		    /* no need to break next */

      case OLLEH:
        olleh();		    /* no need to break next */
    }
}