arrays && functions && pointers

Regan Heath regan at netwin.co.nz
Sun Jun 18 19:28:16 PDT 2006


On Mon, 19 Jun 2006 01:11:37 +0000 (UTC), MM <MM_member at pathlink.com>  
wrote:
> In C I used to do stuff like:
>
> void foo (TILE (*tiles)[TILEW][TILEH]){
> (*tiles)[0][0].z++; //random operation :)
> }

I dont think the (*tiles) is necessary, to confirm this I tried this test  
program:

#include <sys/types.h>
#include <sys/timeb.h>
#include <stdlib.h>
#include <stdio.h>

#define TILEW 1000
#define TILEH 1000

typedef struct _TILE { int x,y; } TILE;

void foo(TILE arr[TILEW][TILEH]) {
	arr[0][0].x = rand();
	arr[0][0].y = rand();
}
void bar(TILE (*arr)[TILEW][TILEH]) {
	(*arr)[0][0].x = rand();
	(*arr)[0][0].y = rand();

}

double now()
{
	struct timeb b;
	ftime(&b);
	return (double)b.time + (double)(b.millitm/1000.0);
}

void main()
{
	TILE (*data)[TILEW][TILEH];
	double start,end;
	int i;

	//allocated on the heap (not enough room on the stack)
	data = calloc(TILEW*TILEH,sizeof(TILE));
	printf("alloc ok\n");

	//pass as pointer
	start = now();
	for(i = 0; i < 10000000; i++) bar(data);
	end = now();
	printf("bar took: %f\n",end-start);

	//pass as array
	start = now();
	for(i = 0; i < 10000000; i++) foo(*data);
	end = now();
	printf("foo took: %f\n",end-start);
}

My results were very similar for both "foo" and "bar".

I believe the reason for this is that in "foo" we pass the array, in C  
this causes the address of the first element to be passed. In "bar" we  
pass a pointer to the array (AKA a pointer to the first element), so in  
effect both functions do exactly the same thing, except that "bar"  
involves and extra dereference of the pointer and might even take longer  
on average.

> But as I see in your (very complete :) explanation I can just do:
>
> Void foo (TILE tiles[TILEW][TILEH]){
> tiles[0][0].z++;
> }
>
> This is not slower? I ask this because this foo will be an excessively  
> used function in the game loop ;)

I wrote up the same test in D:

import std.c.stdlib;
import std.stdio;
import std.perf;

const int TILEW = 1000;
const int TILEH = 1000;

struct TILE { int x,y; }

void foo(TILE arr[TILEW][TILEH]) {}
void bar(TILE (*arr)[TILEW][TILEH]) {}

void main()
{
	PerformanceCounter c = new PerformanceCounter();
	TILE (*arr)[TILEW][TILEH];	
	int i;
	
	arr = cast(TILE (*)[TILEW][TILEH])calloc(TILEW*TILEH,TILE.sizeof);
	writefln("alloc ok");

	c.start();
	for(i = 0; i < 100000000; i++) foo(*arr);
	c.stop();
	writefln("foo took: ",c.milliseconds());
	
	c.start();
	for(i = 0; i < 100000000; i++) bar(arr);
	c.stop();
	writefln("bar took: ",c.milliseconds());
}

My results were interesting, it appears "bar" takes 3 times longer than  
"foo"!

Can someone else "insanity check" my two test cases above both the C and  
the D in case I have missed something.

> btw. How do I reset all the data of a rectangular array?
> something like:
> tiles[][]=0;

If it's an array of structs then setting to "0" will not work, however  
<struct>.init does, eg.

struct TILE { int x,y; }
..

TILE small[2][2];
	
writefln("small array");
small[0][0].x = 1;
small[0][0].y = 1;
small[1][1].x = 2;
small[1][1].y = 2;
foreach(row; small) foreach(t; row) writefln("{",t.x,",",t.y,"}");
writefln("");

writefln("clearing array");	
foreach(inout row; small) row[] = TILE.init;
foreach(row; small) foreach(t; row) writefln("{",t.x,",",t.y,"}");
writefln("");

Note the use of the foreach to access each 'row' of data.

Note the use of "inout" which causes our changes in the foreach to be  
applied to the actual row of data and not just to a copy of it.

Regan



More information about the Digitalmars-d-learn mailing list