K & R Chapter 4 Study Questions

/*********************** General Comments *********************/
// 1. To compile individual programs (P1, for example) on the linux command-line:
// gcc -D P1 ch4_studyQuestions.c

// Many of the programs come directly from Chapter 4 of K&R.

#ifdef P1
// K&R, Ch4, pg. 71
// Note: renamed getline() to my_getline to avoid naming conflict with stdio.h
// Topic: General control question.
// Question: (T or F) In my_getline(): When getchar() returns a '\n', the '\n' is always copied to s.

#include <stdio.h>
#define MAXLINE 1000  /* maximum input line length */

int my_getline(char line[], int max);
int strindex(char source[], char searchfor[]);

char pattern[] = "ould";  /* pattern to search for */

/* find all lines matching pattern */
int main() {
  char line[MAXLINE];
  int found = 0;

  while (my_getline(line, MAXLINE) > 0)
    if (strindex(line, pattern) >= 0) {
      printf("%s", line);
      found++;
    }
  return found;
}
#endif

// Need getline for multiple questions.
#include <stdio.h>
/* getline: get line into s, return length */
int my_getline(char s[], int lim) {
  int c, i;

  i = 0;
  while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
    s[i++] = c;
  if (c == '\n')
    s[i++] = c;
  s[i] = '\0';
  return i;
}

#ifdef P1
/* strindex: return index of t in s, -1 in none */
int strindex( char s[], char t[]) {
  int i, j, k;

  for (i = 0; s[i] != '\0'; i++) {
    for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++)
      ;
    if (k > 0 && t[k] == '\0')
      return i;
  }
  return -1;
}
#endif

#ifdef P2
#include <stdio.h>
// Topic: What is the default return type for functions without a declared prototype.
// Question: Looking just at the main function below, what does the compiler assume is the
// return type within main()
// when the return type for atof() if the line "double atof(char[]);" is deleted?
// NOTE: If you delete the "double atof(... line, the C++ compiler generates an error, not a warning.
// Carefully read Chapter 4 so you understand what the default return type is for functions.
#define MAXLINE 100
/* rudimentary calculator */
int main() {
  double sum;
  double atof(char[]);
  char line[MAXLINE];
  int my_getline(char line[], int max);

  sum = 0;
  while (my_getline(line, MAXLINE) > 0)
    printf("\t%g\n", sum += atof(line));
  return 0;
}

// Note: Program from Ch 4 of K&R, pgs. 71-72.
// Topic: How are characters encoded?
// Question: (T or F) '0' is equivalent to '\0'

// Question: What value does this expression return: 1000 - '0'?

// Question: What value does this expression return: '1' - '0'?

// Topic: General
// Question: (T or F) for-loop A terminates immediately when the input contains '.'

// Question: If  return-statement C was modified to "return sign * val;", and the number 003.05 was typed in, the program would print:

#include <ctype.h>

/* atof: convert string s to double */
double atof(char s[]) {
  double val, power;
  int i, sign;

  for (i=0; isspace(s[i]); i++)  /* skip white space */
    ;
  sign = (s[i] == '-') ? -1 : 1;
  if (s[i] == '+' || s[i] == '-')
    i++;
  for (val = 0.0; isdigit(s[i]); i++)  // for-loop A
    val = 10.0 * val + (s[i] - '0');
  if (s[i] == '.')
    i++;
  for (power = 1.0; isdigit(s[i]); i++) {  // for-loop B
    val = 10.0 * val + (s[i] - '0');
    power *= 10.0;
  }
  return sign * val / power;  // Return Statement C
}
#endif

#ifdef P3

#include <stdio.h>
#include <stdlib.h>
#define MAXOP 100   // max size of operand or operator.
#define NUMBER '0'  // Signal that a number was found.
int getop(char[]);
void push(double);
double pop(void);

// Reverse Polish calculator
int main() {
  int type;
  double op2;
  char s[MAXOP];

  while ((type = getop(s)) != EOF) {
    switch (type) {
    case NUMBER:
      push(atof(s));
      break;
    case '+':
      push(pop() + pop());
      break;
    case '*':
      push(pop() * pop());
      break;
    case '-':
      // push(pop() - pop() is WRONG. pop() on left-hand-side of - could be either the first or second pop
      // because C does not enforce the order that arguments are evaluated.
      op2 = pop();
      push(pop() - op2);
      break;
    case '/':
      op2 = pop();
      if (op2 != 0.0)
	push(pop() / op2);
      else
	printf("error: zero divisor\n");
      break;
    case '\n':
      printf("\t%.8g\n", pop());
      break;
    default:
      printf("error: unknown command %s\n", s);
      break;
    }
  }
  return 0;
}

#define MAXVAL 100 // maximum depth of stack.

int sp = 0;
double val[MAXVAL];
// push: push f onto value stack.
void push(double f) {
  if (sp < MAXVAL)
    val[sp++] = f;
  else
    printf("error: stack full, can't push %g\n.", f);
}

// pop: pop and return top value from stack
double pop(void) {
  if (sp > 0)
    return val[--sp];
  else {
    printf("error: stsack empty\n");
    return 0.0;
  }
}

#include <ctype.h>
int getch(void);
void ungetch(int);

