The following are sample solutions to problems 8, 9, and 10 of the diagnostic test.
/* Notes: as we will be doing in the class, diagnostic.c should be
compiled with
* "gcc -std=c99 -m64 -Wall -Wextra -Wshadow -Werror -pedantic"
* (in particular: we are coding by the C99 standard)
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
/************ PROBLEM 8 ************/
bool is_prime( int n ) {
if( n <= 2 || n % 2 == 0 ) {
return ( n == 2 );
}
for( int i = 3; i * i <= n; i += 2 ) {
if( n % i == 0 ) {
return false;
}
}
return true;
}
/************ PROBLEM 9 ************/
void swap( int *a, int *b ) {
int t = *a;
*a = *b;
*b = t;
}
void permute( int *digits, int n, int p ) {
if( p == n ) {
for( int i = 0; i < n; ++i ) {
printf( "%d ", digits[i] );
}
printf( "\n" );
} else {
for( int i = p; i < n; ++i ) {
swap( &digits[p], &digits[i] );
permute( digits, n, p + 1 );
swap( &digits[p], &digits[i] );
}
}
}
void print_permutations( int n ) {
int *digits = malloc( n * sizeof( int ) );
for( int i = 0; i < n; ++i ) {
digits[i] = i + 1;
}
permute( digits, n, 0 );
free( digits );
}
/************ PROBLEM 10 ************/
size_t search( int *data, size_t N, int value ) {
for( size_t i = 0; i < N; ++i ) {
if( data[i] == value ) {
return i;
}
}
return N;
}
size_t binary_search( int *data, size_t N, int value ) {
size_t lo = 0, hi = N - 1;
while( lo < hi ) {
size_t mid = lo + ( hi - lo ) / 2;
if( data[mid] < value ) {
lo = mid + 1;
} else {
hi = mid;
}
}
return ( hi == lo && data[lo] == value ) ? lo : N;
}
/************ TESTING ************/
void test_is_prime(void) {
int N_prime = 10, N_composite = 20;
int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
int composite[] = { 1, 4, 6, 8, 9, 10, 12, 14, 15, 16,
18, 20, 21, 22, 24, 25, 26, 27, 28 };
for( int i = 0; i < N_prime; ++i ) {
assert( is_prime( prime[i] ) );
}
for( int i = 0; i < N_composite; ++i ) {
assert( !is_prime( composite[i] ) );
}
}
void test_print_permutations(void) {
print_permutations( 3 );
}
void test_search(void) {
size_t N = 7;
int data[] = { 1, 2, 3, 5, 9, 11, 101 };
assert( search( data, N, 0 ) == 7 );
assert( search( data, N, 10 ) == 7 );
assert( search( data, N, 11 ) == 5 );
assert( search( data, N, 102 ) == 7 );
assert( binary_search( data, N, 0 ) == 7 );
assert( binary_search( data, N, 10 ) == 7 );
assert( binary_search( data, N, 11 ) == 5 );
assert( binary_search( data, N, 102 ) == 7 );
}
void run_all_tests(void) {
test_is_prime();
test_print_permutations();
test_search();
}
int main(void) {
run_all_tests();
return 0;
}
Practices Illustrated
- Functions with no parameters are declared with parameter void.
- We use
size_t
for all array index types that could potentially be large. - Judicious horizontal spacing and minimal (but readable) vertical spacing.
- Curly braces used always (even when optional).
- Use of the
bool
type from C99’s stdbool.h. - Variable names are descriptive, but not more verbose than necessary.
- Each solution to a problem has a piece of code to test it.