// 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;
}
《C语言入门经典》Ivor Horton
最新推荐文章于 2022-01-07 22:54:26 发布