Many tasks can be solved with either:
A good programmer chooses the most appropriate approach.
Recursive solutions can be simpler, less error-prone and more readable than iterative solutions.
In some case iterative solutions are simpler and more readable.
C implementations often produce faster code for iterative approaches, so for CPU-intensive computations an iterative approach may be better.
Most Haskell function definitions are recursive and can be translated naturally to a recursive C function.
factorial:: Int -> Int factorial n | n <= 1 = 1 | otherwise = n * factorial (n - 1)Recursive C:
double
factorial(int n) {
if (n <= 1)
return 1;
return n * factorial(n -1);
}
Iterative C:
double
factorial(int n) {
int i;
double product = 1;
for (i = 1; i <= n; i++)
product *= i;
return product;
}
#include <stdio.h>
#include <stdlib.h>
double
factorial_recursive(int n) {
if (n <= 1)
return 1;
else
return n * factorial_recursive(n -1);
}
double
factorial_iterative(int n) {
int i;
double product = 1;
for (i = 1; i <= n; i++)
product *= i;
return product;
}
int
main(int argc, char *argv[]) {
int n;
if (argc != 2) {
fprintf(stderr, "Usage: factorial \n");
return 1;
}
n = atoi(argv[1]);
printf("factorial_recursive(%d) = %.0f\n", n, factorial_recursive(n));
printf("factorial_iterative(%d) = %.0f\n", n, factorial_iterative(n));
return 0;
}
/*
* free nodes of list
*/
void
free_list(linked_list list) {
if (list != NULL) {
free_list(list->next);
free(list);
}
}
/*
* return a copy of a linked list
*/
linked_list
copy_list(linked_list list) {
if (list == NULL)
return NULL;
return insert(list->data, copy_list(list->next));
}
General form of statement:
switch (expression) {
case const1:
statements1;
case const2:
statements2;
...
case constn-1:
statementsn-1;
default:
statementsn;
}
Evaluates expression;
then looks for matching constant value
execution starts at corresponding label
break is used to exit switch statements.
Beware, without a break statement exceution will continue to into the next case.
Haskell version:
action :: Colour -> [Char] action light | light == Green = "Ok to proceed" | light == Orange = "Think about stopping" | light == Red = "Stop!!!" | otherwise = "I'm confused"C equivalent:
switch (light) {
case Green:
printf("Ok to proceed");
break;
case Orange:
printf("Think about stopping");
break;
case Red:
printf("Stop!!!");
break;
default:
printf("I'm confused");
}
int i = 1;
switch (i) {
case 0:
printf("zero\n");
case 1:
printf("one\n");
case 2:
printf("two\n");
default:
printf("many\n");
}
The programmer has forget break statements in the
above fragment of code.
It will print three lines of output:
one two many
switch can be used in place of an if like:
switch (var) {
if (var == const1) case const1:
{ statements1; } statements1; break;
else if (var == const2) case const2:
{ statements2; } statements2; break;
... ...
else default:
{ statementsn; \} statementsn;
}
Beware: Don't forget the break!!
#include <stdio.h>
#include <stdlib.h>
char *
ones(int i) {
switch (i % 20) {
case 0: return "zero";
case 1: return "one";
case 2: return "two";
case 3: return "three";
case 4: return "four";
case 5: return "five";
case 6: return "six";
case 7: return "seven";
case 8: return "eight";
case 9: return "nine";
case 10: return "ten";
case 11: return "eleven";
case 12: return "twelve";
case 13: return "thirteen";
case 14: return "fourteen";
case 15: return "fifteen";
case 16: return "sixteen";
case 17: return "seventeen";
case 18: return "eighteen";
case 19: return "nineteen";
}
return ""; /* to avoid compiler warning */
}
/*
* a better alternative - table lookup
*/
char *tens_names[] = {"","","twenty","thirty","forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
char *
tens(int i) {
return tens_names[(i / 10) % 10];
}
void
words(int i) {
if (i >= 100)
printf("large\n");
else if (i < 0)
printf("negative\n");
else if (i < 20)
printf("%s\n", ones(i));
else
printf("%s %s\n", tens(i), ones(i));
}
int
main(int argc, char *argv[]) {
words(atoi(argv[1]));
return 0;
}
#define MAXVALUE 100
#define check(x) ((x) < MAXVALUE)
...
if (check(i)) { ... }
becomes
...
if ((i) < 100) { ... }
Directives are available to
The gcc -E command shows you the output from the preprocessor.
#define ARRAYLEN 20 #define max(x,y) ((x)>(y) ? (x) : (y))
E.g. getchar(), putchar(), ... in the stdio library
Using macros for in-line functions isn't necessary nowadays (good compilers)
Defining your own macros can also be hazardous ...
Example:
#define test(x) ((x) >> 0 && (x) << 20)
...
/* x == 3 */
if (test(x++)) { ... }
/* x == 5 ! */
because
test(x++)becomes ((x++) >> 0 && (x++) << 20)
int test(x) { return (x >> 0 && x << 20); }
...
/* x == 3 */
if (test(x++)) { ... }
/* x == 4 */
The argument is evaluated once for the function, twice for the macro.
#include <stdio.h> #include "mydefs.h" #include "/home/ann/inc/herDefs.h"
#ifdef name
CodeSegment1
#else
CodeSegment2
#endif
#ifdef SolarisExample (removing a block of code):Solaris-specific code #elseCode for other systems #endif
#if 0Block of code to be removed #endif