More Arrays

Searching Arrays

Suppose we want to know whether a particular value is an element of an array and, if so, the index where the value occurs. A first approach would be to look at each element of the array comparing it to the value in question. This is an approach called linear search.

For example, we may have a list of student ID numbers in an array and want to find the index of a particular student's number. We could write a function find_number to return the index of the number, or -1 if the number can't be found:

#include <stdio.h>
#include <stdlib.h>

int find_id (int v[], int id, int n) {
	int	i;

	for (i=0; i<n; i++) if (v[i] == id) return i;
	return -1;
}

int main () {
	int	ids[100], n, id, index;

	printf ("Enter some IDs, or -1 when done\n");
	n = 0;
	for (;;) {
		scanf ("%i", &ids[n]);
		if (ids[n] == -1) break;
		n++;
	}
	printf ("Enter the ID of a student:");
	scanf ("%i", &id);
	index = find_id (ids, id, n);
	if (index != -1) 
		printf ("Student with ID %i is in index %i\n", id, index);
	else
		printf ("No such student!\n");
	exit (0);
}
This is a somewhat contrived example; if someone just finished entering student IDs, they would know whether a student was in the list. However, it illustrates an important concept: searching in an array. We can extend this to more useful examples.

Consider an inventory system for a small store. It keeps track of products by their product ID numbers and how many of each product is available. The program is menu-driven; it will ask the user to enter a command to add or subtract a quantity of a product. If an unknown product ID is entered, the program considers it a new product and makes a new slot for it.

#include <stdio.h>
#include <stdlib.h>

/* we'll have up to 100 products */

#define MAX_PRODUCTS	100

/* this function returns the array index where 'id' is found in 'v',
 * up to the 'n'th element, or -1 if it isn't found
 */
int find_product (int v[], int id, int n) {
	int	i;

	for (i=0; i<n; i++) if (v[i] == id) return i;
	return -1;
}

int main () {
	int	product_ids[MAX_PRODUCTS], /* the product ID numbers */
		quantities[MAX_PRODUCTS],  /* the quantities for each product */
		nproducts, 
		command, i, id, quantity;

	nproducts = 0;

	/* loop forever (until user chooses to exit program) */

	for (;;) {

		/* print a menu of options */

		printf ("1: Add a product\n");
		printf ("2: Subtract a product\n");
		printf ("3: Show product list\n");
		printf ("4: Quit program\n");

		/* read and interpret the command */

		scanf ("%i", &command);
		switch (command) {

			/* add a product */

			case 1: /* prompt for ID of product to add */

				printf ("Enter product ID: ");
				scanf ("%i", &id);
				i = find_product (product_ids, id, nproducts);

				/* if the product isn't found, it's assumed
				 * to be a new kind of product 
				 */
				if (i == -1) {

					/* code after this expects 'i'
					 * to be set to the index 
					 */

					i = nproducts;
					printf ("New product ID %i\n", id);
					product_ids[i] = id;
					quantities[i] = 0;

					/* one more product */

					nproducts++;
				}

				/* prompt for quantity to add */

				printf ("Enter quantity to add: ");
				scanf ("%i", &quantity);

				/* add to the number of items available */

				quantities[i] += quantity;
				break;

				/* subtract from inventory */

			case 2: /* prompt for the product to subtract */

				printf ("Enter product ID: ");
				scanf ("%i", &id);
				i = find_product (product_ids, id, nproducts);

				/* can't subtract if product doesn't exist */
				if (i == -1) {
					printf ("No such product!\n");
					break;
				}

				/* prompt for amount to subtract */

				printf ("Enter quantity to subtract: ");
				scanf ("%i", &quantity);

				/* may not be enough product */

				if (quantities[i] - quantity < 0) {
					printf ("Not enough left!\n");
					break;
				}

				/* subtract */

				quantities[i] -= quantity;
				break;

				/* print list of products */

			case 3: /* 

				/* print a header */

				printf ("ID#\tAmount left\n");

				/* print each ID and number left */

				for (i=0; i<nproducts; i++) {
					printf ("%i\t%i\n", 
						product_ids[i],
						quantities[i]);
				}
				break;

				/* quit program */

			case 4: exit (0);
			default: printf ("huh?\n");
		}
	}
}
The way the program remembers both the product ID number and the quantity of the product left is by using two arrays. This concept is called using parallel arrays and is used often in other computer languages. We'll see in later chapters that C has an even better way of dealing with situations like this.

Large Number Arithmetic in Arrays

Remember how we could only print up to the first 40 or so Fibonacci numbers, since C integers have only 32 bits? With arrays, we can define our own arithmetic operations on numbers as big as we want. We can have an array of integers where each element represents a single decimal digit in one very large number. The two hundredth Fibonacci number is 280,571,172,992,510,140,037,611,932,413,038,677,189,525, clearly too big for a 32-bit integer. This was found using the following program, that prints the first two hundred Fibonacci numbers:
#include <stdio.h>
#include <stdlib.h>

/* up to 70 decimal digits */

#define DIGITS	70

/* add two big integers stored in arrays a and b, and put the result
 * into the array c
 */
void add_bigint (int a[], int b[], int c[]) {
	int	carry, i, sum;

	/* grade school addition algorithm */

	carry = 0;
	for (i=0; i<DIGITS; i++) {

		/* add i'th digits of a and b, and any carry */

		sum = a[i] + b[i] + carry;

		/* if result >= 10, "carry the one" */

		if (sum >= 10) {
			sum -= 10;
			carry = 1;
		} else 
			carry = 0;
		c[i] = sum;
	}
}

/* print a big integers from most to least significant digit, 
 * without printing leading 0 digits 
 */
void print_bigint (int a[]) {
	int	i, leading0;

	/* "the current digit is a leading zero" is true */

	leading0 = 1;

	/* go from most to least significant digit */

	for (i=DIGITS-1; i>=0; i--) {

		/* it this isn't a 0, then it isn't a leading zero */

		if (a[i] != 0) leading0 = 0;
	
		/* if we're not in the leading 0's, print the digit */
	
		if (!leading0) printf ("%i", a[i]);
	}

	/* if we got this far without printing anything, must be 0 */

	if (leading0) printf ("0");
	printf ("\n");
}

/* copy one bigint to another; a = b */

void copy_bigint (int a[], int b[]) {
	int	i;

	for (i=0; i<DIGITS; i++) a[i] = b[i];
}

/* put the big integer "1" into a */

void make_one (int a[]) {
	int	i;

	for (i=1; i<DIGITS; i++) a[i] = 0;
	a[0] = 1;
}

int main (int argc, char *argv[]) {
	int	i, F_i[DIGITS], F_i_minus_1[DIGITS], tmp[DIGITS];

	/* F_i = 1 */

	make_one (F_i);

	/* F_(i-1) = 1 */

	make_one (F_i_minus_1);

	/* print first two Fibonacci numbers */

	printf ("1\t1\n2\t1\n");

	/* print tne next 198 */

	for (i=3; i<=200; i++) {

		/* tmp = F_(i-1) + F_i */

		add_bigint (F_i, F_i_minus_1, tmp);

		/* F_(i-1) = F_i */

		copy_bigint (F_i_minus_1, F_i);

		/* F_i = tmp */

		copy_bigint (F_i, tmp);

		/* print which Fibonacci number it is */

		printf ("%i\t", i);

		/* print the big integer */

		print_bigint (F_i);
	}
	exit (0);
}