《C语言入门经典》Ivor Horton

// Exercise 1.1 Output a name and address
#include <stdio.h>

int main(void)
{
  printf("George Washington\n");
  printf("3200 George Washington Memorial Parkway\n");
  printf("Mount Vernon\n");
  printf("Virginia 22121\n");
  return 0;
}
/**********************************************************************************/
// Exercise 2.1 Convert inches to yards, feet, and inches
#include <stdio.h>

int main(void)
{
  int inches = 0;
  int yards = 0;
  int feet = 0;
  const int inches_per_foot = 12;  // There are 12 inches in 1 foot.
  const int feet_per_yard = 3;     // Rhere are 3 feet in 1 yard.

  printf("Enter a distance in inches: ");
  scanf("%d", &inches);

  feet = inches/inches_per_foot;   // Get whole feet.
  yards = feet/feet_per_yard;      // Get whole yards in value of feet.
  feet %= feet_per_yard;           // Get residual feet.
  inches %= inches_per_foot;       // Get residual inches.

  printf("That is equivalent to %d yards %d feet and %d inches.\n", yards, feet, inches);
  return 0;
}
/**********************************************************************************/
// Exercise 2.2  Calculating the area of a room
#include <stdio.h>

int main(void)
{
  double length = 0.0;                     // Room length in yards
  double width = 0.0;                      // Room width in yards
  long feet = 0L;                          // A whole number of feet
  long inches = 0L;                        // A whole number of inches
  const long inches_per_foot = 12L;
  const double inches_per_yard = 36L;

  // Get the length of the room
   printf("Enter the length of the room in feet and inches - whole feet first: ");
   scanf("%ld", &feet);
   printf("                                           ...Now enter the inches: ");
   scanf("%ld", &inches);
   length = (feet*inches_per_foot + inches)/inches_per_yard;

  // Get the width of the room
   printf("Enter the width of the room in feet and inches - whole feet first: ");
   scanf("%ld", &feet);
   printf("                                          ...Now enter the inches: ");
   scanf("%ld", &inches);
   width = (feet*inches_per_foot + inches)/inches_per_yard;

   // Output the area
   printf("The area of the room is %.2f square yards.\n", length*width);
   return 0;
}
/**********************************************************************************/
// Exercise 2.3  Calculating volume price of alternative products

// The only problem here is to devise a way to determine the price
// for the product type. Here I used the product type value to do this.
#include <stdio.h>

int main(void)
{
  double total_price = 0.0;                // Total price
  int type = 0;                            // Product type
  int quantity = 0;                        // Quantity ordered
  const double type1_price = 3.50;
  const double type2_price = 5.50;

  // Get the product type
  printf("Enter the type (1 or 2): ");
  scanf("%d", &type);

  // Get the order quantity
  printf("Enter the quantity: ");
  scanf("%d", &quantity);

  // Calculate the total price
  total_price = quantity*(type1_price + (type - 1)*(type2_price - type1_price));

  // Output the area
  printf("The price for %d of type %d is $%.2f\n", quantity, type, total_price);
  return 0;
}
/**********************************************************************************/
// Exercise 2.4  Calculating average hourly pay rate
#include <stdio.h>

int main(void)
{
  double pay = 0.0;                // Weekly pay in dollars
  double hours = 0.0;              // hours worked
  int dollars = 0;                 // Hourly rate - dollars
  int cents = 0;                   // ... and cents

  // Get the Weekly pay
  printf("Enter your weekly pay in dollars: ");
  scanf("%lf", &pay);

  // Get the order quantity
  printf("Enter the hours worked: ");
  scanf("%lf", &hours);

  // Calculate the average hourly rate - dollars first
  dollars = (int)(pay/hours);

  // to get the cents we can subtract the dollars from the hourly rate
  // and multiply by 100 to get cents. If we then add 0.5 and convert the result
  // back to an integer, it will be to the nearest cent.
  cents = (int)(100.0*(pay/hours - dollars) + 0.5);

  // Output the average hourly rate
  printf("Your average hourly pay rate is %d dollars and %d cents.\n", dollars, cents);
  return 0;
}
/**********************************************************************************/
// Exercise 3.1 Convert temperatures
#include <stdio.h>

int main(void)
{
  int choice = 0;
  double temperature = 0.0;
  printf("This program can do the following:\n"
         "1. Convert from degrees Centigrade to degrees Fahrenheit\n"
         "2. Convert from degrees Fahrenheit to degrees Centigrade\n"
         "Select the conversion (1 or 2): ");
  scanf("%d", &choice);

  printf("Enter a temperature in degrees %s: ",
                          (choice == 1 ?  "Centigrade" : "Fahrenheit"));
  scanf("%lf", &temperature);

  if(choice == 1)
    printf("That is equivalent to %.2lf degrees Fahrenheit\n", temperature*9.0/5.0 + 32.0);
  else
    printf("That is equivalent to %.2lf degrees Centigrade\n", (temperature - 32.0)*5.0/9.0);
  return 0;
}
/**********************************************************************************/
// Exercise 3.2 Display a date
#include <stdio.h>

int main(void)
{
  int month = 0;
  int day = 0;
  int year = 0;
  printf("Enter the date as three integer values separated by spaces (month day year): ");
  scanf("%d", &month);
  scanf("%d", &day);
  scanf("%d", &year);
  if(day > 3 && day < 21 || day > 23 && day < 31)
    printf("\n%dth ",day);
  else
    printf("\n%d%s ", day, (day%10 == 1 ? "st": (day%10 == 2 ? "nd" : "rd")));

  switch(month)
  {
    case 1:
      printf("January ");
      break;
    case 2:
      printf("February ");
      break;
    case 3:
      printf("March ");
      break;
    case 4:
      printf("April ");
      break;
    case 5:
      printf("May");
      break;
    case 6:
      printf("June");
      break;
    case 7:
      printf("July");
      break;
    case 8:
      printf("August");
      break;
    case 9:
      printf("September");
      break;
    case 10:
      printf("October");
      break;
    case 11:
      printf("November");
      break;
    case 12:
      printf("December");
      break;
  }
  printf(" %d\n", year);
  return 0;
}
/**********************************************************************************/
// Exercise 3.3 Calculate a discounted price

// I interpreted this exercise as implying that the 10% applies to items 31 to 50
// and the 15% applies to items in excess of 50.
// That is, you don't get 15% discount on the whole price when you order 51 items.

// There is more than one way of doing this so different is not necessarily wrong.

#include <stdio.h>

int main(void)
{
  const int level1 = 30;               // Quantity over this level are at discount1
  const int level2 = 50;               // Quantity over this level are at discount2
  const double discount1 = 0.10;       // 10% discount
  const double discount2 = 0.15;       // 15% discount
  const double unit_price = 5.0;       // Basic unit price
  int quantity = 0;
  int qty_full_price = 0;              // 0 to 30 at full price
  int qty_level1 = 0;                  // 31 to 50 at level1 price
  int qty_level2 = 0;                  // Over 50 at level2 price
  printf("Enter the quantity that you require: ");
  scanf("%d", &quantity);
 
  if(quantity > 50)                     // Quantity over 50
  {
    qty_full_price = level1;
    qty_level1 = level2 - level1;
    qty_level2 = quantity - level2;
  }
  else if(quantity > 30)                // Quantity is from 30 to 50
  {
    qty_full_price = level1;
    qty_level1 = quantity - level1;
  }
  else
    qty_full_price = quantity;

  printf("The total price for %d items is $%.2lf\n", quantity,
    unit_price*(qty_full_price + (1.0 - discount1)*qty_level1 + (1.0 - discount2)*qty_level2));
  return 0;
}
/**********************************************************************************/
/*Exercise 3.4 A calculator that allows multiple calculations */
#include <stdio.h>

int main(void)
{
  double number1 = 0.0;          /* First operand value a decimal number  */
  double number2 = 0.0;          /* Second operand value a decimal number */
  char operation = 0;            /* Operation - must be +, -, *, /, or %  */
start:
  printf("\nEnter the calculation\n");
  scanf("%lf %c %lf", &number1, &operation, &number2);

  switch(operation)
  {
    case '+':                     // No checks necessary for add
      printf("= %lf\n", number1 + number2);
      break;

    case '-':                     // No checks necessary for subtract
      printf("= %lf\n", number1 - number2);
      break;

    case '*':                     // No checks necessary for multiply
      printf("= %lf\n", number1 * number2);
      break;                              

    case '/':
      if(number2 == 0)           // Check second operand for zero 
        printf("\n\n\aDivision by zero error!\n");
      else
        printf("= %lf\n", number1 / number2);
      break;

    case '%':                    // Check second operand for zero
      if((long)number2 == 0) 
         printf("\n\n\aDivision by zero error!\n");
      else
        printf("= %ld\n", (long)number1 % (long)number2);
      break;

    default:                     // Operation is invalid if we get to here
      printf("\n\n\aIllegal operation!\n");
      break;
  }

  /* The following statements added to prompt for continuing */
  char answer = 'n';
  printf("\n Do you want to do another calculation? (y or n): ");
  scanf(" %c", &answer);
  if(answer == 'y' || answer == 'Y')
    goto start;                       /* Go back to the beginning */

  return 0;
}
/**********************************************************************************/
//Exercise 4.1 Generate a multiplication table */
#include <stdio.h>

int main(void)
{
  int table_size = 0;                       // Table size        */

  printf("Enter the table size (from 2 to 12): ");
  scanf("%d", &table_size);
  if(table_size > 12)
  {
    printf("Table size must not exceed 12 - setting to 12\n");
    table_size = 12;
  }
  else if(table_size < 2)
  {
    printf("Table size must be at least 2 - setting to 2\n");
    table_size = 2;
  }

  for(int row = 0 ; row <= table_size ; ++row)
  {
    printf("\n");                      // Start new row
    for(int col = 0 ; col<=table_size ; ++col)
    {
      if(row == 0)                     // 1st row?
      {                                // Yes - output column headings
        if(col == 0)                   // 1st column?
          printf("    ");              // Yes - no heading
        else
          printf("|%4d", col);         //No - output heading
      }
      else
      {                                // Not 1st row - output rows
        if(col == 0)                   // 1st column?
          printf("%4d", row);          // Yes - output row label
        else
          printf("|%4d", row*col);     // No - output table entry
      }
    }
    if(row == 0 )                      // If we just completed 1st row
    {                                  // output separator dashes
      printf("\n");
      for(int col = 0 ; col <= table_size ; ++col)
        printf("_____");
    }
  }
  printf("\n");
	return 0;
}
/**********************************************************************************/
// Exercise 4.2 Displaying printable characters
#include <stdio.h>
#include <ctype.h>

int main(void)
{
  char ch = 0;                       // Character code value
  for(int i = 0 ; i < 128 ; ++i)
  {
    ch = (char)i;
    if(i%2 == 0)
      printf("\n");
    printf("  %4d    %c",ch,(isgraph(ch) ? ch : ' '));
  }
  printf("\n");
	return 0;
}
/**********************************************************************************/
/*Exercise 4.3 Displaying printable characters plus whitspace names */
#include <stdio.h>
#include <ctype.h>

int main(void)
{
  char ch = 0;                       /* Character code value */
  for(int i = 0 ; i < 128 ; ++i)
  {
    ch = (char)i;
    if(i%2 == 0)
      printf("\n");
    printf("  %4d",ch);
    if(isgraph(ch))
      printf("               %c",ch);
    else
    {
      switch(ch)
      {
        case '\n':
           printf("         newline",ch);
           break;
        case ' ':
           printf("           space",ch);
           break;
        case '\t':
           printf("  horizontal tab",ch);
           break;
        case '\v':
           printf("    vertical tab",ch);
           break;
         case '\f':
           printf("       form feed",ch);
           break;
        default:
           printf("                ");
           break;
      }
    }

  }
  printf("\n");
	return 0;
}
/**********************************************************************************/
//Exercise 4.4 Modified Simple Simon

// rand() returns values from 0 to RAND_MAX
// We have to select one of the digits 0 to 9 based on the value returned by rand().
// Thus we need to divide the range from 0 to RAND_MAX into 10 intervals
// and select a digit depending on the range in which the number returned by rand() lies.

#include <stdio.h>                               // For input and output 
#include <ctype.h>                               // For toupper() function
#include <stdbool.h>                             // For bool, true, false
#include <stdlib.h>                              // For rand() and srand()
#include <time.h>                                // For time() function

