Arrays are useful when we want a number of data items to be stored
which are the same as each other. However, many computing applications
require data of different kinds to be associated. A typical place where
this occurs is in the computing concept known as a record. For example
a database record for a particular student might include the student number,
full name, course-code and year of entry. Such a record could be declared
as a C structure like this:
struct student {
long int studno;
char name[50];
char course[7];
int startyear;
};
Other examples of related data might be a complex number consisting of
a real and imaginary part, or the x,y coordinates of a pixel:
struct coord { float x,y; };
struct complex { float real,imaginary; };
These declarations don't create any space for data storage, but they provide
a template for data of the appropriate types to be allocated. Let's allocate
some storage to data variables:
struct coord origin, cursor; /* 2 x-y coordinates called origin and cursor */ struct student sweng3[50]; /* array sweng3 for 50 students */
To avoid having to use 2 words (e.g. struct coord ) to refer
to our new data types where 1 will do we could instead define a new date
type (typedef) by saying:
struct coord { float x,y; };
typedef struct coord COORD; /* COORD is now same as struct coord */
COORD origin, cursor; /* declare 2 x-y coordinates called origin and cursor */
We can now declare complex data with a single word in a similar way that
we use other built-in data types such as float and int. This
simplification is useful if the name of the data type is going to appear
in various places within our program, e.g. for declaring types of local
data within functions or function parameters. Members x and y of origin
and cursor can now be accessed as origin.x, origin.y, cursor.x and cursor.y
.
e.g. Here is the definition of a function distance() which
calculates and returns the distance between 2 x-y coordinates:
float distance(COORD a, COORD b){ /* calculate distance between a and b */
float z,vert,horiz; /* z = distance, vert = y1 - y2, horiz = x1 - x2 */
horiz=a.x - b.x; /* the horizontal distance */
vert=a.y - b.y; /* the vertical distance */
/* calculate z as the hypotenuse of a right angle triangle */
z=sqrt((horiz*horiz) + (vert*vert)); /* Pythagorus theorem: */
return z; /* z*z = x*x + y*y */
}
Here is a function getcoord() which inputs x and y values and returns
a coordinate:
COORD getcoord(void){
COORD temp;
printf("please enter x and y coordinates\n");
scanf("%f%f",&temp.x,&temp.y);
return temp;
}
Here is a simple program making use of the above 2 functions:
#include <stdio.h>
#include <math.h> /* needed to use sqrt() square root */
struct coord { float x,y; }; /* declare structure coord as having x and y members */
typedef struct coord COORD; /* COORD is now same as struct coord */
COORD origin, cursor; /* declare 2 x-y coordinates called origin and cursor */
float distance(COORD a, COORD b); /* function prototypes */
COORD getcoord(void);
int main(void){
COORD origin, cursor;
float seperation;
printf("enter details for origin:\n");
origin=getcoord();
printf("enter details for cursor:\n");
cursor=getcoord();
seperation=distance(origin,cursor);
printf("the distance between origin and cursor is %f\n",seperation);
return 0;
}
Members x and y of coordinates of locations a and b can also be
accessed through pointers to a and b so that if pointer p stores the address
of a (coded as: p=&a; ) then p->x directly accesses member
x of a or a.x . In order to avoid having to copy data around and
to save a little bit of memory, let's rewrite the above program using pointer
notation:
/* declarations above here of headers , stuct coord and typedef COORD
all stay the same so I won't repeat them */
float distance(COORD *a, COORD *b); /* a and b are now pointers to COORD */
void getcoord(COORD *t); /* inputs coordinate through COORD* pointer t */
int main(void){
COORD origin, cursor, *orig,*curs;
orig=&origin; curs=&cursor; /* store addresses in pointers orig and curs */
float seperation;
printf("enter details for origin:\n");
getcoord(orig);
printf("enter details for cursor:\n");
getcoord(curs);
seperation=distance(orig,curs);
printf("the distance between origin and cursor is %f\n",seperation);
getch();
return 0;
}
float distance(COORD *a, COORD *b){ /* calculate distance between a and b */
float z,vert,horiz; /* z = distance, vert = y1 - y2, horiz = x1 - x2 */
horiz=a->x - b->x; /* the horizontal distance note use of -> pointer syntax */
vert=a->y - b->y; /* the vertical distance */
/* calculate z as the hypotenuese of a right angle triangle */
z=sqrt((horiz*horiz) + (vert*vert)); /* pythagorus theorem: */
return z; /* z*z = x*x + y*y */
}
void getcoord(COORD *t){ /* inputs x-y coordinate directly using pointer */
printf("please enter x and y coordinates\n");
scanf("%f%f",&t->x,&t->y); /* -> has higher precedence than & */
}
printf("please enter x and y coordinates\n");
scanf("%f%f",&t->x,&t->y);
With:
COORD c;
printf("please enter x and y coordinates\n");
scanf("%f%f",&c.x,&c.y); /* input into coordinate c using address of c */
*t=c; /* assign (copy) coordinate c to the object pointed at by t */
Supposing we want 10 coordinates and we don't want to mess around
with individual names for them. We can declare the data required as an
array:
typedef struct coord { float x,y; } COORD;
COORD graph[10];
We can then assign members of our structure array like this:
graph[9].x = 12.5; graph[9].y = 7.3; /* assign values to tenth element [9] of graph array */Or we could input values into all coordinates like this:
int i;
for(i=0;i<10;i++){
printf("please enter x value for coordinate %d\n",i+1);
scanf("%f",&graph[i].x);
printf("please enter y value for coordinate %d\n",i+1);
scanf("%f",&graph[i].y);
}
Considering that graph without [] brackets is a pointer to the start of
the array, lets recode the above using structure pointer ( -> ) notation:
int i;
for(i=0;i<10;i++){
printf("please enter x value for coordinate %d\n",i+1);
scanf("%f",&(graph+i)->x); /* -> has higher precedence than & */
printf("please enter y value for coordinate %d\n",i+1);
scanf("%f",&(graph+i)->y);
}
Quite often a structure will contain an array. E.G:
typedef struct student {
char name[30];
float mark;
} STUDENT;
STUDENT you;
printf ("enter name and mark\n");
scanf ("%s%f",you.name,&you.mark); /* you.name is the address of the name array */
/* so no &ersand needed to get address*/
/* BUT you.mark is not an array so needs & */
printf ("hello %s your mark is %f\n",you.name,you.mark);
printf ("The first letter of your name is %c\n",you.name[0]);
Unlike arrays, structures can be copied as a complete entity using
a single assignment. This saves time. E.G instead of writing:
strcpy(temp.name,you.name); /* have to use function strcpy to copy a string */ temp.mark = you.mark; /* can assign mark in one go */we can write:
temp=you; /* copy entire structure in one go */