Archive for the ‘Data Structures’ Category

Algebraic Mesher

Thursday, March 13th, 2008

In looking for an alternative to the half edge meshing scheme, I hit upon the idea of using algebraic relations between cells, faces and vertices in order to build a mesh. Those relationships were described in the previous post. Here I want to describe how I implemented this in C.

Data Structures

Like my Half Edge mesher, the MESH_TYPE data structure consists of lists of all the vertices, faces and cells in the mesh.

struct mesh_type { //contains all mesh info ALIST cells; //cell list ALIST faces; //face list ALIST verts; //vert list };

ALIST is the generic array I had defined earlier. It consists of a small data structure that includes a pointer to an array on the heap containing the actual data. In this way, the array can be resized and bounds checking can be done. The figure shows the mesh data structure.

Mesh Data Structure

Up to this point, the structures are the same as in the Half Mesh program. Where things change is in the data structures for the cells, faces and vertices. For instance a face structure looks like

struct face_type { ALIST verts; //list of ptrs to face verts ALIST cells; //list of ptrs to faces 1 or 2 cells };

Each face in the list of faces contains lists of pointers to elements in these three master lists. Trying to draw all the relationships can get confusing. This pictures gives an idea for the faces of a cell

Cell Data Structure

Each cell in the master list contains a list of four face pointers. These pointers point to the four faces in the master list where this cell’s faces reside. Imagine how confusing that picture would be if I were to try and draw all the connections between cells, vertices and faces?

Accessing the Data

Suppose you want to average the x and y coordinates all the vertices of a cell, to make sure it matches the cell center. (This is one of the tests I used to check the meshing code.) This can be done easily using the new improved FOR_EACH macro from the generic list include file:

double totX, totY,dx,dy; VERT_TYPE **ppVert; FOR_EACH(pCell, pMesh->cells) { totX = 0; totY = 0; FOR_EACH(ppVert, pCell->verts) { pVert = *ppVert; totX += pVert->x[0]; totY += pVert->x[1]; } //Find diff betw cell center and vert ave dx = pCell->x[0] - totX/4; dy = pCell->x[1] - totY/4;

The outer loop is over the cells in the master list of cells for the mesh. The way the FOR_EACH works, is it puts a pointer to the current cell into pCell on each pass through the loop. This allows us to dereference the fields of the cell. It is the inner loop, over the cell vertices, where confusion can set in. The vertex list in a cell structure holds pointers to the actual vertices residing in the master vertex list. Since FOR_EACH returns a pointer to whatever is in the list, it returns a pointer to a pointer. That is why I defined the variable ppVert. In order to gain access to the x and y position of the vertex, we dereference ppVert, to get a pointer to the vertex. From their we can get the position. These dereferencing subtleties were not at all clear to me as I wrote this. In addition, I hadn’t always allocated memory for my lists. The result was the memory debugging nightmare I mentioned previously.

Assessment

The entire motivation for this project was to generate a meshing program that had some of the elegance of the half edge mesh, while being better suited for CFD applications. Was it successful? It is hard for me to say at this point. In terms of code length, the two implementations are nearly identical. Thus one is not a lot clumsier than the other. One thing I find troubling about the algebraic meshing approach is you can’t look at the code and tell if its right. When you see a line like

pVert = getItem(verts,CID+i+1); //SE vert

how do you know that pVert is really the south east vertex of cell CID? You need to sketch out the grid and work out the relationships. Also, I am still reeling a bit from all the memory problems I had. The half edge mesh routine came together a lot more easily.

All in all, I would say the jury is still out on this one. But now that I have created it, I hope to use it to do some work with Immersed Boundaries.

Download

If you want to play with the code to generate meshes, you can download it here. Put the files ArrayType.inc and AlgMesher.c in the same folder and compile and run:

gcc -Wall AlgMesher.c ./a.exe

When main runs, it will call a test function that tests five different aspects of a simple 100×100 mesh. It writes out the results to a text file. In this way, I tried to make the code relatively bug free. Enjoy.

Rethinking the Half Edge Mesh

Saturday, March 1st, 2008

In earlier discussions (here and here), I extolled the benefits of the half edge mesh. It is an elegant way of compactly storing 2d mesh information. Moreover, it allows you to easily do adjacency tests (e.g., what are all the edges touching this vertex?). However, upon further reflection, two weaknesses have occurred to me:

  1. It is lacking for the finite volume method.
  2. Its not extendable to 3d

I don’t know that these are show stopper considerations, but they do give one pause. Lets look at them in more detail.

Finite Volume

The key tenet of the finite volume method is the balance of fluxes leaving and entering each cell face. This is what makes this approach intrinsically conservative, unlike the finite element method.

At some point in the execution of a finite volume code, we loop over the faces in the domain and calculate the fluxes crossing those faces. Because each pair of cells share one face, we know that the material leaving cell A must flow into cell B. But the half edge data structure doesn’t have faces; it has half faces. There is no single entity that connects both cells. So how do we achieve this conservation? The simplest way is probably to create a full face data structure that each half face points to. We can then calculate the fluxes on this face as normal. While this adds additional complexity to the scheme and reduces its elegance, it should be perfectly doable.

3d

What really makes me doubt the viability of the half edge approach is in generalizing it to 3d. In 2d, the vertices, edges and cells are connected together in a simple fashion. For instance, the edges around a cell are connected, one to the next, in a chain. This makes it easy to create a linked list of edges to go around the cell.

Face linkage in 2d, 3d

In 3d, each cell is surrounded by six faces. There are many ways to connect these faces together in a linked list. The figure shows one of them. That is workable, but how do you get an adjacency test out of it? For instance, lets say you want to know all the faces that surround a vertex. I can’t figure out any clever way of looping through the half faces to achieve this.

Next Steps

I am working on another mesh generator that uses algebraic relationships between cells, faces and vertices to establish the connections between these entities. It has a certain elegance to it as well. Unfortunately, in implementing it, I hit all kinds of memory and pointer problems that took awhile to work out.

Half Edge Mesh Implementation

Saturday, February 2nd, 2008

In a previous post, I discussed the elegance of the Half Edge data structure for storing mesh information. This time, we will implement such a scheme in C. The goal is simple: create a program that meshes a 2d rectangle with a structured grid, while storing the information in the Half Edge data structure.

If we know the length and width of the rectangle, and the cell size, we can compute the number of rows and columns in our mesh. We can then loop over these rows and columns, creating cells, faces and vertices and linking them together. As we create these mesh elements, we will store them in lists, using the generalized arrays we developed earlier.

We will build the mesh row by row. The first step is to create the south most row of vertices. As we construct a row of cells, we will be building them on top of the vertices of the previous row. So for the very first row cells, we must first create a row of verts. Once this is done, we enter a pair of nested for loops where we loop over the rows and columns of the mesh. Here is the basic idea

for (i=0; i<numRows; i++) { Prepare the row for (j=0; j<numCols; j++) { Set corner vertices of cell Create new cell Create faces of cell Make remaining connections Hook up the pairs of WF and NF faces Save a few items to help with next cell or next row } wrap up this row }

Once the first row of verts is created, we begin creating cells. For the first cell of a row, we must create a north west vertex. For all other cells on that row, the north east vertex of the previous cell becomes the north west vertex for the new cell. We then need only create one vertex per cell, specially the north east one. This is shown in Step 2 of the figure. With the four vertices of the cell defined, we can then create the four faces of the cell (step 3), then create the cell and link everything together. Its then on to the next cell. In this step by step fashion we build up the mesh.

MeshSteps

A subtlety

There is a subtlety I didn’t mention in the previous post. There are 8 half faces that touch a vertex. How do you know which one to store in the vertex? For an interior vertex it doesn’t really matter, as long as its consistent with the scheme for cycling through the faces around the vertex. Specifically, if you store a face pointing toward the vertex, then you cycle through the faces with the command

face = face->pair->nextF;

If you pick a face that points toward the vertex, then you use

face = face->nextF->pair;

For vertices at the edge of the domain, greater care is needed. Not every face has a pair near the edge, so a command like

face = face->pair->nextF;

can lead to errors. Also, we need to pick the edge that allows us to go fully around the vertex. In the picture below, this can only be satisfied for vertex V by picking face F.

Faces around a vertex

In general, we need to pick the most counter clockwise edge, relative to the vertex. (That is because our circular linked list of faces is organized in a counter clockwise direction.)

More on Lists

In writing this simple mesher, I made use of the generalized arrays developed earlier. In the process of using these, I came across various things that didn’t work that well, so I changed them. For instance, the listAppend function originally returned an index to the data array where the new data was written. It turned out to be more convenient to return a pointer to that data.

I also realized that the creation and destruction functions were overly restrictive. They assume the user has already created the list object and only needs the data array allocated. There are times however, when the user would like both allocated and deallocated for him. So there are now two sets of creation and destruction functions:

void createListData(ALIST *list, long maxEl, size_t elSize) void destroyListData(ALIST *list) void createList(ALIST **list, long maxEl, size_t elSize) void destroyList(ALIST *list)

This provides greater flexibility, but also adds complexity. Speaking of complexity, the astute reader will note in the source code that I did not use these flexible arrays for the lower and oldNF arrays. Instead I used fixed arrays, dimensioned to 1000 elements. A flexible array would be perfect here, since it will auto-expand to however many rows are needed. But the extra hassle didn’t seem worth it for some something so simple.

If I had used these flexible arrays, setting and getting values would have looked like:

LL = *(VERT_TYPE *)getItem(lower, j); setItem(lower, j) = UL;

instead of

LL = lower[j]; lower[j] = UL;

That is a serious loss of readability. When getting the item from the list, you have to remember that getItem returns a pointer to the data element, so you must dereference it. To be proper, you need to cast the pointer first. That makes for some pretty darn ugly code. I could use a macro to clean it up. Perhaps something like:

#define GET_ITEM(pList, index, datatype) *(datatype *)getItem(pList, index);

I will have to experiment with it.

Wrap Up

If you want to play with the code to generate a half edge mesh, you can download it here. Put the files ArrayType.inc nd HalfMesher.c in the same folder and compile and run:

gcc -Wall HalfMesher.c ./a.exe

When main runs, it will call a test function that tests different aspects of a simple 10×10 mesh. It writes out the results to a text file. This is how I made sure the code was relatively bug free.

Half Edge Mesh – Intro

Saturday, January 26th, 2008

When I created the mesh generator for BFlow, I used a straightforward but unimaginative set of data structures for storage. A mesh is made up of cells, faces, edges and vertices. Unstructured meshes have arbitrary relationships between these (unlike a structured mesh), and thus those relationships must be stored.

In a 2d, a mesh looks like this:

mesh

My BFlow data structures to hold the information for a mesh look like this:

TYPE CellType node(4) AS LONG '1=SW,2=SE,3=NE,4=NW (1st 4 are the corners) Face(4) AS LONG '1=East, 2=west, 3=North, 4=South nb(4) AS LONG 'Neighbor cells. 1=East, 2=west, 3=North, 4=South END TYPE TYPE FaceType node(2) AS LONG 'ptrs to two nodes of face cell(2) AS LONG 'ptrs to neighbor cells END TYPE TYPE VertType face(4) AS LONG 'pointer to touching faces, 1=East,2-West,3=North,4=South cell(4) AS LONG 'pointer to touching cells, 1=SW,2=SE,3=NE,4=NW END TYPE

(These are Basic declarations, but they would look very similar in C.) You can see that everything is stored. A cell can have four faces and four nodes. Pointers to them are stored in that cell structure. A vertex can be touched by four faces. Pointers to all those faces are stored for each vertex.

There is a very elegant alternative storage scheme called the Half Edge Mesh. Amazingly little information is stored, but it provides everything you need! The key idea is that rather than store edges (or faces in 2d), you store half edges (half faces). While an ordinary face is defined by its two end points, a half face is directed and defined by just a single point. The picture shows the idea.

mesh2

This probably looks like a step in the wrong direction, if we are trying to simplify things. Yet, this change is really helpful. The data structure for a half face looks like:

struct face_type { VERT_TYPE *vert; //vertex at the end of the half-face FACE_TYPE *pair; //Oppositely oriented adjacent half-face CELL_TYPE *cell; //cell that this face belongs to FACE_TYPE *nextF; //next half-face around the cell };

The vertex and cell structures are given below:

struct vert_type { double x; double y; FACE_TYPE *face; //Ptr to a touching face }; struct cell_type { FACE_TYPE *face; //south face of cell };

The cell structure seems especially spartan, at least compared with what I started with. How do you access the faces of the cell? Or its vertices? It turns out to be very easy:

FACE_TYPE* face = cell->face; do { // ...some face calcs... face = face->nextF; } while (face != cell->face);

The cell faces are effectively organized into a circular linked list. Thus the above code works equally well for a quad mesh as a polyhedral mesh.

Accessing all of the vertices around the cell is nearly as easy:

VERT_TYPE *vert; FACE_TYPE *face = cell->face; do { vert = face->vert; // ...some vert calcs... face = face->next; } while (face != cell->face);

Now lets try something trickier. Say you needed to loop over all of the cells surrounding a vertex? This could come up in a CFD model, for instance, when interpolating a field value from the cell centers to the vertices. Here is the code:

CELL_TYPE *cell; FACE_TYPE* face = vert->face; do { cell = face->cell; // ...cell calcs... face = face->nextF->pair; } while (face != vert->face);

This takes advantage of the fact that pairs of faces are oriented in opposite directions. In the figure below, face F1 is pointed upward. Its pair face, F2, is pointed downward. Each face stores a pointer to the vertex that it is pointing to. F1 stores a pointer to V1, while F2 stores a pointer to V2.

Mesh3

You can trace out logic by picking one of the faces pointing toward vertex V2, then following the steps. It is very elegant.

Compared to my original scheme, the Half Edge approach is both more efficient (in terms of memory use) and more flexible (since its not limited to quad meshes). In my next entry, I will explore this in more detail.

Writing to generic arrays

Tuesday, January 1st, 2008

In an earlier entry, we developed a generic array in C and a way to loop through that array. The idea behind this is simple: if we have a standard way to working with arrays, we can eliminate common errors (like writing outside array bounds) while providing great flexibility. In playing with this tool, I found that I need a function for writing an element to an array. I quickly whipped something out and hit a roadblock.

Imagine a function, ListAppend, that adds a new element onto the end of a generic array. Its declaration might look like this:

int ListAppend(AList *list, void *item)

(The name ListAppend might seem odd in the context of C arrays, but I am picturing a python list, that you can easily manipulate without worries.) This function takes the list, and a pointer to the item to be added and returns the array index of this new item. The problem comes when we try to copy the data in item to its slot in the array. Imagine some code like this

void *pData = list->Data + list->NumEl * list->ElSize; //calc where to write data *pData = *item; // Write data <-- illegal! Can't deref void ptr.

The first line determines where to write the data (at the end of the array) and the second line writes it. Unfortunately, the compiler doesn’t like this. Because both pointers are of type void, the compiler doesn’t know how many bytes to copy from *item and doesn’t know how many *pData can safely hold. For this to work right, both pointers need to be of the correct type. The compiler needs this information at compile time, so we can’t be setting it at run time. What to do?

Solutions

I have thought of three ways to approach this, none totally satisfactory.

- User defined assignment function
- memcopy
- macros

In the first method, we have a single ListAppend function of the form:

int ListAppend(AList *list, void *item)

like before. But we add a function pointer to the list structure. This pointer points to a user written function that copies the data from item to the correct slot at the end of the array. Here is an example of such a function:

int AssignFuncVert(void *src, void *dest) { VERT_TYPE *pdest = (VERT_TYPE *)dest; VERT_TYPE *psrc = (VERT_TYPE *)src; *pdest = *psrc; return 0; }

This code first casts the pointers into the appropriate type (VERT_TYPE in this case) and then does the assignment. This approach is in the opposite direction of where we are trying to go with these generic arrays. We want our generic structures to be easy to use. Function pointers have complex syntax and are scary for some people.

The memcpy approach takes advantage of the memcpy function in the string.h file. This function copies n bytes from one location to the other. You don’t have to worry about types. As long as you copy the correct number of bytes, all is well. Since we are already storing the size of an element, this is no problem. The memcpy function is called like so:

memcpy(pData, item, list->ElSize)

This approach requires no additional work on the part of the user, which makes it very attractive. On the downside, we are circumventing the type checking the compiler does, which may set us up for problems.

In the third approach, we mimic templates in C++. A macro is used to generate a ListAppend function for each data type of interest. You would call the macro like so:

LIST_APPEND(ListAppendVert, VERT_TYPE)

and get a function that looks like:

int ListAppendVert(ALIST *list, VERT_TYPE *item)

The nice thing about this approach is it is type safe. If you pass the wrong thing to the ListAppendVert function, the compiler will complain. The downside is it is a bit unclear, just from looking at an include file containing this macro, what you are supposed to do. There would have to be some good comments included.

Pros and Cons

All three approaches have pros and cons. In my view, the most important criteria in deciding which approach is best are simplicity and robustness. We all have limited bandwidth, and we don’t want to waste it on stupid stuff. A generic array is nice, but if it takes too long to come up to speed each time we use it, we will just use ordinary arrays. Robustness is more subtle. Will the code stand up to typos and other errors, either by flagging them early or gracefully doing the right thing? Not being a strong C programmer, it is hard for me to anticipate what might go wrong.

Approach Simplicity Robustness --------------------------------------------------------------------------- -------------------------------------------- User Func low med memcpy high med Macros med high --------------------------------------------------------------------------- -------------------------------------------

The table is a stab at rating the three approaches. The memcpy approach doesn’t require any extra work by the user, so it ranks well simplicity. I think it should be safe, but can’t be positive. Copying bytes, regardless of type seems a bit risky. The user function approach could be a turn off to people. Function pointers are tricky enough to scare many off. The macro approach is very attractive from a robustness point of view, but I think there is a high potential for forgetting how to use them. Given all this, I think I will go with memcpy and see how it works out.

A small program that implements each of these three methods is in the file WriteToArray. It can be compiled with the command gcc -Wall WriteToArray.c.

General Linked List in C

Thursday, December 27th, 2007

In an earlier entry, we developed a generic way of creating and looping through arrays in C. Arrays are very useful, but for some things linked lists are better. So lets develop some general tools for them.

Decisions

First, a design decision must be made. Each element in the list needs a pointer to the next element, and optionally a pointer to the previous one. Where should these pointers reside? There are a couple of options. The most obvious approach is to add next and previous pointers to whatever structure is used to store your data. This leads to a structure like the figure.
LinkList1
Data Structures for Linked Lists. Direct Approach.

We have a generic container (in green). It stores the number of elements in the list, along with a pointer to the first and last elements. It is up to the user to create the structure that holds the data for each element of the list. And this structure must include the prev and next pointers. This approach is conceptually simple and provides direct access to the data. However, it lacks generality. If you want to make a list containing elements based on a structure from another library, you are out of luck, unless they contain the prev and next pointers. Also, what if you want to store these data items in multiple lists? Can’t be done with a single set of next and prev pointers.

A way around this problem is to add a level of indirection to the scheme. The figure below shows the idea. We now have two predefined structures, one for the list (green) and a new one for a generic list element (blue).
LinkList2
Data Structures for Linked Lists. Indirect Approach.

Now a list can store items of any data type. It could even contain different structures. This generality comes at the price of more complex data access. To retrieve an item from the list, you must do something like:

mylist.pFirst->ListEl->Data1
(green) (blue) (pink)

Instead of

mylist.pFirst->Data1
(green) (pink)

This is one extra level of indirection, compared to the first scheme. It makes the code less readable, is more error prone and is probably slower as well.

Since we are going for generality, we will use the indirect approach, and see how it works.

Another design decision is should the list be linear or circular. In other words, should the next pointer in the last element be set to NULL or to the first element? We’ll keep it simple and create a linear list

Implementation

Here are what our two generic structures look like:

//Generic list Element struct lelement { LElement *next; LElement *prev; void *data; }; //Generic List Structure struct llist { int NumEl; //Number of elements in list LElement *pFirst; //Ptr to first element in list LElement *pLast; //Ptr to last element in list };

The structure for a generic element in the list contains three pointers: next and prev needed for the list, and data which points to the data we are storing. The container structure holds the number of elements in the list, as well as pointers to the first and last elements.

To create an empty list, we just initialize the items in the container:

void CreateList(LList *list) { list->NumEl = 0; list->pFirst = NULL; list->pLast = NULL; }

We assume the memory was allocated elsewhere. An element can be added to the end of the list by adjusting the pointers at the end of the list and in the new element. The code below shows an implementation of this.

LElement *AddToList(void *item, LList *list) { //check inputs assert(item!=NULL); assert(list!=NULL); //Create generic element to hold item ptr LElement *NewEl; NewEl = (LElement *)malloc(sizeof(NewEl)); //create generic element assert(NewEl != NULL); list->NumEl = list->NumEl + 1; NewEl->data = item; if (list->NumEl == 1) { list->pFirst = NewEl; NewEl->prev = NULL; NewEl->next = NULL; } else { NewEl->prev = list->pLast; NewEl->next = NULL; list->pLast->next = NewEl; } list->pLast = NewEl; return NewEl; }

It is also to be able to add data at the beginning or middle of the list. This can be done in a similar way, although there are a few more details to worry about. To remove an item from the list you simply bypass it, then free the memory. Because we don’t know if the data is stored in multiple lists, it is never freed, only the generic list element.

Looping

To loop through a linked list, we can create a macro similar to the one for general arrays:

#define FOR_EACH(item_ptr, list) \ for (ListEl = myList.pFirst; ListEl != NULL; ListEl=ListEl->next)

This macro creates a for loop that initializes ListEl at the first value. It then increments this value at the end of each pass through the loop until the end of the loop is reached. This makes it handy for looping through an already existing list. It is not very helpful in looping through a list under construction.

Summing up

The list code can be found here: ListType.c. It can be compiled with the command

gcc -Wall ListType.c

In creating this example, I hit many snags. It is very easy to make a mistake when rearranging the pointers for an insertion. Then the test code would try to write to a NULL pointer and crash! In comparison, the array list was much easier to develop. If I was going to use linked lists for general storage like this, I would want a well tested library, rather than just winging it.

A Generalized Array in C

Tuesday, December 18th, 2007

In numerical computations, we frequently have lists of objects we must deal with. In C, there are two types of containers commonly used for holding these lists: arrays and linked lists. Arrays are good for fast, random access to the list. However, they are a few drawbacks. It is easy to write outside of array bounds and crash the code. It is hard to add elements to the middle of the list. And if you need more space than you allocated, you need to allocate a new larger block of memory and copy everything over.

Linked lists are good for frequently changing lists. You can easily insert an element anywhere in the list. Since memory is allocated as each element is created, there is no problem running out of room. However, cycling through the list can be slower, since the elements can be scattered all over in memory, and it is time consuming to retrieve the ith element of a list. Numerical folks tend to favor arrays, but both tools are useful.

Here we will create a general array and a macro for looping through it. This will hopefully be useful for reducing coding errors.

Array Structure

Lets begin by creating a general array structure, and some functions to access it.

A generic structure, that can hold arrays of anything might look like:

typedef struct { long NumEl; //number of elements size_t ElSize; //size of each element void *Data; //ptr to data } AList;

This structure stores the size of the array, the size of each item in the array and a pointer to the first element in the array. Knowing the number of elements in the array is useful to staying in array bounds. The size is important for allocating memory and when we try looping. Notice that Data is a pointer to void. That is because we don’t know what type of array we will have. It could be intergers, floats or some arbitrary structure.

A new ArrayList could be created like so:

void CreateList(AList *list, long NumEl, size_t ElSize) { list->NumEl = NumEl; list->ElSize = ElSize; list->Data = (void *)malloc((NumEl + 1) * ElSize); if (list->Data == NULL) printf ("Error in CreateList: Can't allocate memory"); }

To destroy a list, we must deallocate the memory for the data array. The DestroyList function does this:

void DestroyList(AList *list) { if (list->Data != NULL) { free(list->Data); list->Data = NULL; } }

One can access an element in the array with

void *GetItem(AList list, long index) { if (index >= 0 || index < list.NumEl) {return list.Data + index * list.ElSize;} else { printf ("Wrting outside array bounds"); return NULL; } }

This may look a little strange. If Data is a pointer to an array why not access the elements in the normal fashion with [] brackets? The problem is that we don’t what ahead of time what type of data is stored in the array. For something like list.Data[5] to work, the compiler must know the size of each element, so it can calculate the distance (in memory) from the starting point. Since it doesn’t know that, we do the calculation for it.

One could also envision a SetItem routine, but this would be very dependent on the nature of the element being stored. So it is best to let the user set each element as it makes sense to do so.

For Each loop

One of the first lessons I learned in programming was: Don’t write outside array bounds! Its an important lesson, and a simple one, yet I still occasionally mess up. Why? Because its easy. Here is a very simple way to screw up in C:

int i; float myArray[10] for i=0; i<=10; i++) { //some code }

In C, arrays start at index 0, so the above declaration runs from myArray[0] to myArray[9]. Yet our loop runs to myArray[10]. Trouble!

Some languages handle the looping details for you. Consider this equivalent code in Python:

myList = [1,4,2,3,5,6,3,8,5,9] for each item in myList: #some code

The For statement knows there are ten items in myList and loops over them. Each pass through the loop, it takes the current item in the list and assigns it to Item. You can then do what you want with it.

This type of high level construct frees us to focus on the job at hand while leaving the bookkeeping to the computer. Unfortunately, in the case of Python, this comes at the cost of speed.

Lets try to emulate the For statement in Python. Consider the following macro:

#define FOR_EACH(index, item_ptr, list) \ item_ptr=list.Data; \ for (index=0; index

The FOR_EACH macro has three arguments: an index, a pointer to the an item in the array and the list structure. Like the Python equivalent, with each pass through the loop, the item pointer is set to point to the current position in the array. To find that position, we need to know the size of the elements, as mentioned above. With a macro like this, it is impossible to write outside array bounds. Because the compiler substitutes the code in at compile time, the performance should be the same as hand coding the loop. The best of both worlds!

Trying it out

Lets try a simple example to make sure it is working. Here is a very simple structure:

typedef struct //toy structure to play with { int val1; double val2; } ElType;

To loop through a list, we first create the list, then call the FOR_EACH macro. We must declare an index variable and a pointer to an element, but don’t need to initialize these. Here is the code:

int main() { int i; AList mylist; ElType myEl; ElType *pMyEl; CreateList(&mylist, 100, sizeof(myEl)); FOR_EACH(i, pMyEl, mylist) { pMyEl->val1 = i; pMyEl->val2 = (double)(2.*i); printf("i = %d, val1 = %d, val2 = %f\n", i, pMyEl->val1, pMyEl->val2); } DestroyList(&mylist); return 0; }

A nice feature of this approach is one could later change the array to be 200 elements and all the loops will still work fine.

Download code here: Array Code