int main(void)
{
  const int ndigits = 10;                        // Number of digits from 0 to 9
  const int interval = RAND_MAX/ndigits;         // Interval in rand() range
  int rand_value = 0;                            // A value generated by rand()

  char another_game = 'Y';                       // Records if another game is to be played
  const unsigned int DELAY = 1;                  // Display period in seconds
  bool correct = true;                           // true for correct sequence, false otherwise
  unsigned int tries = 0;                        // Number of successful entries for sequence length 
  unsigned int digits = 0;                       // Number of digits in a sequence
  time_t seed = 0;                               // Seed value for random number sequence
  unsigned int number = 0;                       // Stores an input digit
  time_t wait_start = 0;                         // Stores current time
  clock_t start_time = 0;                        // Game start time in clock ticks
  unsigned int score = 0;                        // Game score
  unsigned int total_digits = 0;                 // Total of digits entered in a game
  unsigned int game_time = 0;                    // Game time in seconds

  // Describe how the game is played
  printf("\nTo play Simple Simon, ");
  printf("watch the screen for a sequence of digits.");
  printf("\nWatch carefully, as the digits are only displayed"
                             " for %u second%s ", DELAY, DELAY > 1 ? "s!" :"!");
  printf("\nThe computer will remove them, and then prompt you ");
  printf("to enter the same sequence.");
  printf("\nWhen you do, you must put spaces between the digits.\n");
  printf("\nGood Luck!\nPress Enter to play\n");
  scanf("%c", &another_game);

  // Game loop - one outer loop iteration is a complete game
  do
  {
    // Initialize game
    correct = true;                              // Indicates correct sequence entered
    tries = 0;                                   // Initialize count of successful tries
    digits = 2;                                  // Initial length of digit sequence
    start_time = clock();                        // Record time at start of game

    // Inner loop continues as long as sequences are entered correctly
    while(correct)
    {
      ++tries;                                   // A new attempt
      wait_start = clock();                      // record start time for sequence

      // Generate a sequence of digits and display them
      srand(time(&seed));                        // Initialize the random sequence
      for(unsigned int i = 1 ; i <= digits ; ++i)
      {
        rand_value = rand();
        for(unsigned int j = 0 ; j < ndigits ; ++j)
        {
          if(rand_value >= j*interval && rand_value <= (j + 1)*interval)
          {
            printf("%u ", j);                    // Output a random digit
            break;
          }
        }
      }

      
      for( ; clock() - wait_start < DELAY*CLOCKS_PER_SEC; );  // Wait DELAY seconds

      // Now overwrite the digit sequence
      printf("\r");                              // Go to beginning of the line
      for(unsigned int i = 1 ; i <= digits ; ++i)
        printf("  ");                            // Output two spaces

      if(tries == 1)                             // Only output message for 1st try
        printf("\nNow you enter the sequence  - don't forget"
                                               " the spaces\n");
      else
        printf("\r");                            // Back to the beginning of the line

      srand(seed);                               // Reinitialize the random sequence
       for(unsigned int i = 1 ; i <= digits ; ++i)
      {
       // Read the input sequence & check against the original
       scanf("%u", &number);                     // Read a digit
        rand_value = rand();
        unsigned int digit = 0;
        for( ; digit < ndigits ; ++digit)
        {
          if(rand_value >= digit*interval && rand_value <= (digit + 1)*interval)
            break;
        }
        if(number != digit)                      // Compare with generated digit
        {
          correct = false;                       // Incorrect entry
          break;                                 // No need to check further...
        }
      }

      // On every third successful try, increase the sequence length
      if(correct && ((tries % 3) == 0))
        ++digits;

      printf("%s\n", correct ? "Correct!" : "Wrong!");
    }

    // Calculate and output the game score
    score = 10*(digits - ((tries % 3) == 1));    // Points for sequence length
    total_digits = digits*(((tries % 3) == 0) ? 3 : tries % 3);
    if(digits > 2)
      total_digits += 3*((digits - 1)*(digits - 2)/2 - 1);

    game_time = (clock() - start_time)/CLOCKS_PER_SEC - tries*DELAY;

    if(total_digits > game_time) 
      score += 10*(game_time - total_digits);    // Add points for speed
    printf("\n\nGame time was %u seconds. Your score is %u", game_time, score);

    fflush(stdin);                               // Clear the input buffer

    // Check if new game required
    printf("\nDo you want to play again (y/n)? ");
    scanf("%c", &another_game);

  }while(toupper(another_game) == 'Y');
  return 0;
}
/**********************************************************************************/
// Ex4.5  A Modified Guessing Game
#include <stdio.h>
#include <stdlib.h>                   
#include <time.h>                           // For time() function
#include <ctype.h>                          // I added this for toupper()
#include <stdbool.h>                        // I added this for true

int main(void)
{
  int chosen = 0;                           // The lucky number
  int guess = 0;                            // Stores a guess
  const int max_tries = 3;                  // The maximum number of tries
  int limit = 20;                           // Upper limit for pseudo-random values
  char answer = 'N';

  srand(time(NULL));                        // Use clock value as starting seed
  printf("\nThis is a guessing game.\n");

  while(true)                              
  {
    chosen = 1 + rand() % limit;             // Random int 1 to limit
    printf("I have chosen a number between 1 and 20 which you must guess.\n");

    for(int count = max_tries ; count > 0 ; --count)
    {
      printf("\nYou have %d tr%s left.", count, count == 1 ? "y" : "ies");
      printf("\nEnter a guess: ");          // Prompt for a guess 
      scanf("%d", &guess);                  // Read in a guess

      // Check for a correct guess
      if(guess == chosen)
      {
        printf("\nCongratulations. You guessed it!\n");
        break;                              // End the program
      }
      else if(guess < 1 || guess > 20)      // Check for an invalid guess
        printf("I said the number is between 1 and 20.\n ");
      else
        printf("Sorry, %d is wrong. My number is %s than that.\n",
                            guess, chosen > guess ? "greater" : "less");
    }
    printf("\nYou have had three tries and failed. The number was %ld\n", chosen);
    printf("Do you want to play again (Y or N)?");
    scanf(" %c", &answer);
    if(toupper(answer) != 'Y')
      break;

  }
  return 0;
}
/**********************************************************************************/
//Exercise 5.1 Summing reciprocals of five values
#include <stdio.h>

int main(void)
{
  const int nValues = 5;               // Number of data values
  double data[nValues];                // Stores data values
  double reciprocals[nValues];
  double sum = 0.0;                    // Stores sum of reciprocals

  printf("Enter five values separated by spaces: \n");
  for(int i = 0 ; i < nValues ; ++i)
    scanf("%lf", &data[i]);

  printf("You entered the values:\n");
  for(int i = 0 ; i < nValues ; ++i)
    printf("%15.2lf", data[i]);
  printf("\n");

  printf("\nThe values of the reciprocals are:\n");
  for(int i = 0 ;  i < nValues ; ++i)
  {
    reciprocals[i] = 1.0/data[i];
    printf("%15.2lf", reciprocals[i]);
  }
  printf("\n\n");

  for(int i = 0 ; i<nValues ; i++)
  {
    sum += reciprocals[i];              // Accumulate sum of reciprocals
    if(i > 0)
      printf(" + ");
    printf("1/%.2lf", data[i]);
  }
  printf(" = %lf\n", sum);
  return 0;
}
/**********************************************************************************/
//Exercise 5.2 Summing 100 data values
#include <stdio.h>

int main(void)
{
  double data[100];                    // Stores data values
  double sum = 0.0;                    // Stores sum of terms
  double sign = 1.0;                   // Sign - flips between +1.0 and -1.0

  int j = 0;
  for(size_t i = 0 ; i < sizeof(data)/sizeof(double) ; ++i)
  {
    j = 2*(i + 1);
    data[i] = 1.0/(j * (j + 1) * (j + 2));
    sum += sign*data[i];
    sign = -sign;
  }

   // Output the result
  printf("The result is %.4lf\n", 4.0*sum + 3.0);
  printf("The result is an approximation of pi, isn't that interesting?\n");
	return 0;
}
/**********************************************************************************/
//Exercise 5.3 Handling monetary values as integers
#include <stdio.h>

int main(void)
{
  const size_t size = 5;
  float amounts[size];                     // Stores data values
  long dollars[size];
  long cents[size];

  printf("Enter %zd monetary values separated by spaces:\n", size);
  for(size_t i = 0 ; i < size ; ++i)
    scanf("%f", &amounts[i]);

  for(size_t i = 0 ; i < size ; ++i)
  {
    dollars[i] = (long)amounts[i];
    cents[i] = (long)(100.0*(amounts[i] - dollars[i]));
  }

  printf("\n");
  for(size_t i = 0 ; i < size ; ++i)
    printf("  $%d.%02d", dollars[i], cents[i]);

  printf("\n");
  return 0;
}
/**********************************************************************************/
//Exercise 5.4 Table of reciprocals, squares, cubes, and fourth powers.
#include <stdio.h>

int main(void)
{
  const size_t nrows = 11;              // Number of rows in the array
  const size_t ncols = 5;               // Number of columns in the array
  double data[nrows][ncols];            // Stores data values
  double value = 2.0;                   // Value to be stored in array

  for(size_t row = 0 ; row < nrows ; ++row)
	{
    data[row][0] = value;
    data[row][1] = 1.0/data[row][0];               // 1/x
    data[row][2] = data[row][0]*data[row][0];      // x*x
    data[row][3] = data[row][2]*data[row][0];      // x*x*x
    data[row][4] = data[row][3]*data[row][0];      // x*x*x*x
		value += 0.1;
  }


  printf("            x  ");
  printf("          1/x  ");
  printf("          x*x  ");
  printf("         x*x*x ");
  printf("        x*x*x*x");

    for(size_t row = 0 ; row < nrows ; ++row)
  {
    printf("\n");
    for(size_t col = 0 ; col < ncols ; ++col)
      printf("%15.4lf", data[row][col]);
  }

  printf("\n");
	return 0;
}
/**********************************************************************************/
//Exercise 5.5 Calculating average student grades.
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>

int main(void)
{
  size_t nclasses = 0;                  // Number classes
  size_t nstudents_max = 0;             // Maximum number of students in a class
  char answer = 'N';

  printf("How many students are in the largest class? :");
  scanf("%zd", &nstudents_max);
  printf("How many classes are there? :");
  scanf("%zd", &nclasses);


  int grades[nclasses][nstudents_max];                     // Stores the grades
  size_t students[nclasses];                               // Stores the number of students in each class

  for(size_t class = 0 ; class < nclasses ; ++class)
	{
    printf("Enter the grades for students in class %zd.\n", class + 1);
    students[class] = 0;                                   // Student count within a class
    while(true)
    {
      printf("Enter the integer grade for student %zd: ", students[class] + 1);
      scanf("%d", &grades[class][students[class]]);
      if(++students[class] == nstudents_max)                // Increment and check student count
      {
        printf("Class %zd complete.", class + 1);
        break;
      }
      printf("Any more students in class %zd (Y or N): ", class + 1);
      scanf(" %c", &answer);
      if(toupper(answer) == 'N')
      break;
    }
  }
  printf("\n");
  for(size_t class = 0 ; class < nclasses ; ++class)
	{
    int class_total = 0;
    printf("Student grades for class %zd are:\n", class + 1);
    for(size_t student = 0 ; student < students[class] ; ++student)
    {
      class_total += grades[class][student];
      if((student + 1) % 6 == 0)
        printf("\n");
      printf("%5d", grades[class][student]);
    }
    printf("\nAverage grade for class %zd is %.2lf\n", class + 1, (double)class_total/students[class]);
  }
	return 0;
}
/**********************************************************************************/
// Exercise 6.1 Convert an integer to words
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>

int main(void)
{
  char *unit_words[] = {"zero", "one","two","three","four","five","six","seven","eight","nine"};
  char *teen_words[] = {"ten", "eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"};
  char *ten_words[] = {"error", "error","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"};
  char hundred[] = " hundred";
  char and[] = " and ";
  char value_str[50] = "";
  int value = 0;                     // Integer to be converted
  int digits[] = {0,0,0};            // Stores digits of value entered
  int i = 0;

  printf("Enter a positive integer less than 1000: ");
  scanf_s("%d",&value);
  if(value >= 1000)
    value = 999;
  else if(value < 1)
    value = 1;

  while(value > 0)
  {
    digits[i++] = value % 10;
    value /= 10;
  }

  if(digits[2] > 0)
  {
    strcat_s(value_str, sizeof(value_str), unit_words[digits[2]]);
    strcat_s(value_str, sizeof(value_str), hundred);
    if(digits[1] > 0 || digits[0] > 0)
      strcat_s(value_str, sizeof(value_str), and);
  }
  if(digits[1] > 0)
  {
    if(digits[1] == 1)
      strcat_s(value_str, sizeof(value_str), teen_words[digits[0]]);
    else
    {
      strcat_s(value_str,sizeof(value_str), ten_words[digits[1]]);
      if(digits[0] > 0)
      {
        strcat_s(value_str, sizeof(value_str), " ");
        strcat_s(value_str, sizeof(value_str), unit_words[digits[0]]);
      }
    }
  }
  else
    if(digits[0] > 0)
      strcat_s(value_str, sizeof(value_str), unit_words[digits[0]]);
  printf("\n%s\n", value_str);
  return 0;
}
/**********************************************************************************/
// Exercise 6.2 Analyze comma-separated list of words
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAX_LEN  5000                                      // Maximum string length
int main(void)
{
  char list[MAX_LEN];                                      // Stores the list of comma separated words
  const char comma[] = ",";                                // The only word delimiter

  printf("Enter a comma separated list of words:\n");
  gets_s(list, sizeof(list));                              // Read the list of words

  // Remove spaces
  size_t index = 0;                                        // Character position
  size_t i = 0;
  do
  {
    if(isspace(list[i]))                                   // If it's whitespace...
      continue;                                            // ... skip the character...
    list[index++] = list[i];                               // ... otherwise copy the character
  } while(list[i++] != '\0');

  // Find words in list
  char *ptr = NULL;
  size_t list_len = strnlen_s(list, MAX_LEN);
  char *pWord = strtok_s(list, &list_len, comma, &ptr);    // Find 1st word
  if(pWord)
  {
    do
    {
      printf("%s\n", pWord);
      pWord = strtok_s(NULL, &list_len, comma, &ptr);      // Find subsequent words
    }while(pWord);                                         // NULL ends tokenizing
  }

	return 0;
}
/**********************************************************************************/
// Exercise 6.3 A random thought for the day
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define MAX_LEN    50         // Maximum thought string length

int main(void)
{
  char thoughts[][MAX_LEN] = {"Wherever you go, there you are!",
                              "A nod is as good as a wink to a blind horse.",
                              "Many hands make light work.",
                              "Too many cooks spoil the broth.",
                              "A rolling stone gathers no moss.",
                              "A wise man will cover the hole in his carpet."};

  srand((unsigned int)time(NULL));

  printf("Today's thought is:\n%s\n", thoughts[rand()%(sizeof(thoughts)/MAX_LEN)]);
  return 0;
}
/**********************************************************************************/
// Exercise 6.4 Looking for palindromes
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#define MAX_LEN 500                             // Maximum sentence length

int main(void)
{
  char sentence[MAX_LEN];                        // Stores the sentence to be tested
  char sentence_chars[MAX_LEN];                  // Stores the sentence without punctuation and spaces
  size_t j = 0;                                  // Index to character position
  size_t length = 0;                             // Length of a string

  printf("Enter a sentence to be tested:\n");
  gets_s(sentence, MAX_LEN);

  // Copy only letters as lowercase
  for (size_t i = 0 ; i < strnlen_s(sentence, MAX_LEN) ; ++i)
    if(isalpha(sentence[i]))
      sentence_chars[j++] = tolower(sentence[i]);
  sentence_chars[j] = '\0';                      // Append string terminator

  length = strnlen_s(sentence_chars, MAX_LEN);   // Get the string length

  // Compare matching characters in the string
  // If any pair are not the same, then it's not a palindrome
  bool isPalindrome = true;
  for(size_t i = 0 ; i < length/2 ; ++i)
  {
    if(sentence_chars[i] != sentence_chars[length - 1 - i])
    {
      isPalindrome = false;
      break;
    }
  }
  printf("\n The sentence you entered is%sa palindrome.\n", isPalindrome ? " " : " not ");
    return 0;
}
/**********************************************************************************/
// Exercise 7.1 Calculating a floating-point average using pointers
/*********************************************************************
 * In this solution I allocate a some memory and when it is full     *
 * allocate a new, larger amount of memory and copy the contents of  *
 * the old memory to the new. I then free the old memory. This       *
 * process repeats as often as necessary.                            *
**********************************************************************/
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define CAP_INCR 5                                               // Capacity increment for memory allocation

