// 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; }