In Search of the foreach Keyword

C has three looping keywords: do, for, and while. These keywords construct a block of statements that repeat, hopefully but not necessarily with a terminating condition. Other programming languages offer additional looping keywords, including the popular and useful foreach.

Forgetting about the goto keyword, the foreach keyword finds itself in languages that offer a richer variety of data constructions than C. In these languages, something I call a collection exists. This data structure is where you often see foreach used, though it can also be used with any array of data.

Consider the following data set:

$list = { "Dr. No", "From Russia with Love", "Goldfinger", "Thunderball" }

One way a foreach keyword can be used on this collection is:

foreach( $item in $list )
    print $item

The above code (assume it’s valid) outputs each string in the $list collection, represented as variable $item in the loop. A C language equivalent might be:

for( i=0; i<items; i++ )
    printf("%d\n",list[i]);

Unlike other types of loop, the foreach statement lacks an iteration counter. Instead, its job is to process the collection (the second argument) individually, using the first argument to repeatedly represent the items in the list.

A foreach statement in C would operate on an array. Its loop count is the number of elements in an array. The C language lacks an operator (or method) to return an array’s size, so a specific calculation must be made to determine how many elements the array holds. This calculation is dependent upon the array’s data type.

For example, in a character array, the number of elements is determined by dividing the memory size of the array by the size of the data type (char). This process is done differently for each array data type: char, int, float, pointers, and so on. The following code demonstrates:

2020_12_26-Lesson-a.c

#include <stdio.h>

int main()
{
    char c[] = { 'a', 'b', 'c', 'd' };
    int i[] = { 10, 100 };
    float f[] = { 1.4, 5.7, 9.0, 22.7, 88.8 };
    char *s[3] = { "this", "that", "the other" };

    puts("Array element count:");
    printf("c = %lu\n",sizeof(c)/sizeof(char) );
    printf("i = %lu\n",sizeof(i)/sizeof(int) );
    printf("f = %lu\n",sizeof(f)/sizeof(float) );
    printf("s = %lu\n",sizeof(s)/sizeof(char*) );

    return(0);
}

In the source code, the expression sizeof(n)/sizeof(type) returns the number of elements in the array: n is an array variable and type is the variable’s data type. For the character pointer array, the data type is a char pointer, as shown in Line 14 with sizeof(char*).

Here’s the program’s output:

Array element count:
c = 4
i = 2
f = 5
s = 3

It’s possible to calculate the number of elements in the array, but what’s not obvious to the code is the array’s data type; the sizeof operator returns the proper sizes, but it can’t guess at the type of data it’s examining. This difficulty must be overcome if a foreach keyword is to be emulated in C.

One trick is to use the size of an element in the array instead of the data type. For example, in an int array, element a[0] is the size of an integer. Likewise, in a char array, a[0] is the size of a char. Using this trick is demonstrated here:

2020_12_26-Lesson-b.c

#include <stdio.h>

int main()
{
    char c[] = { 'a', 'b', 'c', 'd' };
    int i[] = { 10, 100 };
    float f[] = { 1.4, 5.7, 9.0, 22.7, 88.8 };
    char *s[3] = { "this", "that", "the other" };

    puts("Array element count:");
    printf("c = %lu\n",sizeof(c)/sizeof(c[0]) );
    printf("i = %lu\n",sizeof(i)/sizeof(i[0]) );
    printf("f = %lu\n",sizeof(f)/sizeof(f[0]) );
    printf("s = %lu\n",sizeof(s)/sizeof(s[0]) );

    return(0);
}

This solution represents the first step to emulating the foreach keyword, as the array size is obtained. I continue to explore this concept in next week’s Lesson.

Leave a Reply