int main(void)
{
  double *values = NULL;                                         // Pointer to memory holding data values - none inmtially
  int capacity = 0;                                              // Maximum number of values that can be stored - none initially
  double *temp = NULL;                                           // Pointer to newly allocated memory
  double sum = 0.0;                                              // Sum of values
  int count = 0;                                                 // Number of values read
  char answer = 'n';

  do
  {
    if(count == capacity)                                        // Check if there is spare memory
    {
      capacity += CAP_INCR;                                      // Increase the capacity of memory by increment
      temp = realloc(values, capacity*sizeof(double));           // and reallocate it
      if(!temp)                                                  // If memory was not allocated
      {                                                          // Output a message  and end 
        printf("Memory allocation failed. Terminating program.");
        exit(1);
      }
     // When there are values stored in memory, they will be copied automatically to the new memory 
     values = temp;                                              // Copy address of new memory to values
      temp = NULL;                                               // Reset pointer
    }

    printf("Enter a value: ");
    scanf_s("%lf", values+count++);

    printf("Do you want to enter another(y or n)? ");
    scanf(" %c", &answer);
  }while(tolower(answer) == 'y');

  // Now sum the values
  for(size_t i = 0 ; i < count ; ++i)
    sum += *(values + i);

  // Output the average
  printf("\nThe average of the the values you entered is %.2lf.\n", sum/count);
  free(values);                                                  
  // We are done - so free the memory
  return 0;
}
/**********************************************************************************/
// Exercise 7.2 Storing and displaying proverbs in order of length
/***************************************************************************
 * This program will read any number of proverbs of any length.            *
 * The input buffer has a default size that is increased automatically     *
 * if it is not large enough.                                              *
 * The same applies to the number of proverbs. If the initial capacity     *
 * for pointers to proverbs is exceeded, a larger space is allocated.      *
 * Additional space is allocated fro recording the lengths of the proverbs.*
 * You could add printf() statements to record when new memory is allocated*
 * Values for BUFFER_LEN, BUFFER_LEN_INCR, and CAPACITY_INCR are set low   *
 * so as to cause frequent reallocation of memory for you to track.        *
 * In a practical program they would be set much higher to avoid           *
 * frequent reallocation of heap memory.                                   *
****************************************************************************/
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_LEN 5                                                      // Initial length of input buffer
#define BUFFER_LEN_INCR 3                                                 // Increment to buffer length
#define CAPACITY_INCR 2                                                   // Increment to capacity for proverbs

int main(void)
{
   char **pProverbs = NULL;                                               // Pointer to proverb string pointers
   char **temp = NULL;                                                    // Temporary pointer to proverb string pointers
   size_t *pLengths = NULL;                                               // Pointer to proverb lengths
   size_t *ptemplengths = NULL;                                           // Temporary pointer to lengths memory
   int capacity = 0;                                                      // Number of proverbs that can be stored
   int count = 0;                                                         // Number of proverbs read
   char *pstart = NULL;                                                   // Pointer to input buffer start
   char *pstr = NULL;                                                     // Pointer to a string
   int buffer_length = BUFFER_LEN;                                        // Input buffer length

   char *pbuffer = (char*)malloc(BUFFER_LEN);                             // Initial buffer allocation
   if(!pbuffer)                                                           // If memory was not allocated...
   {                                                                      // ...output a message  and end
     printf("Memory allocation for buffer failed. Terminating program.\n");
     exit(1);
   }
   pstart = pbuffer;                                                      // Store start of buffer

   for(;;)
   {
     if(count == capacity)                                                // Do we have space for proverbs?
     { // No, so increase the capacity
       capacity += CAPACITY_INCR;
       // Allocate memory for proverb pointers
       temp = realloc(pProverbs, capacity*sizeof(char*));                 // Space for pointers to proverbs
       if(!temp)                                                          // If memory was not allocated
       {                                                                  // Output a message  and end
         printf("Memory allocation failed. Terminating program.\n");
         exit(1);
       }
       pProverbs = temp;                                                  // Copy address of new memory
       temp = NULL;                                                       // Reset pointer

      // Allocate memory for lengths of proverbs
      ptemplengths = realloc(pLengths, capacity*sizeof(size_t));          // Space for lengths proverbs
       if(!ptemplengths)                                                  // If memory was not allocated
       {                                                                  // Output a message  and end
         printf("Memory allocation for proverb lengths failed. Terminating program.\n");
         exit(1);
       } 
       pLengths = ptemplengths;                                           // Copy address of new memory
       ptemplengths = NULL;                                               // Reset pointer
     }

     printf("Enter a proverb and press Enter, or just press Enter to end:\n");

     // Read a proverb
     while((*pbuffer++ = getchar()) != '\n')
     {
       if(pbuffer - pstart == buffer_length)                              // Check for buffer full
       {
         buffer_length += BUFFER_LEN_INCR;                                // Increase buffer length
         pstr = realloc(pstart, buffer_length);                           // Allocate new buffer
         if(!pstr)                                                        // If memory was not allocated
         {                                                                // Output a message  and end
           printf("Memory allocation for input buffer failed. Terminating program.\n");
           exit(1);
         } 

         // The new memory contains the current proverb text but can be at a different address from pstart.
         // We must reset pbuffer to point to the same relative position in the new memory
         // as it did in the old memory and pstart should point to the new buffer.
         pbuffer = pstr + (pbuffer - pstart);                             // Address of next position in new memory
         pstart = pstr;                                                   // Set to start of new buffer
         pstr = NULL;                                                     // Reset pointer
       }
     }

     // check for empty line indicating end of input
     if((pbuffer - pstart) < 2)
       break;

     *(pbuffer - 1) = '\0';                                               // Add string terminator overwriting newline character
     pbuffer = pstart;
     *(pLengths + count) = strnlen_s(pbuffer, buffer_length);             // Store the proverb length
     if(!(*(pProverbs + count) = (char*)malloc(*(pLengths + count) + 1))) // Allocate space for the proverb
     { // Failed - so output a message  and end
       printf("Memory allocation for input buffer failed. Terminating program.\n");
       exit(1);
     } 
     strcpy_s(*(pProverbs + count), *(pLengths + count) + 1,  pbuffer);   // Copy the proverb
    ++count;
   }

  // Order the proverbs from shortest to longest
  size_t length = 0;
  for(size_t i = 0 ; i < count - 2 ; ++i)
  {
    for(size_t j = i + 1 ; j < count-1 ; ++j)
    {
      if(*(pLengths + i) > *(pLengths + j))
      {
        // Swap the proverb pointers
        pstr = *(pProverbs + i);
        *(pProverbs + i) = *(pProverbs + j);
        *(pProverbs + j) = pstr;

        // Swap corresponding lengths
        length = *(pLengths + i);
        *(pLengths + i) = *(pLengths + j);
        *(pLengths + j) = length;
      }
    }
  }

   // Output all the strings
   printf("\nIn ascending length order, the proverbs you entered are:\n");
   for (size_t i = 0 ; i < count ; ++i)
   {
      printf("%s\n", *(pProverbs + i));
      free(*(pProverbs + i));                                             // Release the memory for the proverb 
      *(pProverbs + i) = NULL;                                            // Set pointer back to NULL for safety
   }
   free(pProverbs);                                                       // Release memory for the pointers
   free(pstart);                                                          // Release memory for the buffer
   free(pLengths);                                                        // Release memory for the lengths
}

/**********************************************************************************/
// Exercise 7.3 Removing spaces and puctuation from a string
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#define BUF_LEN  20                              // Initial length of input buffer
#define BUF_INCR 10                              // Buffer size increment

int main(void)
{
  size_t buf_len = BUF_LEN;
  char *buffer = (char*)malloc(buf_len);         // Input buffer
  char *temp = NULL;
  char *pbuffer1 = buffer;                       // Pointer to buffer position
  char *pbuffer2 = NULL;                         // Pointer to buffer position

   // Read a string
   printf("Enter a string of any length ending with a newline:\n");
   while((*pbuffer1++ = getchar()) != '\n')
  {
    if((pbuffer1 - buffer) == buf_len)
    {
      buf_len += BUF_INCR;
      if(!(temp = realloc(buffer, buf_len)))
      {
        printf("Error allocating buffer.\n");
        exit(1);
      }
      pbuffer1 = temp + (pbuffer1 - buffer);
      buffer = temp;
      temp = NULL;
    }
  }
  *pbuffer1 = '\0';                              // Append string terminator
  pbuffer1 = pbuffer2 = buffer;                  // Reset pointers to start of string

  while((*pbuffer1) != '\0')                     // Loop until the end of the string
  {
    if(ispunct(*pbuffer1) || isspace(*pbuffer1))
    {                                            // If it's space or punctuation
      ++pbuffer1;                                // go to the next character
      continue;
    }
    else
      *pbuffer2++ = *pbuffer1++;                 // otherwise, copy the character
  }
  *pbuffer2 = '\0';                              // Append string terminator

  printf("With the spaces and punctuation removed, the string is now:\n%s\n", buffer);
  free(buffer);
	return 0;
}
/**********************************************************************************/
// Exercise 7.4 Read and process daily temperatures
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define DAYS             2                                 // Initial number of days allowed for
#define READINGS_PER_DAY 6                                 // Readings per day

int main(void)
{
   double **data = NULL;                                   // Pointer to array of pointers to arrays of temperatures
   double **newdata = NULL;                                // Pointer to array of pointers to arrays of temperatures 
   double *averages = NULL;                                // Pointer to array of averages

   int day = 0;
   int max_days = 0;
   char answer = 'n';

   do
   {
     if(day == max_days)
     {
       max_days += DAYS;

       // Create new array of pointers
       newdata = (double**)malloc(max_days*sizeof(double*));

       // Create an array of values of type double for each new day and store the address
       for(int i = day ; i < max_days ; ++i)
         *(newdata + i) = (double*)malloc(READINGS_PER_DAY*sizeof(double));
       if(data != NULL)
       {
         // Copy the addresses of the existing arrays of temperatures
         for(int i = 0 ; i < day ; ++i)
           *(newdata + i) = *(data + i);
         free(data);                                       // Free memory for the old array of pointers
       }
       data = newdata;                                     // copy the address of the new array of pointers
       newdata = NULL;                                     // Reset the pointer
     }

     printf("Enter the %d readings for a day:\n", READINGS_PER_DAY);
     for(int i = 0 ; i < READINGS_PER_DAY ; ++i)
       scanf_s(" %lf", *(data + day) + i);
     ++day;
     printf("Do you want to enter another set(y or n)? ");
     scanf_s(" %c", &answer, sizeof(answer));
   } while(tolower(answer) != 'n');

   // If there is unused memory for temperature values - release it
   for(int i = day ; i < max_days ; ++i)
     free(*(data+i));

   // Allocate space for the averages */
   averages = (double*)malloc(day*sizeof(double));

   //Calculate the averages */
   for(int i = 0 ; i < day ; ++i)
   {
     *(averages + i) = 0.0;
     for(int j = 0 ; j < READINGS_PER_DAY ; ++j)
       *(averages+i) += *(*(data+i)+j);

     *(averages+i) /= READINGS_PER_DAY;
   }

   printf("\nThe daily temperatures and averages are:\n");
   for(int i = 0 ; i < day ; ++i)
   {
     for(int j = 0 ; j < READINGS_PER_DAY ; ++j)
       printf("%8.1lf", *(*(data +i ) + j));

     printf("   Average:%8.1lf\n", *(averages + i));
   }
   // Finally - release all the heap memory
   free(averages);
   for(int i = 0 ; i < day ; ++i)
     free(*(data + i));

   free(data);
   return 0;
}
/**********************************************************************************/
// Exercise 8.1 A function to calculate an average
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define CAPACITY_INCREMENT 6                     // Increment in the capacity for data values

double average(double data[], int count)
{
  double sum = 0.0;
  for(int i = 0 ; i < count ; sum += data[i++])
    ;
  return sum/count;
}

int main(void)
{
   double *data = NULL;                          // Pointer to array of data values
   double *temp = NULL;                          // Pointer to new array of data values
   int count = 0;                                // Number of data values
   int capacity = 0;                             // Number of data values that can be stored
   char answer = 'n';

   do
   {
     if(count == capacity)
     {
       capacity += CAPACITY_INCREMENT;
       // Create new array of pointers
       if(!(temp = (double*)realloc(data, capacity*sizeof(double))))
       {
         printf("Error allocating memory for data values.\n");
         exit(1);
       }
       data = temp;
     }

     printf("Enter a data value: ");
     scanf_s(" %lf", data + count++);
     printf("Do you want to enter another (y or n)? ");
     scanf_s(" %c", &answer, sizeof(answer));
   } while(tolower(answer) != 'n');

   printf("\nThe  average of the values you entered is %10.2lf\n", average(data, count));
   free(data);
   return 0;
}
/**********************************************************************************/
// Exercise 8.2 A function to return a string representation of an integer
#include <stdio.h>
#include <stdbool.h>

#define STR_LEN 6                                // Length of string to store value string

// Converts an integer to a string. Caller must allocate string array.    
// Function returns the string to allow use of the function in an expression.
char* itoa(int n, char str[], size_t size)
{
  size_t i = 0;                                   // character count
  bool negative = n < 0;                          // Indicates negative integer 
  int length = 0;                                 // Length of string
  char temp = '0';                                // Temporary storage

  if(negative)                                    // If it's negative...
    n = -n;                                       // ...make it positive

  // Generate digit characters in reverse order
  do
  {
    if(size == i + 1 + (negative ? 1 : 0))
    {
      printf("String not long enough.\n");
      return NULL;
    }
    str[i++] = '0' + n%10;                       // Create a rightmost digit
    n /= 10;                                     // Remove the digit
  }while(n > 0);                                 // Go again if there's more digits

  if(negative)                                   // If it was negative...
    str[i++] = '-';                              // ...append minus

  str[i] = '\0';                                 // Append terminator
  length = i;                                    // Save the length including null character

  // Now reverse the string in place by switching first and last,
  // second and last but one, third and last but two, etc.
  for(i = 0 ; i < length/2 ; ++i)
  {
    temp = str[i];
    str[i] = str[length - i - 1];
    str[length - i - 1] = temp;
  }
  return str;                                    // Return the string
}


int main(void)
{
   char str[STR_LEN];                            // Stores string representation of an integer
   long testdata[] = { 30L, -98L, 0L, -1L, 999L, -12345L, 12345L};

   for (int i = 0 ; i < sizeof testdata/sizeof(long) ; ++i)
   {
     if(itoa(testdata[i],str, sizeof(str)))
       printf("Integer value is %d, string is %s\n", testdata[i], str);
   }

   return 0;
}
/**********************************************************************************/
// Exercise 8.3 A function to return a string representation of an integer with a given width
#include <stdio.h>
#include <stdbool.h>

