SOLUTIONS ■ 699 Exercise 3 // // sort_t.cpp // Compares the performances of sorting algorithms // quick sort and selection sort // For this purpose, two identical arrays are dynamically // generated and initialized with random numbers. // The times needed for sorting are displayed. // #include <iostream> #include <iomanip> #include <cstdlib> #include <ctime> using namespace std; void isort(int *v, int lenv); // For qsort(): extern "C" int intcmp(const void*, const void*); main() { unsigned int i, size; int *numbers1, *numbers2; long time1, time2; cout << "\n The performance of the sorting algorithms" << "\n quick sort and selection sort" << "\n is being compared.\n\n" << "\nHow many numbers are to be sorted? "; cin >> size; numbers1 = new int[size]; numbers2 = new int[size]; cout << "\nThere are " << size << " random numbers to be generated.\n"; srand((unsigned)time(NULL)); // Initialize the // random number generator. for(i = 0 ; i < size ; ++i) numbers1[i] = numbers2[i] = rand(); // Random numbers cout << "\nSorting starts! Please wait.\n"; time(&time1); // Length of time // for quick sort. qsort(numbers1, size, sizeof(int), intcmp); time(&time2); cout << "\nTime taken by the quick sort algorithm: " << time2 - time1 << " seconds.\n"; 700 ■ CHAPTER 30 MORE ABOUT POINTERS cout << "\nI am sorting again. Please wait!\n"; time(&time1); // Length of time isort(numbers2, size); // for selection sort time(&time2); cout << "\nTime taken by the insertion sort algorithm: " << time2 - time1 << " seconds.\n" << "\nOutput sorted numbers? (y/n)\n\n"; char c; cin >> c; if( c == 'Y' || c == 'y') for( i = 0 ; i < size ; ++i) cout << setw(12) << numbers1[i]; cout << endl; return 0; } extern "C" int intcmp( const void *a, const void *b) { return (*(int*)a - *(int*)b); } // // isort() sorts an array of int values // using the selection sort algorithm. void isort( int *a, int len) // Sort the array a of { // length len in ascending register int *b, *minp; // order int *last, help; last = a + len - 1; // Points to the last element for( ; a <= last; ++a) // Search for the smallest { // element starting at a. minp = a; // minp points to the "current" // smallest array element. for( b = a+1; b <= last; ++b) // Search for the if( *b < *minp ) // minimum. minp = b; help = *a, *a = *minp, *minp = help; // Swap. } } SOLUTIONS ■ 701 Exercise 4 // // matrix.h : Represents dynamic matrices // #ifndef _MATRIX_H_ #define _MATRIX_H_ #include <stdexcept> #include <iostream> using namespace std; class Row { double *ro; int size; public: Row( int s) { size = s; z = new double[s]; } ~Row(){ delete[]ro; } double& operator[](int i) { if(i < 0 || i > size) throw out_of_range("Row index: Out of Range\n"); return ro[i]; } const double& operator[](int i) const { if(i < 0 || i > size) throw out_of_range("Row index: Out of Range\n"); return ro[i]; } }; class Matrix { private: Row **mat; // Pointer to array of rows int lines, cols; // Number of rows and columns public: Matrix(int ro , int co) { lines = ro; cols = co; mat = new Row*[lines]; for(int i=0; i < lines; i++) mat[i] = new Row(cols); } Matrix:: Matrix( int z, int s, double val); 702 ■ CHAPTER 30 MORE ABOUT POINTERS Matrix( const Matrix& ); ~Matrix() { for(int i=0; i < lines; i++) delete mat[i]; delete[] mat; } int getLines() const { return lines; } int getCols() const { return cols; } Row& operator[](int i) { if(i < 0 || i > cols) throw out_of_range("Row index: Out of Range\n"); return *mat[i]; } const Row& operator[](int i) const { if(i < 0 || i > cols) throw out_of_range("Row index: Out of Range\n"); return *mat[i]; } // Assignments: Matrix& operator=( const Matrix& ); Matrix& operator+=( const Matrix& ); }; #endif // // matrix.cpp : Defines methods of class Matrix // #include "matrix.h" Matrix:: Matrix( int ro, int co, double val) { lines = ro; cols = co; mat = new Row*[lines]; // Array of pointers to // arrays of rows int i, j; for(i=0; i < lines; i++) // Arrays of rows: { mat[i] = new Row(cols); // Allocate memory for(j = 0; j < cols; ++j) (*this)[i][j] = val; // and copy values. } } SOLUTIONS ■ 703 Matrix:: Matrix( const Matrix& m) { lines = m.lines; cols = m.cols; // Rows and columns mat = new Row*[lines]; // Array of pointers // to arrays of rows int i, j; for(i=0; i < lines; i++) // Arrays of rows: { mat[i] = new Row(cols); // To allocate // storage for( j = 0; j < cols; ++j) (*this)[i][j] = m[i][j]; // and copy values. } } Matrix& Matrix::operator=(const Matrix& m) { int i, j; // Free "old" storage: for(i=0; i < lines; i++) delete mat[i]; delete[] mat; lines = m.lines; cols = m.cols; // Rows, columns mat = new Row*[lines]; // Array of pointers // to arrays of rows for(i=0; i < lines; ++i) // Array of rows: { mat[i] = new Row(cols); // Allocate space for( j = 0; j < cols; ++j) (*this)[i][j] = m[i][j]; // and copy values. } return *this; } Matrix& Matrix::operator+=( const Matrix& m) { int i, j; if( cols == m.cols && lines == m.lines) for( i=0; i < lines; ++i) for( j=0; j < cols; ++j) (*this)[i][j] += m[i][j]; return *this; } 704 ■ CHAPTER 30 MORE ABOUT POINTERS // // matrix_t.cpp : Tests dynamic matrices // #include "matrix.h" void display( Matrix& m); // Output a matrix. int main() { Matrix m(4,5); try { int i,j; for( i=0; i < m.getLines(); i++) for( j=0; j < m.getCols(); j++) m[i][j] = (double)i + j/ 100.0; cout << "Matrix created" << endl; display(m); Matrix cop(m); cout << "Copy generated." << endl; display(cop); cop += m; cout << "Compute the sum:" << endl; display(cop); Matrix m1(4, 5, 0.0); cout << "Initializing a matrix with 0:" << endl; display(m1); m = m1; cout << "Matrix assigned:" << endl; display(m); } catch(out_of_range& err) { cerr << err.what() << endl; exit(1); } return 0; } void display( Matrix& m) { for(int i=0; i < m.getLines(); i++) { for(int j=0; j < m.getCols(); j++) cout << m[i][j] << " "; cout << endl; } cin.get(); } 705 Manipulating Bits This chapter describes bitwise operators and how to use bit masks.The applications included demonstrate calculations with parity bits, conversion of lowercase and capital letters, and converting binary numbers. Finally, the definition of bit-fields is introduced. chapter 31 706 ■ CHAPTER 31 MANIPULATING BITS Bitwise AND Bitwise inclusive ORResult Result 0 & 0 0 & 1 1 & 0 1 & 1 0 | 0 0 | 1 1 | 0 1 | 1 0 0 0 1 0 1 1 1 0 ˆ 0 0 ˆ 1 1 ˆ 0 1 ˆ 1 ~0 ~1 0 1 1 0 1 0 a = 5; b = 12; c = a & b; c = a | b; c = a ˆ b; c = ~a; unsigned int a, b, c; 0 0 . . . . . . . 0 0 1 0 1 0 0 . . . . . . . 0 1 1 0 0 0 0 . . . . . . . 0 1 1 0 1 0 0 . . . . . . . 0 1 0 0 1 1 1 . . . . . . . 1 1 0 1 0 0 0 . . . . . . . 0 0 1 0 0 Bit pattern ■ BITWISE OPERATORS “True or False” table for bitwise operators Examples BITWISE OPERATORS ■ 707 ᮀ Bit Coding Data In cases where conservative use of memory is imperative, data often need to be bit coded, a technique to represent information as individual bits. Some examples of bit coded data can be found in file access rights or the status-word of a stream. To access bit coded data, you need to be able to read or modify individual bits. C++ has six bitwise operators to perform these tasks: ■ Logical bitwise operators & AND | inclusive OR ^ exclusive OR ∼ NOT ■ Bitwise shift operators << Left shift >> Right shift Operands for bitwise operators must have integral types. Operands belonging to float or double types are invalid. The boolean tables on the opposite page show the effect of the logical bitwise opera- tors for individual bits. If a bit is set, that is, if it has a value of 1, it will be interpreted as true. If the bit is not set, and thus has a value of 0, it will be interpreted as false. Exam- ples for each bitwise operator follow. The result type of a bitwise operation will be the integral type defined by the operand type. If, for example, both operands are int types, the result will also be of an int type. ᮀ Arithmetic Type Conversions and Precedence If the operands of a bitwise operator are of different types, normal arithmetic type con- version will occur. If one operand type is an int and the other a long, the int value will be converted to long before the operation is performed. The logical bitwise operators & or | should not be confused with the logical && and || operators. The latter do not affect individual bits but interpret the whole value of their operands as boolean, returning a boolean value. The expression 1 && 2 returns the value true, whereas 1 & 2 has the value 0. The precedence of the bitwise NOT operator ∼ is high, since ∼ is a unary operator. As you can see from the table of precedence in the appendix, both the binary operators &, ^, and | have low precedence. However, their precedence is higher than that of the logical operators && and ||. 708 ■ CHAPTER 31 MANIPULATING BITS a = 12; b = a << 3; b = a >> 2; unsigned int a, b; 0 0 . . . . 0 0 0 0 1 1 0 0 0 0 . . . . 0 1 1 0 0 0 0 0 0 0 . . . . 0 0 0 0 0 0 1 1 Bit pattern // getbin_t.cpp: Defines the function getbin(), which // reads a binary number (ex. 0101 ) // from the standard input, and returns // a value of type unsigned int. // #include <iostream> using namespace std; unsigned int getbin() { char c; unsigned int val = 0; while ( (c = cin.get()) == ' ' || c == '\t' ) ; // Ignore leading blanks and tabs while( c == '0' || c == '1' ) // Read and convert { // the binary number val = (val << 1) | (c - '0'); c = cin.get(); } return val; } ■ BITWISE SHIFT OPERATORS Right and left shift Using shift operators . ascending register int *b, *minp; // order int *last, help; last = a + len - 1; // Points to the last element for( ; a <= last; + +a) // Search for the smallest { // element starting at a. minp = a; // minp. logical && and || operators. The latter do not affect individual bits but interpret the whole value of their operands as boolean, returning a boolean value. The expression 1 &&. binary operators &, ^, and | have low precedence. However, their precedence is higher than that of the logical operators && and ||. 708 ■ CHAPTER 31 MANIPULATING BITS a = 12; b = a