// getop: get next operator of numeric operand.
int getop(char s[]) {
  int i, c;
  // Question: (T or F) The sole purpose of the statement below is to skip over spaces and tabs.
  while ((s[0] = c = getch()) == ' ' || c == '\t')
    ;
  s[1] = '\0';
  if (!isdigit(c) && c != '.')
    return c;  // not a number.
  i = 0;
  if (isdigit(c))  // collect integer part.
    while (isdigit(s[++i] = c = getch()))
      ;
  if (c == '.') // collect fractional part.
    while (isdigit(s[++i] = c = getch()))
      ;
  s[i] = '\0';
  if (c != EOF)
    ungetch(c);
  return NUMBER;
}

#define BUFSIZE 100
char buf[BUFSIZE];
int bufp = 0;  // next free position in buf.

int getch(void) {
  return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c) {  // push character back on input.
  if (bufp >= BUFSIZE)
    printf("ungetch: too many characters.\n");
  else
    buf[bufp++] = c;
}
  
#endif

// Topic: Scope.
// Question: (T or F) The scope of a name is the part of the program within whch the name can be used.

// Topics: variable scope, initialization of variables, external linkage.
// For the questions that use P4 - P12, study the differences to see what
// causes compilation errors.

#ifdef P4
// Question (T or F) The program below will compile without error.
#include <stdio.h>
int main() {
  printf("%d\n", my_variable);
}
int my_variable;

#endif

#ifdef P5
// Question (T or F) The program below will compile without error.
#include <stdio.h>
int my_variable = 4;
int main() {
  printf("%d\n", my_variable);
}
int my_variable;

#endif

#ifdef P6
// Question (T or F) The program below will compile without error.
#include <stdio.h>
int my_variable=4;
int main() {
  printf("%d\n", my_variable);
}
int my_variable=5;

// Error: ch4_studyQuestions.c:278:5: error: redefinition of 'my_variable'
#endif

#ifdef P7
// Question (T or F) The program below will compile without error.

// in my_variable is a declaration, int my_variable=5 is a definition.
// illegal for g++: ch4_studyQuestions.c:292:5: error: redefinition of 'my_variable'
#include <stdio.h>
int my_variable;
int main() {
  printf("%d\n", my_variable);
}
int my_variable=5;
#endif

#ifdef P8
// Question (T or F) The program below will compile without error.

#include <stdio.h>
int my_variable = 4;
int main() {
  int my_variable = 3;
  printf("%d\n", my_variable);
}
#endif

#ifdef P9
// Question (T or F) The program below will compile without error.

#include <stdio.h>
int my_variable = 4;
int main() {
  static int my_variable = 3;
  printf("%d\n", my_variable);
}
#endif

#ifdef P10
// Question (T or F) The program below will compile without error.

#include <stdio.h>
static int my_variable = 4;
int main() {
  static int my_variable = 3;
  printf("%d\n", my_variable);
}
#endif

#ifdef P11
// Question (T or F) The program below will compile without error.

// Note: variables cannot be seen outside of the block where they are declared.
#include <stdio.h>
int my_variable = 4;
int main() {
  int my_variable = 3; {
    int my_variable = 4;
  }
  printf("%d\n", my_variable);
}
#endif

#ifdef P12
// Topic: scope.
// Question How many compilation errors will this program generate?

#include <stdio.h>
double foo () {return 2;}
double my_variable = 4 * 3 / foo();
int main() {
  double my_variable = 4 * 3 / foo();
  printf("%f\n", my_variable);
}
#endif

#ifdef P13
#include <stdio.h>
// Recursive printd
void printd(int n) {
  if (n < 0) {
    putchar('-');
    n = - n;
  }
  if (n / 10)
    printd(n / 10);
  putchar (n % 10 + '0');
}

int main() {
  printd(1234);
}
#endif

#ifdef P14
#include <stdio.h>

int fib(int x) {
    if (x == 0)
        return 0;

    if (x == 1)
        return 1;

    return fib(x-1)+fib(x-2);
}

int main() {
  int inputValue = 10;
  for (int i=0; i<=inputValue; i++)
    printf("fib(%d):%d\n", i, fib(i));
}

#endif

#ifdef P15
// Topic: Writing and using macros.
// Question: What value will this program print?

#define max(A, B) ((A) > (B) ? (A) : (B))
int main() {
  int i=0, j=0;
  int val = max(i++, j++);
  printf("%d\n", val);
}

#endif

#ifdef P16
// Topic: Writing and using macros.
// Question: What value will this program print?
#define square(x) x * x
#include <stdio.h>
int main() {
  int value = square(2-1);
  // Note: converts to 2 -1 * 2 - 1 -> 2 - (-1 * 2) - 1
  printf("%d\n", value);
}

#endif

#ifdef P17
#include <stdio.h>
int main() {
  printf("%d\n", '0');
}
#endif

#ifdef P18
// Topic: Using the extern keyword.
// Question: What will this program print?
// Ans: 
#include <stdio.h>
int my_variable = 5;
int main() {
  int foo(int);
  int my_variable = 6;
  printf("%d\n", foo(my_variable));
}

int foo(int a) {
  extern int my_variable;
  return my_variable + a;
}
#endif