#define STR_LEN 15                               // Length of string to store value string

// Convert an integer to a string with a fixed width.
// if the widh is too small, the minimum width is assumed.
char* itoa(int n, char str[], size_t size, size_t width)
{
  size_t i = 0;                                   // character count
  bool negative = n < 0;                          // Indicates negative integer 
  int length = 0;                                 // Length of string
  char temp = '0';                                // Temporary storage
  if(size <= width + 1 + negative ? 1 : 0)
  {
    printf("String too short for width\n");
    return NULL;
  }

  if(negative)                                    // If it's negative...
    n = -n;                                       // ...make it positive

  // Generate digit characters in reverse order
  do
  {
    if(size == i + 1 + (negative ? 1 : 0))
    {
      printf("String not long enough.\n");
      return NULL;
    }
    str[i++] = '0' + n%10;                       // Create a rightmost digit
    n /= 10;                                     // Remove the digit
  }while(n > 0);                                 // Go again if there's more digits

  if(negative)                                   // If it was negative...
    str[i++] = '-';                              // ...append minus

  str[i] = '\0';                                 // Append terminator
  length = i;                                    // Save the length including null character

  // Now reverse the string in place by switching first and last,
  // second and last but one, third and last but two, etc.
  for(i = 0 ; i < length/2 ; ++i)
  {
    temp = str[i];
    str[i] = str[length - i - 1];
    str[length - i - 1] = temp;
  }

  // Shift the string to the right and insert spaces
  if(width > length)
  {
    for(int i = length, j = width ; i >= 0 ; --i, --j)
      str[j] = str[i];
    for(i = 0 ; i < width - length ; ++i)
      str[i] = ' ';
  }
  return str;                                    // Return the string
}


int main(void)
{
   char str[STR_LEN];                            // Stores string representation of integer
   long testdata[] = { 30L, -98L, 0L, -1L, 999L, -12345L, 1234L};
   size_t width = 8;                             // Width for integer to string
   for (size_t i = 0 ; i< sizeof testdata/sizeof(long) ; ++i)
  {
    if(itoa(testdata[i],str, sizeof(str), width))
     printf("Integer value is %10d, string is %s\n",testdata[i], str);
  }

   return 0;
}


/**********************************************************************************/
// Exercise 8.4 A function to return the number of words in a string passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define LENGTH_INCREMENT  20
#define MAX_WORD_LENGTH   30

int countwords(char str[]);                                    // Function to count words in a string
int segment_string(char str[], char *words[]);                 // Function to segment a string
int count_letters(char str[]);                                 // Function to count letters in a word


int main(void)
{
   char* pStr = NULL;             // Points to memory that stores the string
   char* pTemp = NULL;            // Temporary pointer
   char** words = NULL;           // Pointer to an array of words
   int length = 0;                // Current string length
   int max_length = 0;            // Current maximum string length
   int wordcount = 0;             // Count of words in string

   // Read the string
   printf("Enter a string:\n");
   do
   { // If there is not enough memory, allocate some more
     if(length >= max_length)
     {
       max_length += LENGTH_INCREMENT;
       if(!(pTemp = realloc( pStr, max_length)))
      {
        printf("Memory allocation for string failed.\n");
        exit(1);
      }
       pStr = pTemp;
     }
   }while((pStr[length++] = getchar()) != '\n');
   pStr[--length] = '\0';         // Append string terminator

   wordcount = countwords(pStr);  // Get the word count

   // Now allocate memory to hold the words
   words = (char**)malloc(wordcount*sizeof(char*));
   for(int i = 0 ; i < wordcount ; ++i)
     words[i] = (char*)malloc(MAX_WORD_LENGTH);

   segment_string(pStr, words);   // Segment the string into words

   // Sort the words in order of length */
   for(size_t i = 0 ; i < wordcount - 1 ; ++i)
  {
     for(size_t j = i ; j < wordcount ; ++j)
    {
       if(count_letters(words[i]) > count_letters(words[j]))
       {
         pTemp = words[i];
         words[i] = words[j];
         words[j] = pTemp;
       }
    }
  }
   // Output the words and free the memory
   printf("The words in the string in order of length are:\n");
   for(size_t i = 0 ; i < wordcount ; ++i)
   {
     printf("%s\n",words[i]);
     free(words[i]);
   }
   free(words);      // Free the memory for the pointers
   return 0;
}

// Function to count words in a string
int countwords(char str[])
{
  int count = 0;
  size_t i = 0;
  while(str[i] != '\0')
  {
    if(!isalpha(str[i]))
    {
      i++;
      continue;
    }
    ++count;
    while(isalpha(str[++i]))
      ;
  }
  return count;
}

// Function to segment a string into words and return he number of words
int segment_string(char str[], char *words[])
{
  int count = 0;
  size_t i = 0;
  size_t j = 0;
  while(str[i] != '\0')
  {
    if(!isalpha(str[i]))
    {
      i++;
      continue;
    }
    j = 0;
    while(isalpha(str[i]))
    {
      words[count][j++] = str[i++];
    }
    words[count++][j] = '\0';
  }
 return count;
}

// Function to count letters in a word
int count_letters(char str[])
{
  int count = 0;
  size_t i = 0;
  while(str[i] != '\0')
  {
    if(isalpha(str[i++]))
      ++count;
  }
  return count;
}

/**********************************************************************************/
// Exercise 9.1 A recursive power function
#include <stdio.h>

double power(double x, int n);


int main(void)
{
  for(double x = 2.0 ; x <= 5.0; x += 0.5)
  {
    for(int n = -4 ; n < 5 ; ++n)
      printf("The value of %.2lf raised to the power %d is %.4lf\n", x, n, power(x,n));
    printf("\n");
  }

  return 0;
}

// Function to raise x to the power n
double power(double x, int n)
{
  if(n < 0)
  {
    n = -n;
    x = 1.0/x;
  }

  if(n == 0)
    return 1.0;

  return x*power(x, n - 1);
}

/**********************************************************************************/
// Exercise 9.2 Implementing arithmetic and array functions 
#include <stdio.h>

double add(double a, double b);                                         // Returns a+b
double subtract(double a, double b);                                    // Returns a-b 
double multiply(double a, double b);                                    // Returns a*b
double array_op(double array[], size_t size, double (*pfun)(double,double));


int main(void)
{
  double array[] = {11.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0};

  int length = sizeof array/sizeof(double);
  printf("The value of:\n");
  for(int i = 0 ; i< length ; i++)
  {
    printf("%.2lf%s", array[i], (i<length-1?" + ":"\n"));
  }
  printf(" is %.2lf\n", array_op(array,length,add));

  printf("\nThe value of:\n");
  for(int i = 0 ; i< length ; i++)
  {
    printf("%.2lf%s", array[i], (i < length - 1 ? (i%2==0?" - ":" + ") : "\n"));
  }
  printf(" is %.2lf\n", array_op(array, length, subtract));http://puui.qpic.cn/coral/Q3auHgzwzM6s5S3ZGB1e0ILZOK4KEvrYicJEIzrweguLXPY87ibRgNkA/100

  printf("\nThe value of:\n");
  for(int i = 0 ; i < length ; ++i)
  {
    printf("%.2lf%s", array[i], (i < length - 1 ? " * "  :"\n"));
  }
  printf(" is %.2lf\n", array_op(array, length, multiply));
  return 0;
}

// Function to calculate a+b
double add(double a, double b)
{
  return a + b;
}

// Function to calculate a-b
double subtract(double a, double b)
{
  return a - b;
}

// Function to calculate a*b
double multiply(double a, double b)
{
  return a*b;
}

// Function to apply an operation, pfun, between successive pairs of elements
double array_op(double array[], size_t size, double (*pfun)(double,double))
{
  double result = array[size - 1];
  size_t i = 0;
  // Work from last to first to accommodate alternating signs for subtract
  for(i = size - 1 ; i > 0 ; i--)
    result = pfun(array[i - 1], result);
  return result;
}

/**********************************************************************************/
// Exercise 9.3 Join array of strings into a single string
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_STRINGS 100                                                   // Maximum string count
#define BUFFER_SIZE 50                                                    // Initial input buffer size

char* join_strings(char *strings[], size_t max_length, size_t count);     // Joins array of strings into a single string 
char* read_string(char terminator, size_t *length);                       // Reads a string from the keyboard

int main(void)
{
  char *pStrings[MAX_STRINGS];                                            // Array of pointers to strings
  char *joined_strings = NULL;                                            // Pointer to the joined string
  size_t length = 0;                                                      // Length of a string
  size_t max_length = 0;                                                  // Maximum string length
  size_t count = 0;                                                       // Number of strings entered
  char answer = 'y';                                                      // Confirms more input
  char terminator = '*';                                                  // Terminator for string entry

  // Read the strings
  while(count < MAX_STRINGS && tolower(answer) == 'y')
  {
    printf("Enter a string terminated by an asterisk:\n");
    if(!(pStrings[count++] = read_string(terminator, &length)))
      exit(1);
    
    if(max_length < length)
      max_length = length;

    printf("Do you want to enter another: ");
    scanf_s(" %c", &answer, sizeof(answer));
    fflush(stdin);                                                        // Lose newline following answer entry
  }

  joined_strings = join_strings(pStrings, max_length, count);
  printf("\nHere are the strings as a single string:\n%s\n", joined_strings);

  free(joined_strings);                                                   // Free memory for joined strings
  for(size_t i = 0 ; i < count ; ++i)                                     // Free memory for original strings
    free(pStrings[i]);
  return 0;
}

/*******************************************************************
 * Function to join an array of strings                            *
 * this function allocates memory that must be freed by the caller *
 * max_length is the length of the longest string, which provides  *
 *  for a safer operation by limiting potential overrun.           *
 *******************************************************************/
char* join_strings(char *strings[], size_t max_length, size_t count)
{
  char* str = NULL;                                                       // Pointer to the joined strings
  size_t total_length = 0;                                                // Total length of joined strings
  size_t length = 0;                                                      // Length of a string

  // Find total length of joined strings
  for(size_t i = 0 ; i < count ; ++i)
  {
    length = strnlen_s(strings[i], max_length);
    total_length += length;
    if(strings[i][length - 1] != '\n')
      ++total_length;                                                     // For newline to be added as separator
  }
  ++total_length;                                                         // For joined string terminator
  printf("Str length: %zd\n", total_length);

  str = (char*)malloc(total_length);                                      // Allocate memory for joined strings
  str[0] = '\0';                                                          // Empty string we can append to

  // Append all the strings
  for(size_t i = 0 ; i < count ; ++i)
  {
    strcat_s(str, total_length, strings[i]);
    length = strnlen_s(str, total_length);
    
    if(str[length - 1] != '\n')                                           // If last character is not a newline
    {
      str[length] = '\n';                                                 // ...replace terminator by a newline... 
      str[length + 1] = '\0';                                             // ...followed by a new terminator
    }
  }
  return str;
}

/***************************************************************************
 * Reads a string of any length.                                           *
 * The string is terminated by the character passed as the argument.       *
 * Memory is allocated to hold the string and must be freed by the caller. *
 * The size of memory occupied by the string is stored in len.             *
 ***************************************************************************/
char* read_string(char terminator, size_t *len)
{
  char *buffer = NULL;                                                    // Pointer to the input buffer
  size_t buffersize = 0;                                                  // Current buffer capacity
  size_t length = 0;                                                      // String length
  char *temp = NULL;                                                      // Temporary buffer pointer

  buffer = (char*)malloc(BUFFER_SIZE);                                    // Initial buffer

  // Read the string character by character
  for(;;)
  {
    // Check for buffer overflow
    if(length == buffersize)
    {
      buffersize += BUFFER_SIZE;                                           // Increase buffer size
      if(!(temp = (char*)realloc(buffer, buffersize)))                     // Allocate new buffer
      {
        printf("Input buffer memory allocation failed.\n");
        return NULL;
      }
      buffer = temp;                                                       // Store new buffer address
    }

    // Check for string terminator
    if((buffer[length] = getchar()) == terminator)
      break;
    else
      ++length;
  }

  buffer[length] = '\0';                                                  // Append string terminator
  *len = ++length;
  if(!(temp = (char*)realloc(buffer, length)))                            // Allocate new buffer of exact size
  {
    printf("Input buffer memory allocation failed.\n");
    return NULL;
  }
  return temp;
}

/**********************************************************************************/
// Exercise 9.4 Convert one or more floating-point values into a single string
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdbool.h>

char* to_string(int count, double first, ...);  // Converts doubles to a string separated by commas
char* fp_to_str(double x, size_t *len);         // Converts x to a string
char* int_to_str(int n, size_t *len);           // Converts n to a string

int main(void)
{
  char *str = NULL;                             // Pointer to the string of values
  double values[] = { 1.245, -3.5, 6.758, 33.399, -1.02 };

  printf("\nThe numerical values are:\n");
  for(size_t i = 0 ; i < 5 ; ++i)
    printf("%8.3f", values[i]);

  str = to_string(sizeof values/sizeof(double), values[0], values[1], values[2], values[3], values[4]);

  printf("\n\nThe string of values is:\n%s\n", str);

  free(str);                         // Free memory for string
  return 0;
}

/*******************************************************************
 * Function to convert one or more floating-point values to a      *
 * string with the values separated by commas.                     *
 * This function allocates memory that must be freed by the caller *
 *******************************************************************/
char* to_string(int count, double first, ...)
{
  va_list parg = NULL;                                       // Pointer to variable argument
  char* str = NULL;                                          // Pointer to the joined strings
  char *temp = NULL;                                         // Temporary string pointer
  char *value_str = NULL;                                    // Pointer to a value string
  const char separator[] = ", ";                             // Separator in values string
  size_t separator_length = sizeof(separator)/sizeof(char);  // Length of separator string
  size_t length = 0;                                         // Length of a string
  size_t fp_len = 0;                                         // Floating-point string length


  va_start(parg,first);                                      // Initialize argument pointer

  str = fp_to_str(first, &length);                           // convert the first value

  // Get the remaining arguments, convert them and append to the string
  while(--count > 0)
  {
    value_str = fp_to_str(va_arg(parg, double), &fp_len);    // Get next argument
    length = strnlen_s(str, length) + strnlen_s(value_str, fp_len) + separator_length + 1;
    if(!(temp = (char*)realloc(str, length)))                // Allocate space for string with argument added
    {
      printf("Memory allocation for string failed.\n");
      exit(1);
    }

    str = temp;                                              // Store new memory address
    strcat_s(str, length, separator);                        // Append separator
    strcat_s(str,length, value_str);                         // Append value string
    free(value_str);                                         // Release value string memory
  }
  va_end(parg);                                              // Clean up arg pointer
  return str;
}

