Use of Structures with Functions, Pointers and Arrays

Richard Kay, 3 Oct 2000
 

The purpose of structures


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 */


Definition of new data type: typedef


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 .
 

Functions which communicate using structures


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;
}
 

Use of structure pointers


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 &  */
}

Bug report:

The Borland Compiler doesn't always handle expressions such as &t->x correctly. This can lead to a runtime error with the program crashing with an error message: floating point formats not linked.
Patch:
In the above code replace:
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 */


Structures and arrays


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 &ampersand 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]);
 

Assigning Structures


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 */