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

void problem1(void) {
  struct name {
    char last[50] ;
    char first[50] ;
  } ;
  struct name iam ;
  puts("\n\nProblem 1") ;
  strcpy(iam.last, "Brock") ;
  strcpy(iam.first, "Dean") ;
  printf("  My name is %s %s\n", iam.first, iam.last) ;

}

void problem2(void) {
  char x ;
  char * const y = &x ;    /* &x to avoid uniitialized variable message */
  char const * z = &x ;
  /* y  = &x ;     error: assignment of read-only variable y */
  z  = &x ;
  *y = 'A' ;
  /* *z = 'B' ;    error: assignment of read-only location *z    */
  /* z  = 'C' ;    warning: assignment makes pointer from integer */
  z = y ;
}

#define PRINTINT(m) {whole = 10 ; fract = 2.5; cword = "2011" ; \
   printf("%-30s is %5d\n", #m, m); }
#define PRINTDBL(m) {whole = 10 ; fract = 2.5; cword = "2011" ; \
   printf("%-30s is %5.2f\n", #m, m); }
#define PRINTSTR(m) {whole = 10 ; fract = 2.5; cword = "2011" ; \
   printf("%-30s is \"%s\"\n", #m, m); }

void problem3(void) {
  int    whole = 10 ;
  double fract =  2.5 ;
  char  *cword = "2011" ;  /* '0' to '9' is 48 to 57*/
  puts("\n\nProblem 3") ;
  PRINTINT(cword[2]) ;
  PRINTSTR(cword+2) ;
  PRINTINT(++whole) ;
  PRINTINT(whole++) ;
  PRINTDBL(whole / fract) ;
  PRINTDBL(whole * fract) ;
  PRINTINT(whole = fract) ;
  PRINTDBL(fract = whole) ;
  PRINTINT(whole-- / 5 ) ;
  PRINTINT(--whole == 10 || whole) ;
  PRINTINT(whole += -10) ;
  /* This is legal C.  It's the same as fract + --5 or fract + 10 */
  /* Of course, it was supposed to be fract += -5 */
  PRINTDBL(fract +- -5) ;
  PRINTINT(1 && whole++ ? whole : 0 ) ;
  PRINTINT(1 || whole++ ? whole : 0  ) ;
  PRINTINT(strlen(cword)) ;
  PRINTINT(strlen(&cword[2])) ;
  PRINTINT(cword[4]) ;
  PRINTINT(strstr(cword, "12") == NULL) ;
  PRINTSTR(strchr(cword, '0')) ;
  PRINTINT(!isalpha(*cword)) ;
  PRINTINT(* ++ cword) ;
  PRINTINT(* cword ++) ;
  PRINTINT(5 / 3) ;
  PRINTINT(5 % 3) ;
  PRINTDBL(5.0 / 3) ;
  PRINTDBL(5 / 3 * 5.0) ;
  PRINTINT(5 + 4 * 2) ;
  PRINTINT(5 * 4 + 2) ;
  PRINTINT(4 * 2 / 4) ;
  PRINTINT(4 / 2 * 4) ;
  PRINTINT((int) 3.2 + 2) ;
  PRINTINT(5.2 > 5) ;
  PRINTINT(5.2 < 5.0) ;
  PRINTINT((2, 3) + 5) ;
  PRINTINT(6 > 5 > 4) ;
  PRINTINT(4 && 5) ;
  PRINTINT(5 == (4 || 5)) ;
  PRINTINT(! 5) ;
  PRINTINT(1 && 0 + 1) ;
  PRINTINT(1 + 0 && 1) ;
  PRINTINT((5 || 7) && ! (5 || 7)) ;
  PRINTINT('5' - '3') ;
}

void problem4(void) {
  double x ;
  puts("\n\nProblem 4") ;
  x = 555.5555 ;
  printf("x is [%9.3f]\n", x) ;
  x = 0.5555 ;
  printf("x is [%.0f%%]\n", x*100) ;
  printf("x is [%d%%]\n", (int)(x*100+0.5)) ;
}

void problem5(void) {

    puts("\n\nProblem 5") ;

    puts("\n  loop 1") ;
    {
      int i = 5 ;
      int j = 6 ;
      while (i != j) {
	i = j ;
	j = i ;
	printf("%d\n", i) ;
      }
    }

    puts("\n  loop 2") ;
    {
      int i ;
      for (i=0; i<2 || ++i<5; ++i){
	printf("%d\n", i) ;
      }
    }


    puts("\n  loop 3") ;
    {
      int i = 10 ;
      while (i > 4) {
	i /= 2 ;
	printf("%d\n", i) ;
      }
    }

    puts("\n  loop 4") ;
    {
      int   i ;
      char *c = "ECE209" ;
      for (i=0; c[i]!='\0'; i+=2) {
	printf("%c\n", c[i]) ;
      }
    }

    puts("\n  loop 5") ;
    {
      int i = -3 ;
      while (i+1) {
	printf("%d\n", ++i) ;
      }
    }

    puts("\n  loop 6") ;
    {
      int pcount = 0 ;
      int i ;
      for(i=0; i<4; i=i*i) {
	printf("%d\n", i) ;
	if (++pcount == 4) break ;
      }
    }

    puts("");
}

void problem6(void) {
  int *p ;
  int *q ;
  int  v[3] ;

  puts("\n\nProblem 6") ;

  v[0] = 222 ;
  v[1] = 333 ;
  v[2] = 555 ;
  printf("%d %d %d\n", v[0], v[1], v[2]) ;

  p = &v[0] ;
  v[0] = *(p++) ;
  /* There is an unintended order-of-valuation ambiguity.
   * C doesn't specify if the order of the ++ and the = here.
   * When this statement is executed, p is pointing to v[1]
   * which has the value of 333.
   * If = is done before ++, v[1] will be assigned 334.
   * If ++ is done before +, v[1] will be assigned 333.
   * Either answer was accepted.
   * GCC generates code to do = first.
   */
  v[1] = (*p)++ ;
  v[2] = *p+*p;
  /* At this point, p points to v[1] */
  printf("%d %d %d\n", v[0], v[1], v[2]) ;

  p = &v[1] ;
  q = p+1 ;
  *p = *p + 2 ;
  *q = *q + 3 ;
  /* p points to v[1] and q points to v[2] */
  printf("%d %d %d\n", v[0], v[1], v[2]) ;

  p = q = &v[0] ;
  *p = *p + 2 ;
  *q = *q + 3 ;  
  /* both p and q points to v[0] */
  printf("%d %d %d\n", v[0], v[1], v[2]) ;

  p = &v[0] ;
  q = p ;
  /* both p and q points to v[0] */
  ++*++p ;
  /* now p points to v[1] */
  printf("%d %d %d\n", v[0], v[1], v[2]) ;

  ++*p++ ;
  /* now p points to v[2] */
  *p = p-q ;
  printf("%d %d %d\n", v[0], v[1], v[2]) ;
}

/* These next two functions aren't part of the answer.
 * They just allow the answer to be written.
 */
int cmpDbl(const void *pX,  const void *pY) {
  double X, Y ;
  X = *(double *)pX ;
  Y = *(double *)pY ;
  return X<Y ? -1 : X==Y ? 0 : 1 ;
}

double median(const double V[], int N) {
  double *copyV ;
  int i ;
  double r ;
  copyV = calloc(N, sizeof(double)) ;
  for (i=0; i<N; ++i) {
    copyV[i] = V[i] ;
  }
  /* Avoid writing sorts */
  qsort((void *)copyV, N, sizeof(double), &cmpDbl) ;
  r = (copyV[(N-1)/2] + copyV[N/2])*0.5 ;
  free(copyV) ;
  return r ;
}

void problem7(void) {
  int size ;
  double *values ;
  double medValue ;
  int i, numLo, numHi ;
  double totLo, totHi ;
  puts("\n\nProblem 7") ;
  printf("\nEnter some input for Problem 7A\n") ;

  /* Subproblem 7A solution */
  scanf("%d", &size) ;
  values = calloc(size, sizeof(double)) ;
  for (i=0; i<size; ++i) {
    scanf("%lf", &values[i]) ;
  }

  /* Subproblem 7B solution */
  medValue = median(values, size) ;

  /* Subproblem 7C solution */
  numLo = 0 ;
  totLo = 0.0 ;
  numHi = 0 ;
  totHi = 0.0 ;
  for (i=0; i<size; ++i) {
    if (values[i] < medValue) {
      ++numLo ;
      totLo += values[i] ;
    } else if (values[i] > medValue) {
      ++numHi ;
      totHi += values[i] ;
    }
  }
  printf("Average < median is %8.3f\n", totLo/numLo) ;
  printf("Average > median is %8.3f\n", totHi/numHi) ;
}

#define NUMROWS  8
#define NUMCOLS 16
const char examExample[NUMROWS][NUMCOLS] = {
  "++++++++|+++++++" ,
  "+ \\/ece | \\\\/  +" ,
  "+ /\\    | //\\ \\/" ,
  "+   \\ \\/|     /\\" ,
  "+ \\/  /\\| / hi +" ,
  "--------+-------" ,
  "+ /    /|\\     +" ,
  "++++++++|+++++++"
} ;

const char nomatch[NUMROWS][NUMCOLS] = {
  "0123456|89abcdef" ,
  "0123456|89abcdef" ,
  "0123456|89abcdef" ,
  "0123456|89abcdef" ,
  "0123456|89abcdef" ,
  "0123456|89abcdef" ,
  "0123456|89abcdef" ,
  "0123456|89abcdef"
} ;

const char doublematch[NUMROWS][NUMCOLS] = {
  "0123456|89abcdef" ,
  "0123456|89abcdef" ,
  "-------+--------" ,
  "0123456|89abcdef" ,
  "-------+--------" ,
  "0123456|89abcdef" ,
  "0123456|89abcdef" ,
  "0123456|89abcdef"
} ;


void problem8(const char probGrid[NUMROWS][NUMCOLS]) {
  int i, j ;
  int possibleRows ;
  int gridRow ;
  int gridColumn ;
  /* Problem 8 solution */
  possibleRows = 0 ;
  for(i=0; i<NUMROWS ; ++i) {
    int numPlus = 0 ;
    int numHyphen = 0 ;
    int posPlus ;
    for(j=0; j<NUMCOLS; ++j) {
      if (probGrid[i][j] == '+') {
	numPlus++ ;
	posPlus = j ;
      } else if (probGrid[i][j] == '-') {
	numHyphen++ ;
      }
    }
    if (numHyphen == NUMCOLS-1 && numPlus == 1) {
      ++possibleRows ;
      gridRow = i ;
      gridColumn = posPlus ;
    }
  }
  /* just printing the result -- not part of the solution*/
  printf("  possibleRows is %d\n", possibleRows) ;
  if (possibleRows == 1) {
    printf("  gridRow      is %d\n", gridRow) ;
    printf("  gridColumn   is %d\n", gridColumn) ;
  }
}


void problem8tester(void) {
  puts("\n\nProblem 8") ;
  puts("\n Exam example") ;
  problem8(examExample) ;
  puts("\n No match") ;
  problem8(nomatch) ;
  puts("\n Two matches") ;
  problem8(doublematch) ;
}

void problem9(void) {
  int first, last, inP, outP ;
  char *aPos ;
  char s[100] ;
  puts("\n\nProblem 9") ;

  strcpy(s, "  a little off the sides  ") ;
  printf("  Original string: \"%s\"\n", s) ;

  /* Subproblem 9A solution */
  /* Set first to first non-space */
  for (first=0; s[first] && isspace(s[first]); ++first) { }
  /* Set last to last non-space */
  for (last=strlen(s)-1;  last>=0 && isspace(s[last]); --last) { }
  /* Move up the string */
  for (outP = 0, inP = first; inP <= last; ++inP, ++outP) {
    s[outP] = s[inP] ;
  }
  s[outP] = '\0' ;

  printf("  Modified string: \"%s\"\n", s) ;


  strcpy(s,
	 "Charlotte Parker is going to Charlotte, NC, to visit UNC Charlotte."
	 ) ;
  printf("  Original string: \"%s\"\n", s) ;

  /* Subproblem 9B solution */
  aPos = s ;
  while ((aPos = strstr(aPos, "Charlotte")) != NULL) {
    /* see if it is followed by a punctuation mark */
    if (ispunct(aPos[9])) {
      strncpy(aPos, "Asheville", 9) ;
    }
    aPos = aPos + 9 ;
  }

  printf("  Modified string: \"%s\"\n", s) ;
}

/* datatype needed for Problem 10 */
typedef struct sparceElementRec *sparceElementPtr ;

struct sparceElementRec {
  int    row ;                        /* Position in the matrix  */
  int    col ;
  int    value ;                      /* Value of element  */
  sparceElementPtr   nextOnRow ;      /* Pointers to other nodes */
  sparceElementPtr   nextOnCol ;
} ;

struct sparceMatrix {
  int    numRows ;                    /* number of rows */
  int    numCols ;                    /* number of columns */
  sparceElementPtr   *rows ;          /* rows */
  sparceElementPtr   *cols ;          /* columns */
} ;

/* Problem 10A */
sparceElementPtr allocateElement(int row, int col) {
  sparceElementPtr theOne ;
  theOne = (sparceElementPtr)malloc(sizeof(struct sparceElementRec)) ;
  if (theOne == NULL) {
    return NULL ;
  }
  theOne->row = row ;
  theOne->col = col ;
  theOne->value = 0 ;
  theOne->nextOnRow = NULL ;
  theOne->nextOnCol = NULL ;
  return theOne ;
}


/* Problem 10B */
void multiplySparceMatrix(struct sparceMatrix *M, int k) {
  int r ;
  for (r=0; r<M->numRows; ++r) {
    sparceElementPtr theOne = M->rows[r] ;
    while (theOne != NULL) {
      theOne->value *= k ;
      theOne = theOne->nextOnRow ;
    }
  }
}

void final(void) {
  puts("Final exam\n") ;
  problem1() ;
  problem2() ;
  problem3() ;
  problem4() ;
  problem5() ;
  problem6() ;
  problem7() ;
  problem8tester() ;
  problem9() ;
}

int main(int argc, char *argv[]) {
  final() ;
  return EXIT_SUCCESS ;
}