/***************************************************************************
 * Converts the floating-point argument to a string.                       *
 * Result is with two decimal places.                                      *
 * Memory is allocated to hold the string and must be freed by the caller. *
 ***************************************************************************/
char* fp_to_str(double x, size_t *len)
{
  char *str = NULL;                                          // Pointer to string representation
  char *integral = NULL;                                     // Pointer to integral part as string
  char *fraction = NULL;                                     // Pointer to fractional part as string
  size_t length = 0;                                         // Total string length required
  size_t integral_len = 0;
  size_t fraction_len = 0;
  integral = int_to_str((int)x, &integral_len);              // Get integral part as a string with a sign

  // Make x positive
  if(x < 0)
    x = -x;
  // Get fractional part as a string
  fraction = int_to_str((int)(100.0*(x + 0.005 - (int)x)), &fraction_len);

  length = strnlen_s(integral, integral_len) + strnlen_s(fraction, fraction_len) + 2;  // Total length including point and terminator

  // Fraction must be two digits so allow for it
  if(strlen(fraction) < 2)
    ++length;
  *len = length;
  str = (char*)malloc(length);                               // Allocate memory for total
  strcpy(str, integral);                                     // Copy the integral part
  strcat(str, ".");                                          // Append decimal point

  if(strlen(fraction) < 2)                                   // If fraction less than two digits
    strcat(str,"0");                                         // Append leading zero

  strcat(str, fraction);                                     // Append fractional part

  // Free up memory for parts as strings
  free(integral);
  free(fraction);

  return str;
}

/***************************************************************************
 * Converts the integer argument to a string.                              *
 * Memory is allocated to hold the string and must be freed by the caller. *
 ***************************************************************************/
char* int_to_str(int n, size_t *len)
{
  char *str = NULL;                                          // pointer to the string
  size_t length = 1;                                         // Number of characters in string(at least 1 for terminator
  bool negative = n < 0;                                     // Indicates sign of n

  // Check for negative value
  if(negative)
  {
    n = -n;
    ++length;                                                // For the minus character
  }

  // Increment length by number of digits in n
  int temp = n;
  do
  {
    ++length;
  }
  while((temp /= 10) > 0);

  str = (char*)malloc(length);                               // Allocate space required
  *len = length;

  if(negative)                                               // If it was negative
    str[0] = '-';                                            // Insert the minus sign

  str[--length] = '\0';                                      // Add the terminator to the end

  // Add the digits starting from the end
  do
  {
    str[--length] = '0' + n%10;
  }while((n /= 10) > 0);

  return str;
}

/**********************************************************************************/
// Exercise 9.4 Convert one or more floating-point values into a single string
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdbool.h>

char* to_string(int count, double first, ...);  // Converts doubles to a string separated by commas
char* fp_to_str(double x, size_t *len);         // Converts x to a string
char* int_to_str(int n, size_t *len);           // Converts n to a string

int main(void)
{
  char *str = NULL;                             // Pointer to the string of values
  double values[] = { 1.245, -3.5, 6.758, 33.399, -1.02 };

  printf("\nThe numerical values are:\n");
  for(size_t i = 0 ; i < 5 ; ++i)
    printf("%8.3f", values[i]);

  str = to_string(sizeof values/sizeof(double), values[0], values[1], values[2], values[3], values[4]);

  printf("\n\nThe string of values is:\n%s\n", str);

  free(str);                         // Free memory for string
  return 0;
}

/*******************************************************************
 * Function to convert one or more floating-point values to a      *
 * string with the values separated by commas.                     *
 * This function allocates memory that must be freed by the caller *
 *******************************************************************/
char* to_string(int count, double first, ...)
{
  va_list parg = NULL;                                       // Pointer to variable argument
  char* str = NULL;                                          // Pointer to the joined strings
  char *temp = NULL;                                         // Temporary string pointer
  char *value_str = NULL;                                    // Pointer to a value string
  const char separator[] = ", ";                             // Separator in values string
  size_t separator_length = sizeof(separator)/sizeof(char);  // Length of separator string
  size_t length = 0;                                         // Length of a string
  size_t fp_len = 0;                                         // Floating-point string length


  va_start(parg,first);                                      // Initialize argument pointer

  str = fp_to_str(first, &length);                           // convert the first value

  // Get the remaining arguments, convert them and append to the string
  while(--count > 0)
  {
    value_str = fp_to_str(va_arg(parg, double), &fp_len);    // Get next argument
    length = strnlen_s(str, length) + strnlen_s(value_str, fp_len) + separator_length + 1;
    if(!(temp = (char*)realloc(str, length)))                // Allocate space for string with argument added
    {
      printf("Memory allocation for string failed.\n");
      exit(1);
    }

    str = temp;                                              // Store new memory address
    strcat_s(str, length, separator);                        // Append separator
    strcat_s(str,length, value_str);                         // Append value string
    free(value_str);                                         // Release value string memory
  }
  va_end(parg);                                              // Clean up arg pointer
  return str;
}

/***************************************************************************
 * Converts the floating-point argument to a string.                       *
 * Result is with two decimal places.                                      *
 * Memory is allocated to hold the string and must be freed by the caller. *
 ***************************************************************************/
char* fp_to_str(double x, size_t *len)
{
  char *str = NULL;                                          // Pointer to string representation
  char *integral = NULL;                                     // Pointer to integral part as string
  char *fraction = NULL;                                     // Pointer to fractional part as string
  size_t length = 0;                                         // Total string length required
  size_t integral_len = 0;
  size_t fraction_len = 0;
  integral = int_to_str((int)x, &integral_len);              // Get integral part as a string with a sign

  // Make x positive
  if(x < 0)
    x = -x;
  // Get fractional part as a string
  fraction = int_to_str((int)(100.0*(x + 0.005 - (int)x)), &fraction_len);

  length = strnlen_s(integral, integral_len) + strnlen_s(fraction, fraction_len) + 2;  // Total length including point and terminator

  // Fraction must be two digits so allow for it
  if(strlen(fraction) < 2)
    ++length;
  *len = length;
  str = (char*)malloc(length);                               // Allocate memory for total
  strcpy(str, integral);                                     // Copy the integral part
  strcat(str, ".");                                          // Append decimal point

  if(strlen(fraction) < 2)                                   // If fraction less than two digits
    strcat(str,"0");                                         // Append leading zero

  strcat(str, fraction);                                     // Append fractional part

  // Free up memory for parts as strings
  free(integral);
  free(fraction);

  return str;
}

/***************************************************************************
 * Converts the integer argument to a string.                              *
 * Memory is allocated to hold the string and must be freed by the caller. *
 ***************************************************************************/
char* int_to_str(int n, size_t *len)
{
  char *str = NULL;                                          // pointer to the string
  size_t length = 1;                                         // Number of characters in string(at least 1 for terminator
  bool negative = n < 0;                                     // Indicates sign of n

  // Check for negative value
  if(negative)
  {
    n = -n;
    ++length;                                                // For the minus character
  }

  // Increment length by number of digits in n
  int temp = n;
  do
  {
    ++length;
  }
  while((temp /= 10) > 0);

  str = (char*)malloc(length);                               // Allocate space required
  *len = length;

  if(negative)                                               // If it was negative
    str[0] = '-';                                            // Insert the minus sign

  str[--length] = '\0';                                      // Add the terminator to the end

  // Add the digits starting from the end
  do
  {
    str[--length] = '0' + n%10;
  }while((n /= 10) > 0);

  return str;
}

/**********************************************************************************/
// Exercise 10.2 Reading monetary amounts separated by commas and spaces.
/*
  You only need to ensure that the input format string specifies that '$',
  spaces, and commas are ignored.
*/
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#define COUNT 4

int main(void)
{
  double amounts[COUNT] = {0.0};
  double total = 0.0;
 
   printf_s("Enter the %d amounts:\n", COUNT);
   for(size_t i = 0 ; i < COUNT ; ++i)
   {
     scanf_s("%*[ ,$]%lf", &amounts[i]);
     total += amounts[i];
   }
     
   printf_s("The total of the input is: $%.2lf\n", total);
}


/**********************************************************************************/
// Exercise 10.3 A function to output double values in a given width.
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAX_COUNT 100

void show(double array[], size_t array_size, unsigned int field_width);

int main(void)
{
	char result[20];
	int coun=4;
	sprintf_s(result,sizeof(result),"a dog has %d legs.",coun);
	printf("\n==============%s==========\n",result);
  double array[MAX_COUNT] = {0.0};
  size_t count = 0;
  for(double x = 1.5 ; x < 4.6 ; x += 0.3)
    array[count++] = x;

  unsigned int width = 12;
  show(array, count, width);
  
   printf_s("\n");
}

void show(double array[], size_t array_size, unsigned int field_width)
{
  char format[10] = {'\0'};                         // Holds the format string
  unsigned int places = 2;  
  _snprintf_s(format, sizeof(format),sizeof(format), "%%%u.%ulf",field_width,places);
  printf("\nformat=%s",format);
  // Output the values five to a line;

  for(size_t j = 0 ; j < array_size ; ++j)
  {
    if(j%5 == 0)
      printf_s("\n");

    printf_s(format, array[j]);
	
  }
  
}

/**********************************************************************************/
// Exercise 10.4 A function to read a string terminated by an arbitrary character.
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>

#define MAX_SIZE     100
#define STRING_COUNT   5

char* getString(char *buffer, size_t buffer_size, char end_char);

int main(void)
{
  char buffer[MAX_SIZE] = {0};
  int i = 0;
  for(i = 0 ; i < STRING_COUNT ; ++i)
  {
    printf_s("\nEnter a string terminated by a semi-colon:\n");
    if(!getString(buffer, MAX_SIZE,  ':'))
    {
      printf_s("Error return but continuing...\n");
      continue;
    }
    printf_s("The string you entered was:\n%s\n", buffer);
  }
}

char* getString(char *buffer, size_t size, char end_char)
{
  size_t i = 0;
  // Read a character until end_char is entered
  while((buffer[i++] = getchar()) != end_char)
  {
    if(i >= size)
    {
      printf_s("Buffer capacity exceeded.\n");
      return NULL;
    }
  }
  fflush(stdin);                                 // Clear out newline
  buffer[i-1] = '\0';                            // Overwrite end_char with string terminator
  return buffer;
}

/**********************************************************************************/
// Exercise 11.1 Using a structure representing a length.
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <ctype.h>

#define INCHES_PER_FOOT 12
#define FEET_PER_YARD    3

typedef struct Length
{
  unsigned int yards;
  unsigned int feet;
  unsigned int inches;
} Length;

Length add(const Length first, const Length second);
void show(const Length length);

int main(void)
{
  char answer = 'n';
  Length length = {0};
  Length total = {0};

  do
  {
    printf_s("Enter a length in yards, feet, and inches: ");
    scanf_s(" %u %u %u", &length.yards, &length.feet, &length.inches);
    total = add(total,length);
    printf_s("Do you want to enter another(y or n)?: ");
    scanf_s(" %c", &answer, sizeof(answer));
    fflush(stdin);
  }while(tolower(answer) == 'y');

  printf_s("The total of all the lengths is: ");
  show(total);
  printf_s("\n");
  return 0;
}

struct Length add(const Length first, const Length second)
{
  unsigned long inches = 0;
  Length sum;
  inches = first.inches + second.inches+
    INCHES_PER_FOOT*(first.feet + second.feet + FEET_PER_YARD*(first.yards + second.yards));
  sum.inches = inches%INCHES_PER_FOOT;
  sum.feet = inches/INCHES_PER_FOOT;
  sum.yards = sum.feet/FEET_PER_YARD;
  sum.feet %= FEET_PER_YARD;
  return sum;
}

void show(const Length length)
{
  printf_s("%u yards %u feet %u inches", length.yards, length.feet, length.inches);
}

/**********************************************************************************/
// Exercise 11.2 Using a structure representing a person's name.
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

#define FIRST_NAME_LEN  31
#define SECOND_NAME_LEN 51
#define NUMBER_LEN      16
#define MAX_NUMBERS     50


// Structure defining a name
typedef struct Name
{
  char firstname[FIRST_NAME_LEN];
  char secondname[SECOND_NAME_LEN];
} Name;

// Structure defining a phone record
typedef struct PhoneRecord
{
  struct Name name;
  char number[NUMBER_LEN];
} PhoneRecord;

// Function prototypes
size_t get_records(PhoneRecord records[], size_t size);                                  // Read phone records
void search_records(PhoneRecord records[], size_t count);                                // Search the phone records
int find_record(PhoneRecord records[], size_t start, size_t count, const Name *pName);   // Find the record for a name
void show(const PhoneRecord *pRecord);                                                     // Output a phone record
bool has_name(const PhoneRecord *pRecord, const Name *pName);                            // Test for a name
Name read_name();                                                                        // Read a name from the keyboard

int main(void)
{
  char answer = 'n';
  PhoneRecord records[MAX_NUMBERS];                                                      // Array of phone records
//  Name aName;                                                                          // Stores a name
  size_t count = get_records(records, MAX_NUMBERS);                                      // Number of phone records

  printf_s("\nDo you want to search the phone records (y or n)? ");
  scanf_s(" %c" , &answer, sizeof(answer));
  if(tolower(answer) == 'y')
    search_records(records, count);

  printf_s("\nThe records we have are:\n");
  for(size_t i = 0 ; i < count ; ++i)
    show(records[i]);
  printf_s("\n");
  return 0;
}

// Function to read an arbitrary number of phone records from the keyboard
size_t get_records(PhoneRecord records[], size_t size)
{
  size_t count = 0;
  char answer = 'y';
  do
  {
    records[count].name = read_name();                                        // Read the name
    printf_s("Enter the number for this name: ");
    scanf_s(" %[ 0123456789]",records[count++].number, (rsize_t)NUMBER_LEN);  // Read the number - including spaces

    printf_s("Do you want to enter another(y or n)?: ");
    scanf_s(" %c", &answer, sizeof(answer));
  }while(count <= size && tolower(answer) == 'y');
  return count;
}

// Function to output a record
void show(const PhoneRecord *pRecord)
{
  printf_s("\n%s %s   %s", pRecord->name.firstname,pRecord->name.secondname, pRecord->number);
}

// Function to test whether the name is the same as in a record
bool has_name(const PhoneRecord *pRecord, const Name *pName)
{
  return (strcmp(pName->firstname, pRecord->name.firstname) == 0 &&
                  strcmp(pName->secondname, pRecord->name.secondname) == 0);
}

// Function to read a name and store it in a Name structure
Name read_name(void)
{
  Name name;
  printf_s("Enter a first name: ");
  scanf_s(" %s", name.firstname, (rsize_t)FIRST_NAME_LEN);
  printf_s("Enter a second name: ");
  scanf_s(" %s", name.secondname, (rsize_t)SECOND_NAME_LEN);
  return name;
}

// Function to find the record for a name in records starting at index start.
// count is the number of elements in records.
// The index to the record is returned or -1 if it doesn't exist.
int find_record(PhoneRecord records[], size_t start, size_t count, const Name *pName)
{
  for(size_t i = start ; i < count ; ++i)
  {
    if(has_name(&records[i], pName))                              // Test for the name
      return i;
  }
  return -1;
}

// Search the array of phone records for a number
void search_records(PhoneRecord records[], size_t count)
{
  Name name;
  char answer = 'n';
  do
  {
    name = read_name();
    int index = 0;
    bool first = true;
    while((index = find_record(records, index, count, &name)) >= 0)
    {
      if(first)
      {
        printf_s("The numbers for %s %s are:\n", name.firstname, name.secondname); 
        first = false;   
      }
      printf_s("%s\n", records[index++].number);
      if(index >= count)
        break;  
    }
    if(first)
      printf_s("No numbers found for %s %s.\n", name.firstname, name.secondname);

    printf_s("\nDo you want to search for another name (y or n)? ");
    scanf_s(" %c" , &answer, sizeof(answer));
  }while(tolower(answer) == 'y');
}

/**********************************************************************************/
// Exercise 11.3 Using a linked list of structures representing a person's name.
/*
   You could link the PhoneRecord structures in a list by adding a pointer member.
   I chose to define a Node structure that is a node in a linked list. Each Node
   structure contains a pointer to a PhoneRecord structure and a pointer to
   the next Node structure. Memory for Node and PhoneRecord structures are allocated
   dynamically. You could extend this to allocate memory for names and numbers too.
*/
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

#define FIRST_NAME_LEN  31
#define SECOND_NAME_LEN 51
#define NUMBER_LEN      16


// Structure defining a name
typedef struct Name
{
  char firstname[FIRST_NAME_LEN];
  char secondname[SECOND_NAME_LEN];
} Name;

// Structure defining a phone record
typedef struct PhoneRecord
{
  Name name;
  char number[NUMBER_LEN];
} PhoneRecord;

// Structure defining a node in a linked list of PhoneRecord structures
typedef struct Node Node;
struct Node
{
  PhoneRecord *pRecord;                                                             // Pointer to a PhoneRecord structure
  Node *pNext;                                                                      // Pointer to the next node in the list
};

Name read_name();                                                                   // Read a name from the keyboard
void show(PhoneRecord *pRecord);                                                    // Output a phone record
bool has_name(const PhoneRecord *pRecord, const Name *pName);                       // Test for a name
Node* create_node();                                                                // Create a new list node
PhoneRecord* create_record();                                                       // Create a new phone record
void insert_node(Node *pNode);                                                      // Insert a node in the list
int compare_records(const PhoneRecord *pFirst, const PhoneRecord *pSecond);         // Compare records
int compare_names(const Name *pFirst, const Name *pSecond);                         // Compare two names
void list_numbers(const Name *pName);                                               // List all numbers for a Name structure

Node *pStart = NULL;                                                                // Root node for the linked list

int main(void)
{
  char answer = 'n';
  Node *pNode = NULL;                                                               // Pointer to a list node

  // Read an arbitrary number of phone records from the keyboard
  do
  {
    insert_node(create_node());                                                     // Create and insert new node
    printf_s("Do you want to enter another(y or n)?: ");
    scanf_s(" %c", &answer, sizeof(answer));
  }while(tolower(answer) == 'y');

  // Search the list of phone records for a number
  Name name;
  bool first = true;
  do
  {
    if(first)
    {
      first = false;
      printf_s("\nDo you want to search for a name (y or n)?");
      scanf_s(" %c" , &answer, sizeof(answer));
      if(tolower(answer) == 'n') break;
    }
    name = read_name();
    list_numbers(&name);
    printf_s("Do you want to search for another (y or n)? ");
    scanf_s(" %c" , &answer, sizeof(answer));
  }while(tolower(answer) == 'y');

  // List all the records in the linked list
  printf_s("\nThe records we have are:\n");
  pNode = pStart;
  do
  {
    show(pNode->pRecord);
  }while((pNode = pNode->pNext) != NULL);
  printf_s("\n");

  // Don't forget to free the memory!
  pNode = pStart;
  do
  {
    free(pNode->pRecord);                                                           // Free memory for the record from the current node
    pStart = pNode;                                                                 // Save current node address
    pNode = pNode->pNext;                                                           // Get next node address
    free(pStart);                                                                   // Free memory for the current node
  }while((pNode = pNode->pNext) != NULL);

  return 0;
}

// Read a name from the keyboard and store in a structure
Name read_name(void)
{
  Name name;
    printf_s("\nEnter a first name: ");
    scanf_s(" %s", name.firstname, sizeof(name.firstname));
    printf_s("Enter a second name: ");
    scanf_s(" %s", name.secondname, sizeof(name.secondname));
  return name;
}

// Output a record */
void show(PhoneRecord *pRecord)
{
  printf_s("\n%s %s   %s", pRecord->name.firstname, pRecord->name.secondname, pRecord->number);
}

bool has_name(const PhoneRecord *pRecord, const Name *pName)
{
  return (strcmp(pName->firstname, pRecord->name.firstname) == 0 &&
                  strcmp(pName->secondname, pRecord->name.secondname) == 0);
}

// Create a new list node
Node* create_node(void)
{
  Node *pNode = NULL;                                                               // Pointer to the new node
  pNode = (Node*)malloc(sizeof(Node));                                              // Allocate memory for node
  pNode->pNext = NULL;                                                              // No next node yet
  pNode->pRecord = create_record();                                                 // Create record and store address in node
  return pNode;
}

// Create a new phone record
PhoneRecord* create_record(void)
{
  PhoneRecord *pRecord = NULL;                                                      // Pointer to the new record
  pRecord = (PhoneRecord*)malloc(sizeof(PhoneRecord));                              // Allocate memory
  pRecord->name = read_name();                                                      // Read the name

  // Get the number for the name
  printf_s("Enter the number for this name: ");
  scanf_s(" %[ 0123456789]",pRecord->number, sizeof(pRecord->number));              // Read the number - including spaces
  return pRecord;                                                                   // Return the address of the record 
}

/*
  Compare two PhoneRecord structures
  Returns -1 if the name for the first is < name for the second
  Returns  0 if the name for the first is equal to the name for the second
  Returns +1 if the name for the first is > name for the second
*/
int compare_records(const PhoneRecord *pFirst, const PhoneRecord *pSecond)
{
  return compare_names(&(pFirst->name), &(pSecond->name));
}

/* Compare two names
  Returns -1 if the  first is < the second
  Returns  0 if the first is equal to tthe second
  Returns +1 if the first is >  the second

  The comparison is by second name. If second names are equal,
  first names are compared.
*/
int compare_names(const Name *pfirst, const Name *psecond)
{
  int result = 0;
  result = strcmp(pfirst->secondname,psecond->secondname);
  return (result != 0 ? result : strcmp(pfirst->firstname,psecond->firstname));
}

// Insert a node into the list
void insert_node(Node *pNode)
{
  Node *pCurrent = NULL;
  Node *pPrevious = NULL;

  // Check for empty list
  if(!pStart)
  {
    pStart = pNode;                                                                 // Store address of the node as the start node
    return;
  }

  // Find position to insert the new node
  pCurrent = pStart;
  while(pCurrent)
  {
    if(compare_records(pNode->pRecord, pCurrent->pRecord) <= 0)
    {                                                                               // New node goes before current node
      pNode->pNext = pCurrent;                                                      // Set new node next pointer to current
      if(!pPrevious)                                                                // check for no previous node
      { // pCurrent should be the first node
        pNode->pNext = pStart;                                                      // New node next pointer points to current
        pStart = pNode;                                                             // New node is the first node
      }
      else
      { // Otherwise hook pCurrent up to previous node...
        pPrevious->pNext = pNode;                                                   // Previous node next pointer points to new node
      }
      return;
    }
    // pCurrent fits later in the list so move on...
    pPrevious = pCurrent;                                                           // Previous node will be the current node
    pCurrent = pCurrent->pNext;                                                     // Current node is now the next node
  }
  // If we reach here, add pNode to the end
  pPrevious->pNext = pNode;
}

// List the numbers for a name
void list_numbers(const Name *pName)
{
  Node *pNode = NULL;
  bool found = false;
  int result = 0;

  // Go through the list comparing names
  pNode = pStart;
  while(pNode)
  {
    if(0 == (result = compare_names(pName, &(pNode->pRecord->name))))
    {
      if(!found)                                                                    // If this is the first time
      {
        found = true;                                                               // Reset found flag
        printf_s("The numbers for this name are:\n");                               // and output the heading
      }
      printf_s("%s\n", pNode->pRecord->number);                                     // Output the number for the name
    }
   else if(result < 0)                                                              // If name comes before current
      break;                                                                        // we are done
    pNode = pNode->pNext;                                                           // Otherwise move to next node
  }

  if(!found)                                                                        // If the name was not found
    printf_s("No numbers found for this name.\n");                                  // Say so
}




/**********************************************************************************/
// Exercise 11.4 Using a structure to record the count of occurrences of a word.
/*
  This program defines a structure that stores a word and the count of its occurrences.
  The structures are stored as they are created in a linked list. If you wanted the
  output in alphabetical order, you could insert the structures in the list to ensure
  that the list was ordered. Alternatively you could sort the list.
*/
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAX_WORD_LENGTH    31
#define MAX_TEXT_LENGTH 10000

// Structure defining a count of the occurrences of a given word
typedef struct WordCounter
{
  char *word;
  int word_count;
  struct WordCounter *pNext;                        // Pointer to the next word counter in the list
} WordCounter;

// Function prototypes
void addWord(char *pWord);                          // Adds a new word to the list or updates existing word
void show(const WordCounter *pWordcounter);         // Outputs a word and its count of occurrences
WordCounter* createWordCounter(char *word);         // Creates a new WordCounter structure

// Global variables
WordCounter *pStart = NULL;                         // Pointer to first word counter in the list

int main(void)
{
  char text[MAX_TEXT_LENGTH];                       // Stores input text
  WordCounter *pCounter = NULL;                     // Pointer to a word counter

  // Read the text from the keyboard
  printf_s("Enter the text:\n");
  gets_s(text, MAX_TEXT_LENGTH);

  // Extract the words from the text
  size_t text_len = sizeof(text);
  char *ptr = NULL;
  char separators[] = { ' ' , ',',':' , '\"', '?' , '!' , '.'};

  char *pWord = strtok_s(text, &text_len, separators, &ptr);  // Find 1st word
  while(pWord)
  { // While there are still words...
    addWord(pWord);                                           // Add thew word to the list
    pWord = strtok_s(NULL, &text_len, separators, &ptr);      // .. and find the next one
  }

  // List the words and their counts
  pCounter = pStart;
  while(pCounter)
  {
    show(pCounter);
    pCounter = pCounter->pNext;
  }
  printf_s("\n");

  // Free the memory that we allocated
  pCounter = pStart;
  while(pCounter)
  {
    free(pCounter->word);                           // Free space for the word
    pStart = pCounter;                              // Save address of current
    pCounter = pCounter->pNext;                     // Move to next counter
    free(pStart);                                   // Free space for current
  }
  return 0;
}

// Output a word and its count
void show(const WordCounter *pWordcounter)
{
  // output the word left-justified in a fixed field width followed by the count
  printf_s("\n%-30s   %5d", pWordcounter->word,pWordcounter->word_count);
}

void addWord(char *word)
{
  WordCounter *pCounter = NULL;
  WordCounter *pLast = NULL;

  if(!pStart)
  {
    pStart = createWordCounter(word);
    return;
  }

  // If the word is in the list, increment its count
  pCounter = pStart;
  while(pCounter)
  {
    if(strcmp(word, pCounter->word) == 0)
    {
      ++pCounter->word_count;
      return;
    }
    pLast = pCounter;                               // Save address of last in case we need it
    pCounter = pCounter->pNext;                     // Move to next in the list
  }

  // If we get to here it's not in the list - so add it
  pLast->pNext = createWordCounter(word);
}

// Create and returns a new WordCounter object for the argument
WordCounter* createWordCounter(char *word)
{
  WordCounter *pCounter = NULL;
  pCounter = (WordCounter*)malloc(sizeof(WordCounter));
  pCounter->word = (char*)malloc(strlen(word) + 1);
  strcpy(pCounter->word, word);
  pCounter->word_count = 1;
  pCounter->pNext = NULL;
  return pCounter;
}

/**********************************************************************************/
// Exercise 11.5 Sorting names using a binary tree
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define FIRST_MAX  30
#define SECOND_MAX 50


// Defines a name
typedef struct Name
{
  char first[FIRST_MAX];
  char second[SECOND_MAX];
} Name;

// Defines a node in a binary tree sorting integers
typedef struct Node Node;
struct Node
{
  Name *pName;                                        // Pointer to a name
  int count;                                          // Number of copies of item
  Node *pLeft;                                        // Pointer to left node
  Node *pRight;                                       // Pointer to right node
};

// Function prototypes
Name *readname();                                     // Read a name
int compare(const Name *pName1, const Name *pName2);  // Compare names
void printname(const Name *pName);                    // Output a name
Node *createnode(Name *pName);                        // Create a tree node
void addnode(Name *pName, Node* pNode);              // Insert a new node
void listnodes(Node *pRootNode);                      // List all nodes
void freenodes(Node *pRootNode);                      // Release memory


// Function main - execution starts here
int main(void)
{
  Node *pRoot = NULL;
  char answer = 'n';
  do
  {
    if(!pRoot)
       pRoot = createnode(readname());
    else
      addnode(readname(), pRoot);
    printf_s("\nDo you want to enter another (y or n)? ");
    scanf_s(" %c", &answer, sizeof(answer));
    fflush(stdin);                                    // Get rid of the newline
  } while(tolower(answer) == 'y');

  printf_s("The names in ascending sequence are:\n");
  listnodes(pRoot);                                   // Output the contents of the tree
  freenodes(pRoot);                                   // Release the heap memory

  return 0;
}

/*****************************************
 * Creates a Name object on the heap and *
 * reads the first and second names from *
 * stdin.                                *
 * The freenodes() function takes care   *
 * of releasing the memory for names.    *
 *****************************************/
Name *readname(void)
{
  Name *pName = malloc(sizeof(Name));
  printf_s("Enter the first name: ");
  fgets(pName->first, FIRST_MAX, stdin);
  size_t len = strnlen_s(pName->first, FIRST_MAX);
  if(pName->first[len - 1] == '\n')                   // If there's a newline at the end 
    pName->first[len - 1] = '\0';                     // overwrite it.

  printf_s("Enter the second name: ");
  fgets(pName->second, SECOND_MAX, stdin);
  len = strnlen_s(pName->second, SECOND_MAX);
  if(pName->second[len - 1] == '\n')                  // If there's a newline at the end
    pName->second[len - 1] = '\0';                    // overwrite it.
  return pName;
}

/*************************************************
 * Creates a new node on the heap that contains  *
 * the pointer to the name that is passed as     *
 * the argument.                                 *
 *************************************************/
Node *createnode(Name *pName)
{
  Node *pNode = (Node*)malloc(sizeof(Node));
  pNode->pName = pName;                               // Set the name
  pNode->count = 1;                                   // Set the count
  pNode->pLeft = pNode->pRight = NULL;                // No left or right nodes
  return pNode;
}

// Add a new node to the tree
void addnode(Name *pName, Node* pNode)
{
 // if(!pNode)                                          // If there's no root node
 // {
 //   pNode = createnode(pName);                         // ...create one
 // }

  if(compare(pName, pNode->pName) == 0)               // If name equals current node...                                                   
    ++pNode->count;                                   // ...increment count
  else if(compare(pName, pNode->pName) < 0)           // If less than current node name...
  {
    if(!pNode->pLeft)                                 // ...and there's no left node
      pNode->pLeft = createnode(pName);               // ...create a new left node.
    else                                              // If there is a left node...
       addnode(pName, pNode->pLeft);                  // ...add name via the left node
  }
  else                                                // name is greater than current...
  {
    if(!pNode->pRight)                                // ...so the same process with the right node. 
      pNode->pRight = createnode(pName);
    else
      addnode(pName, pNode->pRight);
  }
}

/**********************************************
 * Lists the node names in ascending sequence *
 **********************************************/
void listnodes(Node *pNode)
{
  if(pNode->pLeft)
    listnodes(pNode->pLeft);

  for(int i = 0; i < pNode->count ; ++i)
    printname(pNode->pName);

  if(pNode->pRight)
    listnodes(pNode->pRight);
}

/*************************************
 * Release memory allocated to nodes *
 * including the memory for the name *
 * referenced by the pName member of *
 * each node.                        *
 *************************************/
void freenodes(Node *pNode)
{
  if(!pNode)                                          // If there's no node...
    return;                                           // ...we are done.

  if(pNode->pLeft)                                    // If there's a left sub-tree...
    freenodes(pNode->pLeft);                          // ...free memory for those nodes.

  if(pNode->pRight)                                   // If there's a right sub-tree...
    freenodes(pNode->pRight);                         // ...free memory for those nodes.

  free(pNode->pName);                                 // Release name memory...
  free(pNode);                                        // ...then current node memory
}

/***************************
 * Write a name to stdout. *
 ***************************/
void printname(const Name *pName)
{
  printf_s("%s %s\n", pName->first, pName->second);
}

/*********************************************
 * Compare two Name objects.                 *
 * If the second names are not equal, return *
 * the result of comparing them. Otherwise   *
 * return the result of comparing the first  *
 * members of the Name objects.              *
 *********************************************/
int compare(const Name *pName1, const Name *pName2)
{
  int result = strcmp(pName1->second, pName2->second);
  if(result != 0)
    return result;
  return strcmp(pName1->first, pName2->first);
}

/**********************************************************************************/
// Exercise 12.1 Writing strings to a file.
/*
  This program creates the file in the current directory.
  You will nee to copy or move the file to the current directory for Exercise 12.2.
  Alternatively you can amend the code to specify a full file path and use the 
  same path in Exercise 12.2.
*/

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define BUFFER_SIZE 50

// Function prototypes
char *read_string(char *buffer, int *pbuffer_size);

int main(void)
{
  FILE *pFile = NULL;                               // File pointer
  char *filename = "myfile.bin";                    // Name of the file to be written
  char answer = 'n';
  size_t str_length = 0;
  int buffer_size = BUFFER_SIZE;
  char *buffer = malloc(buffer_size);               // Create initial buffer

  if(fopen_s(&pFile, filename, "wb"))               // Open myfile.txt to write it
  {
    printf_s("Error opening %s for writing. Program terminated.\n", filename);
    exit(1);
  }
  setvbuf(pFile, NULL, _IOFBF, 512); 

  do
  {  
    printf_s("Enter a string:\n");
    read_string(buffer, &buffer_size);              // Read a string into buffer
    str_length = strnlen_s(buffer, buffer_size);    // Get the string length
    fwrite(&str_length, sizeof(size_t), 1, pFile);  // Write string length to file
    fwrite(buffer, str_length, 1, pFile);           // Write string to file

    printf_s("Do you want to enter another (y or n)? ");
    scanf_s(" %c", &answer, sizeof(answer));
    fflush(stdin);                                  // Flush to lose the newline
  }while(tolower(answer) == 'y');

  fclose(pFile);                                    // Close file
  printf_s("\nFile write complete\n");
  if(buffer)
    free(buffer);
  return 0;
 }

// Reads a string of arbitrary length from the keyboard
// If the string exceeds the buffer capacity, the buffer
// is increased automatically.
char *read_string(char *buffer, int *pbuffer_size)
{
  char *temp = NULL;                                // Used to hold new buffer address
  int position = 0;                                 // Current free position in buffer

  while((buffer[position++] = getchar()) != '\n')
  {
    if(position >= *pbuffer_size - 1)               // Is the buffer full?
    { // Increase the size of the buffer
      *pbuffer_size += BUFFER_SIZE;                 // New buffer size
      if(!(temp = (char*)realloc( buffer, *pbuffer_size)))   // Create new buffer
      {
        printf_s("Error allocatiuong input buffer.\n");
        exit(1);
      }
      position = temp + position - buffer;
      buffer = temp;
    }
  }
  buffer[position-1] = '\0';                        // Overwrite newline with terminator
  return buffer;
}

/**********************************************************************************/
// Exercise 12.2 Reading strings from a file in reverse order.
#define __STDC_WANT_LIB_EXT1__ 1

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

#define BUFFER_SIZE 50

// Function prototypes
size_t get_count(char *file_name);
fpos_t* get_string_positions(char *file_name, size_t str_count);
void copy_file_reversed( char *in_name, char *out_name, fpos_t *positions, size_t str_count);
void list_strings(char *file_name);

// Global variables
char *buffer = NULL;                               // Input/Output buffer for strings
size_t buffer_size = 0;                            // I/O buffer size

int main(void)
{
  char *infilename = "myfile.bin";                 // Name of the file to be read 
  char *outfilename = "outfile.bin";               // Name of the file to be written

  buffer_size = BUFFER_SIZE;                       // Initial buffer size
  buffer = (char*)malloc(buffer_size);             // Create initial buffer
  size_t str_count = get_count(infilename);
  fpos_t *positions = get_string_positions(infilename, str_count);
  copy_file_reversed(infilename, outfilename, positions, str_count);
  list_strings(outfilename);

  // Free the memory we allocated
  free(buffer);
  free(positions);
  return 0;
 }

// Function to get the number of strings in the file 
// and set the buffer size to accommodate the maximum string length
size_t get_count(char *file_name)
{
  FILE *pFile = NULL;                                     // File pointer to input file
  size_t str_length = 0;                                  // Length of a string
  size_t str_count = 0;                                   // Number of strings
  if(fopen_s(&pFile, file_name, "rb"))                    // Open the input file
  {
    printf_s("Error opening %s for reading. Program terminated.", file_name);
    exit(1);
  }
  setvbuf(pFile, NULL, _IOFBF, 512); 

  for(;;)
  {
    fread(&str_length, sizeof(size_t), 1, pFile);         // Read the string length
    if(feof(pFile))                                       // If it is end of file
      break;                                              // We are finished

    // Check buffer is large enough and increase if necessary
    if(str_length >= buffer_size)
    {
      buffer_size = str_length  + 1;
      if(!(buffer = (char*)realloc(buffer, buffer_size)))
      {
        printf_s("Buffer allocation failed.\n");
        exit(1);
      }
    }
    fread(buffer, str_length, 1, pFile);                  // Read the string
    ++str_count;
  }
  fclose(pFile);
  printf_s("\nThere are %zd strings in the input file.", str_count);
  return str_count;
}

// Function to get the position for the beginning of each record in the file
fpos_t* get_string_positions(char *file_name, size_t str_count)
{
  FILE *pFile = NULL;                                     // File pointer to input file
  if(fopen_s(&pFile, file_name, "rb"))                    // Open the input file
  {
    printf_s("Error opening %s for reading. Program terminated.", file_name);
    exit(1);
  }
  setvbuf(pFile, NULL, _IOFBF, 512); 

  fpos_t *positions = (fpos_t*)malloc(str_count*sizeof(fpos_t));  // Array to store the positions
  size_t str_length = 0;                                  // Length of a string
  for(int i = 0 ; i < str_count ; ++i)
  {
    fgetpos(pFile, positions + i);                        // Get the positions
    fread(&str_length, sizeof(size_t), 1, pFile);         // Read the string length
    fread(buffer, str_length, 1, pFile);                  // Read the string
  }
  fclose(pFile);
  return positions;
}

// Copy strings from input file to new file in reverse order
void copy_file_reversed( char *in_name, char *out_name, fpos_t *positions, size_t str_count)
{
  FILE *pInFile = NULL;                                   // File pointer to input file
  FILE *pOutFile = NULL;                                  // File pointer  to output file

  // Open input file for binary read
  if(fopen_s(&pInFile, in_name, "rb"))                    // Open the input file
  {
    printf_s("Error opening %s for reading. Program terminated.", in_name);
    exit(1);
  }
  setvbuf(pInFile, NULL, _IOFBF, 512); 

  // Open output file for binary write
  if(fopen_s(&pOutFile, out_name, "wb"))
  {
    printf_s("Error opening %s for writing. Program terminated.", out_name);
    exit(1);
  }
  setvbuf(pOutFile, NULL, _IOFBF, 512); 

  // Read the records in reverse order from the input file and write to the new file
  size_t str_length = 0;
  for(int i = 0 ; i < str_count ; ++i)
  {
    fsetpos(pInFile, positions + str_count - i - 1);      // Set the file position
    fread(&str_length, sizeof(size_t), 1, pInFile);       // Read the string length
    fwrite(&str_length, sizeof(size_t), 1, pOutFile);     // Write to new file
    fread(buffer, str_length, 1, pInFile);                // Read the string
    fwrite(buffer, str_length, 1, pOutFile);              // Write to new file
  }

  fclose(pInFile);                                        // Close input file
  fclose(pOutFile);                                       // Close output file
  printf_s("\nNew file write complete.\n");
}

void list_strings(char *file_name)
{
  FILE *pFile = NULL;
  size_t str_length = 0;
  if(fopen_s(&pFile, file_name, "r"))                     // Open the new file to read it
  {
    printf_s("Error opening %s for reading. Program terminated.\n", file_name);
    exit(1);
  }
  setvbuf(pFile, NULL, _IOFBF, 512); 

  printf_s("\nThe strings in the new file are:\n");
  while(true)
  {
    fread(&str_length, sizeof(size_t), 1, pFile);
    if(feof(pFile))                                       // If it is end of file
      break;                                              // We are finished
    fread(buffer, str_length, 1, pFile);
    buffer[str_length] = '\0';
    printf_s("\n%s", buffer);
  }
  printf_s("\n");
  fclose(pFile);                                          // Close file
}

/**********************************************************************************/
// Exercise 12.2 Reading strings from a file in reverse order.
#define __STDC_WANT_LIB_EXT1__ 1

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

#define BUFFER_SIZE 50

// Function prototypes
size_t get_count(char *file_name);
fpos_t* get_string_positions(char *file_name, size_t str_count);
void copy_file_reversed( char *in_name, char *out_name, fpos_t *positions, size_t str_count);
void list_strings(char *file_name);

// Global variables
char *buffer = NULL;                               // Input/Output buffer for strings
size_t buffer_size = 0;                            // I/O buffer size

int main(void)
{
  char *infilename = "myfile.bin";                 // Name of the file to be read 
  char *outfilename = "outfile.bin";               // Name of the file to be written

  buffer_size = BUFFER_SIZE;                       // Initial buffer size
  buffer = (char*)malloc(buffer_size);             // Create initial buffer
  size_t str_count = get_count(infilename);
  fpos_t *positions = get_string_positions(infilename, str_count);
  copy_file_reversed(infilename, outfilename, positions, str_count);
  list_strings(outfilename);

  // Free the memory we allocated
  free(buffer);
  free(positions);
  return 0;
 }

// Function to get the number of strings in the file 
// and set the buffer size to accommodate the maximum string length
size_t get_count(char *file_name)
{
  FILE *pFile = NULL;                                     // File pointer to input file
  size_t str_length = 0;                                  // Length of a string
  size_t str_count = 0;                                   // Number of strings
  if(fopen_s(&pFile, file_name, "rb"))                    // Open the input file
  {
    printf_s("Error opening %s for reading. Program terminated.", file_name);
    exit(1);
  }
  setvbuf(pFile, NULL, _IOFBF, 512); 

  for(;;)
  {
    fread(&str_length, sizeof(size_t), 1, pFile);         // Read the string length
    if(feof(pFile))                                       // If it is end of file
      break;                                              // We are finished

    // Check buffer is large enough and increase if necessary
    if(str_length >= buffer_size)
    {
      buffer_size = str_length  + 1;
      if(!(buffer = (char*)realloc(buffer, buffer_size)))
      {
        printf_s("Buffer allocation failed.\n");
        exit(1);
      }
    }
    fread(buffer, str_length, 1, pFile);                  // Read the string
    ++str_count;
  }
  fclose(pFile);
  printf_s("\nThere are %zd strings in the input file.", str_count);
  return str_count;
}

// Function to get the position for the beginning of each record in the file
fpos_t* get_string_positions(char *file_name, size_t str_count)
{
  FILE *pFile = NULL;                                     // File pointer to input file
  if(fopen_s(&pFile, file_name, "rb"))                    // Open the input file
  {
    printf_s("Error opening %s for reading. Program terminated.", file_name);
    exit(1);
  }
  setvbuf(pFile, NULL, _IOFBF, 512); 

  fpos_t *positions = (fpos_t*)malloc(str_count*sizeof(fpos_t));  // Array to store the positions
  size_t str_length = 0;                                  // Length of a string
  for(int i = 0 ; i < str_count ; ++i)
  {
    fgetpos(pFile, positions + i);                        // Get the positions
    fread(&str_length, sizeof(size_t), 1, pFile);         // Read the string length
    fread(buffer, str_length, 1, pFile);                  // Read the string
  }
  fclose(pFile);
  return positions;
}

// Copy strings from input file to new file in reverse order
void copy_file_reversed( char *in_name, char *out_name, fpos_t *positions, size_t str_count)
{
  FILE *pInFile = NULL;                                   // File pointer to input file
  FILE *pOutFile = NULL;                                  // File pointer  to output file

  // Open input file for binary read
  if(fopen_s(&pInFile, in_name, "rb"))                    // Open the input file
  {
    printf_s("Error opening %s for reading. Program terminated.", in_name);
    exit(1);
  }
  setvbuf(pInFile, NULL, _IOFBF, 512); 

  // Open output file for binary write
  if(fopen_s(&pOutFile, out_name, "wb"))
  {
    printf_s("Error opening %s for writing. Program terminated.", out_name);
    exit(1);
  }
  setvbuf(pOutFile, NULL, _IOFBF, 512); 

  // Read the records in reverse order from the input file and write to the new file
  size_t str_length = 0;
  for(int i = 0 ; i < str_count ; ++i)
  {
    fsetpos(pInFile, positions + str_count - i - 1);      // Set the file position
    fread(&str_length, sizeof(size_t), 1, pInFile);       // Read the string length
    fwrite(&str_length, sizeof(size_t), 1, pOutFile);     // Write to new file
    fread(buffer, str_length, 1, pInFile);                // Read the string
    fwrite(buffer, str_length, 1, pOutFile);              // Write to new file
  }

  fclose(pInFile);                                        // Close input file
  fclose(pOutFile);                                       // Close output file
  printf_s("\nNew file write complete.\n");
}

void list_strings(char *file_name)
{
  FILE *pFile = NULL;
  size_t str_length = 0;
  if(fopen_s(&pFile, file_name, "r"))                     // Open the new file to read it
  {
    printf_s("Error opening %s for reading. Program terminated.\n", file_name);
    exit(1);
  }
  setvbuf(pFile, NULL, _IOFBF, 512); 

  printf_s("\nThe strings in the new file are:\n");
  while(true)
  {
    fread(&str_length, sizeof(size_t), 1, pFile);
    if(feof(pFile))                                       // If it is end of file
      break;                                              // We are finished
    fread(buffer, str_length, 1, pFile);
    buffer[str_length] = '\0';
    printf_s("\n%s", buffer);
  }
  printf_s("\n");
  fclose(pFile);                                          // Close file
}

/**********************************************************************************/
// Exercise 12.4 Writing names and phone numbers to a file. */
/*
  This solution uses a PhoneRecord structure with the name and number stored in
  arrays with a fixed size. This allows the file operations to be very simple.
  You can just read or write a PhoneRecord structure since its size is fixed.

  If you wanted to allocate space for the name and number dynamically, then
  you would have to explicitly write the name and number strings as well as the
  PhoneRecord structure to the file. You would also need to include the length of each
  data item in the file so you knew how much to read back.
*/

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>

#define FIRST_NAME_LENGTH  31
#define SECOND_NAME_LENGTH 51
#define NUMBER_LENGTH      21


// Structure defining a name
typedef struct NName
{
  char firstname[FIRST_NAME_LENGTH];
  char secondname[SECOND_NAME_LENGTH];
} Name;

// Structure defining a phone record
typedef struct PPhoneRecord
{
  Name name;
  char number[NUMBER_LENGTH];
} PhoneRecord;


// Function prototypes */
PhoneRecord read_phonerecord(void);                   // Read a name and number from the keyboard
Name read_name(void);                                 // Read a name from the keyboard
void list_records(char *filename);                    // List all the records in the file
void show_record(const PhoneRecord *precord);         // Output name and number from a phone record
void find_numbers(Name *pname, char *filename);       // Find numbers corresponding to a given name
void add_record(char *filename);                      // Add a new name and number to the file
void delete_records(Name *pname, char *filename);     // Delete records for a given name
void show_operations(void);                           // Displays operations supported by the program
int equals(Name *name1, Name *name2);                 // Compare two names for equality


int main(void)
{
  char *filename = "C:\\records.bin";                 // Name of the file holding the records
  char answer = 'n';                                  // Stores input responses
  show_operations();                                  // Display the available operations

  while(true)
  {
    printf_s("\nEnter a letter to select an operation: ");
    scanf_s(" %c", &answer, sizeof(answer));
    Name name;
    switch(toupper(answer))
    {
      case 'A':                                       // Add a new name and number record
        add_record(filename);
        break;
      case 'D':                                       // Delete records for a given name
        name = read_name();
        delete_records(&name, filename);
        break;
      case 'F':                                       // Find the numbers for a given name
         name = read_name();
       find_numbers(&name, filename);
        break;
      case 'L':                                       // List all the name/number records
        list_records(filename);
        break;
      case 'Q':                                       // Quit the program
        return 0;
      default:
        printf_s("Invalid selection try again.\n");
        show_operations();
        break;
    }
  }
 }

// Reads a name and number from the keyboard and creates a PhoneRecord structure
PhoneRecord read_phonerecord(void)
{
  PhoneRecord record;
  record.name = read_name();
  printf_s("Enter the number: ");
  scanf_s(" %[ 0123456789]",record.number, sizeof(record.number));  // Read the number - including spaces
  return record;
}

// Outputs the name and number from a phone record
void show_record(const PhoneRecord *precord)
{
  printf_s("\n%s %s   %s", precord->name.firstname, precord->name.secondname, precord->number);
}

// Add a new name and number
void add_record(char *filename)
{
  FILE *pFile = NULL;
  PhoneRecord record;

  if(fopen_s(&pFile, filename, "a+"))          // Open/create file to be written in append mode
  {
    printf_s("Error opening %s for writing. Program terminated.\n", filename);
    exit(1);
  }
  record = read_phonerecord();                 // Read the name and number
  fwrite(&record, sizeof record, 1, pFile);
  fclose(pFile);                               // Close file
  printf_s("New record added.\n");
}

// Read a name from the keyboard and create a Name structure for it
Name read_name(void)
{
  Name name;
  printf_s("Enter a first name: ");
  scanf_s(" %s", name.firstname, sizeof(name.firstname));
  printf_s("Enter a second name: ");
  scanf_s(" %s", name.secondname, sizeof(name.secondname));
  return name;
}

// Delete records for a given name
/* To delete one or more records we can copy
   the contents of the existing file to a new
   file, omitting the records that are to be
   deleted. We can then delete the old file and
   rename the new file to have the old file
   name.
*/
void delete_records(Name *pname, char *filename)
{
  FILE *pFile = NULL;
  FILE *pNewFile = NULL;
  char *pnewfilename = NULL;
  char answer = 'n';
  PhoneRecord record;

  if(fopen_s(&pFile, filename, "r"))                   // Open current file to read it
  {
    printf_s("Error opening %s for reading. Program terminated.\n", filename);
    exit(1);
  }

  pnewfilename = tmpnam(NULL);                       // Create temporary file name
  if(fopen_s(&pNewFile, pnewfilename, "w"))          // Open temporary file to write it
  {
    printf_s("Error opening %s for writing. Program terminated.\n", pnewfilename);
    fclose(pFile);
    exit(1);
  }

  // Copy existing file contents to temporary file, omitting deleted records
  while(true)
  {
    fread(&record, sizeof record, 1, pFile);         // Read a record
    if(feof(pFile))                                  // if it's end of file...
      break;                                         // ...quit copy loop

    if(equals(pname, &(record.name)))                // Is the record this name?
    {
      printf_s("Found a record:\n");                 // Ys, so it's a delete candidate
      show_record(&record);
      printf_s("\nDo you really want to delete it (y or n)? ");
      scanf_s(" %c", &answer, sizeof(answer));
      if(tolower(answer) == 'y')                     // If it's to be deleted
        continue;                                    // Skip the copying
    }
    fwrite(&record, sizeof record, 1, pNewFile);     // copy current record
  }
  fclose(pFile);
  fclose(pNewFile);

  if(fopen_s(&pNewFile, pnewfilename, "r"))          // Open temporary file to read it
  {
    printf_s("Error opening %s for reading. Program terminated.", pnewfilename);
    exit(1);
  }
  if(fopen_s(&pFile, filename, "w"))                 // Open original file to write it
  {
    printf_s("Error opening %s for writing. Program terminated.\n", filename);
    exit(1);
  }

  // Copy contents of new temporary file back to old file
  // This overwrites the original contents because the mode is "w"
  while(true)
  {
    fread(&record, sizeof record, 1, pNewFile);      // Read temporary file
    if(feof(pNewFile))                               // If we read EOF
      break;                                         // We are done

    fwrite(&record, sizeof record, 1, pFile);       // Write record to original file
  }
  fclose(pFile);                                     // Close the original file
  fclose(pNewFile);                                  // Close the temporary file 
  remove(pnewfilename);                              // Delete the temporary file
  printf_s("Delete complete.");
}

// List all the records in the file
void list_records(char *filename)
{
  FILE *pFile;
  PhoneRecord record;
  bool file_empty = true;                            // File empty flag

  if(fopen_s(&pFile, filename, "r"))                 // Open the file to read it
  {
    printf_s("Error opening %s for reading. Program terminated.", filename);
    exit(1);
  }
  setvbuf(pFile, NULL, _IOFBF, 512); 

  // List the file contents
  while(true)
  {
    fread(&record, sizeof record, 1, pFile);
    if(feof(pFile))
      break;
    file_empty = false;                              // We got a record so set empty flag false
    show_record(&record);                            // output the record
  }
  fclose(pFile);                                     // Close the file

  // Check whether there were any records
  if(file_empty)
    printf_s("The file contains no records.\n");
  else
    printf_s("\n");
}

// Displays the operations that are supported by the program
void show_operations(void)
{
  printf_s("The operations available are:\n"
    "A: Add a new name and number entry.\n"
    "D: Delete all existing entries for a name.\n"
    "F: Find the number(s) for a given name.\n"
    "L: List all the entries in the file.\n"
    "Q: Quit the program.\n");
}

// Find numbers corresponding to a given name
void find_numbers(Name *pname, char *filename)
{
  FILE *pFile = NULL;
  PhoneRecord record;
  bool name_found = false;                           // Name found flag

  if(fopen_s(&pFile, filename, "r"))                 // Open the file to read it
  {
    printf_s("Error opening %s for reading. Program terminated.", filename);
    exit(1);
  }

  // Search the records read from the file
  while(true)
  {
    fread(&record, sizeof record, 1, pFile);         // Read a record
    if(feof(pFile))
      break;
   if(equals(pname,&(record.name)))                  // Is it the name requested?
   {
     if(!name_found)                                 // Is this the first time we found it?
     {
       name_found = true;                            // Yes so set flag to true
       printf_s("The numbers for this name are:");   // Output initial message
     }
     printf_s("\n%s",record.number);                 // Output the number
   }
  }
  fclose(pFile);                                     // Close the file

  // Check for name not found
  if(!name_found)
    printf_s("The name was not found.\n");
  else
    printf_s("\n");
}

// Compare two names for equality
int equals(Name *pname1, Name *pname2)
{
  return (strcmp(pname1->firstname, pname2->firstname) == 0) && (strcmp(pname1->secondname, pname2->secondname) == 0);
}

/**********************************************************************************/
// Exercise 13.1 Defining a COMPARE(x,y) macro
/*
  One advantage of the COMPARE macro is that is works with numeric values of any type.
  Another advantage is that there is no function call overhead.
*/
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>

#define COMPARE(x,y) (((x)<(y)) ? -1 : (((x)==(y)) ? 0 : 1))

int main(void)
{
  int a = 5, b = 5, c = 10;
  printf_s("COMPARE(%d, %d) = %d\n", a, b, COMPARE(a,b));
  printf_s("COMPARE(%d, %d) = %d\n", a, c, COMPARE(a,c));
  printf_s("COMPARE(%d, %d) = %d\n", c, b, COMPARE(c,b));
  printf_s("COMPARE(%d, %d) = %d\n", a+b, c-b, COMPARE(a+b,c-b));

  double x = 24.5, y = 28.0, z = 3.5;
  printf_s("COMPARE(%.2f, %.2f) = %d\n", x, y, COMPARE(x,y));
  printf_s("COMPARE(%.2f, %.2f) = %d\n", y, z, COMPARE(y,z));
  printf_s("COMPARE(%.2f, %.2f) = %d\n", x+z, y, COMPARE(x+z,y));
  return 0;
}

/**********************************************************************************/
// Exercise 13.2 A function to produce a string containing the current time
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>

/******************************************
 * Function that returns time as a string *
 * arg = 0 result is in 12 hour format    *
 * arg = 1 result is in 24 hour format    *
 ******************************************/
char *time_str(int arg)
{
  bool afternoon = true;
  time_t now = time(NULL);
  struct tm *ptime = localtime(&now);

  if(!arg)
  {
    afternoon = ptime->tm_hour > 12;
    ptime->tm_hour %= 12;
  }

  static char result[12];
  sprintf_s(result, sizeof(result), "%2d:%02d:%02d", ptime->tm_hour, ptime->tm_min, ptime->tm_sec);
  if(!arg)
  {
    strcat_s(result, sizeof(result), afternoon ? " pm" : " am");
  }
  return result;
}

int main(void)
{
  printf_s("Time is %s\n", time_str(0));
  printf_s("Time is %s\n", time_str(1));
  return 0;
}
/**********************************************************************************/
// Exercise 13.3 A macro to ouput the value of an expression
#include <stdio.h>
/*
 The macro always produces a floating-point result of evaluating the expression.
 I arbitrarily made it prodeuce output with 3 decimal places.
 If you were to define the macro to produce an integer result, then it would only
 work with expressions involving integers.
*/
#define print_value(expr) printf(#expr " = %.3lf\n", ((double)(expr)))


int main(void)
{
  int x = 4;
  double y = 3.5;
  print_value(x);
  print_value(y);
  print_value(x*x*x - 5);
  print_value(x*y + 10);
  print_value(x*y + 10*y/x);
  print_value(x*x + x*y + y*y);
  return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值