Data structure tutorial. For understanding, Formulas and forms for Computer Science. Istituto italiano di scienze umane
anand-prakash-2
anand-prakash-2

Data structure tutorial. For understanding, Formulas and forms for Computer Science. Istituto italiano di scienze umane

47 pages
8Number of visits
Description
Data structure tutorial for preparing iit
20 points
Download points needed to download
this document
Download the document
Preview3 pages / 47
This is only a preview
3 shown on 47 pages
Download the document
This is only a preview
3 shown on 47 pages
Download the document
This is only a preview
3 shown on 47 pages
Download the document
This is only a preview
3 shown on 47 pages
Download the document
815.PDF

M. Campbell © 1993 Deakin University

Module 815

Data Structures Using C

Module 815 Data Structures Using C

Page 813-1

Aim

After working through this module you should be able to create and use new and complex data types within C programs.

Learning objectives

After working through this module you should be able to:

1. Manipulate character strings in C programs.

2. Declare and manipulate single and multi-dimensional arrays of the C data types.

3. Create, manipulate and manage C pointers to data elements.

4. Create and manage complex data types in C.

5. Use unions to define alternate data sets for use in C programs.

6. Allocate memory to variables dynamically.

7. Manipulate characters and bits.

Content

Strings.

Arrays.

Pointers.

Data definitions – Structures.

Data definitions – Unions.

Dynamic allocation of data

Character and bit manipulation

Learning Strategy

Read the printed module and the assigned readings and complete the exercises as requested.

Assessment

Completion of exercises and the CML test at the end of the module.

Module 815 Data Structures Using C

Page 813-2

References & resources

The C Programming Language. 2nd. edition Brian W. Kernighan and Dennis M. Ritchie Prentice-Hall, 1988

Turbo C/C++ Manuals.

Turbo C/C++ MS DOS compiler.

Module 815 Data Structures Using C

Page 813-3

Objective 1 After working through this module you should be able to manipulate character strings in C programs

Strings

A string is a group of characters, usually letters of the alphabet. In order to format your printout in such a way that it looks nice, has meaningful titles and names, and is aesthetically pleasing to you and the people using the output of your program, you need the ability to output text data. We have used strings extensively already, without actually defining them. A complete definition of a string is ‘a sequence of char type data terminated by a NULL character,’.

When C is going to use a string of data in some way, either to compare it with another, output it, copy it to another string, or whatever, the functions are set up to do what they are called to do until a NULL character (which is usually a character with a zero ASCII code number) is detected. You should also recall (from Module 813: Fundamental Programming Structures in C) that the char type is really a special form of integer – one that stores the ASCII code numbers which represent characters and symbols.

An array (as we shall discover shortly) is a series of homogeneous pieces of data that are all identical in type. The data type can be quite complex as we will see when we get to the section of this module discussing structures. A string is simply a special case of an array, an array of char type data. The best way to see these principles is by use of an example [CHRSTRG.C].

#include "stdio.h" void main( ) { char name[5]; /* define a string of characters */

name[0] = 'D'; name[1] = 'a'; name[2] = 'v'; name[3] = 'e'; name[4] = 0; /* Null character - end of text */ printf("The name is %s\n",name); printf("One letter is %c\n",name[2]); printf("Part of the name is %s\n",&name[1]);

}

The data declaration for the string appears on line 4. We have used this declaration in previous examples but have not indicated its meaning. The data declaration defines a string called name which has, at most, 5 characters in it. Not only does it define the length of the string, but it also states, through implication, that the characters of the string will be numbered from 0 to 4. In the C language, all subscripts start at 0 and increase by 1 each step up to the maximum which in this case is 4. We have therefore named 5 char type variables: name[0], name[1],

Module 815 Data Structures Using C

Page 813-4

name[2], name[3], and name[4]. You must keep in mind that in C the subscripts actually go from 0 to one less than the number defined in the definition statement. This is a property of the original definition of C and the base limit of the string (or array), i.e. that it always starts at zero, cannot be changed or redefined by the programmer.

Using strings

The variable name is therefore a string which can hold up to 5 characters, but since we need room for the NULL terminating character, there are actually only four useful characters. To load something useful into the string, we have 5 statements, each of which assigns one alphabetical character to one of the string characters. Finally, the last place in the string is filled with the numeral 0 as the end indicator and the string is complete. (A #define statement which sets NULL equal to zero would allow us to use NULL instead of an actual zero, and this would add greatly to the clarity of the program. It would be very obvious that this was a NULL and not simply a zero for some other purpose.) Now that we have the string, we will simply print it out with some other string data in the output statement.

You will, by now, be familiar with the %s is the output definition to output a string and the system will output characters starting with the first one in name until it comes to the NULL character; it will then quit. Notice that in the printf statement only the variable name needs to be given, with no subscript, since we are interested in starting at the beginning. (There is actually another reason that only the variable name is given without brackets. The discussion of that topic will be found in the next section.)

Outputting part of a string

The next printf illustrates that we can output any single character of the string by using the %c and naming the particular character of name we want by including the subscript. The last printf illustrates how we can output part of the string by stating the starting point by using a subscript. The & specifies the address of name[1].

This example may make you feel that strings are rather cumbersome to use since you have to set up each character one at a time. That is an incorrect conclusion because strings are very easy to use as we will see in the next example program.

Some string subroutines

The next example [STRINGS.C] illustrates a few of the more common string handling functions. These functions are found in the C standard library and are defined in the header file string.h.

Module 815 Data Structures Using C

Page 813-5

#include "stdio.h" #include "string.h" void main( ) { char name1[12], name2[12], mixed[25]; char title[20];

strcpy(name1, "Rosalinda"); strcpy(name2, "Zeke"); strcpy(title,"This is the title."); printf(" %s\n\n" ,title); printf("Name 1 is %s\n", name1); printf("Name 2 is %s\n", name2); if(strcmp(name1,name2)>0) /* returns 1 if name1 > name2 */

strcpy(mixed,name1); else

strcpy(mixed,name2); printf("The biggest name alpabetically is %s\n" ,mixed); strcpy(mixed, name1); strcat(mixed," "); strcat(mixed, name2); printf("Both names are %s\n", mixed);

}

First, four stringsare defined. Next, a new function that is commonly found in C programs, the strcpy function, or string copy function is used. It copies from one string to another until it comes to the NULL character. Remember that the NULL is actually a 0 and is added to the character string by the system. It is easy to remember which one gets copied to which if you think of the function as an assignment statement. Thus if you were to say, for example, ‘x = 23;’, the data is copied from the right entity to the left one. In the strcpy function the data are also copied from the right entity to the left, so that after execution of the first statement, name1 will contain the string Rosalinda, but without the double quotes. The quotes define a literal string and are an indication to the compiler that the programmer is defining a string.

Similarly, Zeke is copied into name2 by the second statement, then the title is copied. Finally, the title and both names are printed out. Note that it is not necessary for the defined string to be exactly the same size as the string it will be called upon to store, only that it is at least as long as the string plus one more character for the NULL.

Alphabetical sorting of strings

The next function to be considered is the strcmp or the string compare function. It will return a 1 if the first string is lexicographically larger than the second, zero if they are the two strings are identical, and -1 if the first string is lexicographically smaller than the second. A lexicographical comparison uses the ASCII codes of the characters as the basis for comparison. Therefore, ‘A’ will be “smaller” than ‘Z’ because the ASCII code for ‘A’ is 65 whilst the code for ‘Z’ is 90. Sometimes however, strange results occur. A string that begins with the letter ‘a’ is larger than a string that begins with the letter ‘Z’ since the ASCII code for ‘a’ is 97 whilst the code for ‘Z’ is 90.

Module 815 Data Structures Using C

Page 813-6

One of the strings, depending on the result of the compare, is copied into the variable mixed, and therefore the largest name alphabetically is printed out. It should come as no surprise to you that Zeke wins because it is alphabetically larger: length doesn’t matter, only the ASCII code values of the characters.

Combining strings

The last four statements in the [STRINGS.C] example have another new feature, the strcat, or string concatenation function. This function simply adds the characters from one string onto the end of another string taking care to adjust the NULL so a single string is produced. In this case, name1 is copied into mixed, then two blanks are concatenated to mixed, and finally name2 is concatenated to the combination. The result is printed out which shows both names stored in the one variable called mixed.

Exercise 1

Write a program with three short strings, about 6 characters each, and use strcpy to copy one, two, and three into them. Concatenate the three strings into one string and print the result out 10 times.

Write a program thatwill output the characters of a string backwards. For example, given the string “computer”, the program will produce

Module 815 Data Structures Using C

Page 813-7

Objective 2 After working through this module you should be able to declare and manipulate single and multi-dimensional arrays of the C data types.

ARRAYS

The last objective discussed the structure of strings which are really special cases of an array. Arrays are a data type that are used to represent a large number of homogeneous values, that is values that are all of the one data type. The data type could be of type char, in which case we have a string. The data type could just as easily be of type int, float or even another array.

An array of integers

The next program [INTARRAY.C] is a short example of using an array of integers.

#include "stdio.h" void main( ) { int values[12]; int index;

for (index = 0;index < 12; index++) values[index] = 2 * (index + 4);

for (index = 0;index < 12; index++) printf("The value at index = %2d is %3d\n", index, values[index]);

}

Notice that the array is defined in much the same way we defined an array of char in order to do the string manipulations in the last section. We have 12 integer variables to work with not counting the one named index. The names of the variables are values[0], values[1], ... , and values[11]. Next we have a loop to assign nonsense, but well defined, data to each of the 12 variables, then print all 12 out. Note carefully that each element of the array is simply an int type variable capable of storing an integer. The only difference between the variables index and values[2], for example, is in the way that you address them. You should have no trouble following this program, but be sure you understand it. Compile and run it to see if it does what you expect it to do.

An array of floating point data

Now for an example of a program [BIGARRAY.C] with an array of float type data. This program also has an extra feature to illustrate how strings can be initialised.

#include "stdio.h" #include "string.h" char name1[ ] = "First Program Title"; void main( ) { int index; int stuff[12];

Module 815 Data Structures Using C

Page 813-8

float weird[12]; static char name2[] = "Second Program Title";

for (index = 0; index < 12; index++) { stuff[index] = index + 10; weird[index] = 12.0 * (index + 7);

} printf("%s\n", name1); printf("%s\n\n", name2); for (index = 0; index < 12; index++)

printf("%5d %5d %10.3f\n", index, stuff[index], weird[index]); }

The first line of the program illustrates how to initialise a string of characters. Notice that the square brackets are empty, leaving it up to the compiler to count the characters and allocate enough space for our string including the terminating NULL. Another string is initialised in the body of the program but it must be declared static here. This prevents it from being allocated as an automatic variable and allows it to retain the string once the program is started. You can think of a staic declaration as a local constant.

There is nothing else new here, the variables are assigned nonsense data and the results of all the nonsense are printed out along with a header. This program should also be easy for you to follow, so study it until you are sure of what it is doing before going on to the next topic.

Getting data back from a function

The next program [PASSBACK.C] illustrates how a function can manipulate an array as a variable parameter.

#include "stdio.h" void main( ) { int index; int matrix[20];

/* generate data */ for (index = 0 ;index < 20; index++)

matrix[index] = index + 1; /* print original data */ for (index = 0; index < 5 ;index++)

printf("Start matrix[%d] = %d\n", index, matrix[index]); /* go to a function & modify matrix */ dosome(matrix); /* print modified matrix */ for (index = 0; index < 5 ;index++)

printf("Back matrix[%d] = %d\n", index, matrix[index]); }

dosome(list) /* This will illustrate returning data */ int list[ ]; { int i;

/* print original matrix */ for (i = 0;i < 5; i++)

printf("Before matrix[%d] = %d\n", i list[i]); /* add 10 to all values */ for (i = 0; i < 20; i++)

list[i] += 10; /* print modified matrix */ for (i = 0; i < 5; i++)

printf("After matrix[%d] = %d\n", i, list[i]);

Module 815 Data Structures Using C

Page 813-9

}

An array of 20 variables named matrix is defined, some nonsense data is assigned to the variables, and the first five values are printed out. Then we call the function dosome taking along the entire array as a parameter.

The function dosome has a name in its parentheses also but it uses the local name ‘list’ for the array. The function needs to be told that it is really getting an array passed to it and that the array is of type int. Line 20 does that by defining list as an integer type variable and including the square brackets to indicate an array. It is not necessary to tell the function how many elements are in the array, but you could if you so desired. Generally a function works with an array until some end-of- data marker is found, such as a NULL for a string, or some other previously defined data or pattern. Many times, another piece of data is passed to the function with a count of how many elements to work with. In our present illustration, we will use a fixed number of elements to keep it simple.

So far nothing is different from the previous functions we have called except that we have passed more data points to the function this time than we ever have before, having passed 20 integer values. We print out the first 5 again to see if they did indeed get passed here. Then we add ten to each of the elements and print out the new values. Finally we return to the main program and print out the same 5 data points. We find that we have indeed modified the data in the function, and when we returned to the main program, we brought the changes back. Compile and run this program to verify this conclusion.

Arrays pass data both ways

It was stated during our study of functions that when data was passed to a function, the system made a copy to use in the function which was thrown away when we returned. This is not the case with arrays. The actual array is passed to the function and the function can modify it any way it wishes to. The result of the modifications will be available back in the calling program. This may seem strange (that arrays are handled differently from single point data) but it is correct. The reason is that when an array is passed to a function, the address of (or a pointer to) the function is the piece of data that is used. The is analagous to the Pascal construct of placing a VAR in front of a parameter in a procedure definition.

Multiple-dimensional arrays

Arrays need not be one-dimensional as the last three examples have shown, but can have any number of dimensions. Most arrays usually have either one or two dimensions. Higher dimesions have applications

Module 815 Data Structures Using C

Page 813-10

in mathematics but are rarely used in data processing environments. The use of doubly-dimensioned arrays is illustrated in the next program [MULTIARAY.C].

#include "stdio.h" void main( ) { int i, j; int big[8][8], large[25][12];

/* Create big as a a multiplication table */ for (i = 0; i < 8; i++)

for (j = 0; j < 8; j++) big[i][j] = i * j;

/* Create large as an addition table */ for (i = 0; i < 25; i++)

for (j = 0; j < 12; j++) large[i][j] = i + j;

big[2][6] = large[24][10] * 22; big[2][2] = 5; big[big[2][2]][big[2][2]] = 177;

/* this is big[5][5] = 177; */

for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++)

printf("%5d ", big[i][j]); printf("\n"); /* newline for each increase in i */

} }

The variable big is an 8 by 8 array that contains 8 times 8 or 64 elements in total. The first element is big[0][0], and the last is big[7][7]. Another array named large is also defined which is not square to illustrate that the array need not be square! Both are filled up with data, one representing a multiplication table and the other being formed into an addition table.

To illustrate that individual elements can be modified at will, one of the elements of big is assigned the value from one of the elements of large after being multiplied by 22. Next, big[2][2] is assigned the arbitrary value of 5, and this value is used for the subscripts of the next assignment statement. The third assignment statement is in reality big[5][5] = 177 because each of the subscripts contain the value 5. This is only done to demonstrate that any valid expression can be used for a subscript. It must only meet two conditions: it must be an integer (although a char will work just as well), and it must be within the range of the subscript for which it is being used.

The entire matrix variable big is printed out in a square form so you can check the values to see if they were set the way you expected them to be. You will find many opportunities to use arrays, so do not underestimate the importance of the material in this section.

Module 815 Data Structures Using C

Page 813-11

Exercise 2

Define two integer arrays, each 10 elements long, called array1 and array2. Using a loop, put some kind of nonsense data in each and add them term for term into another 10 element array named arrays. Finally, print all results in a table with an index number, for example

1 2 + 10 = 12 2 4 + 20 = 24 3 6 + 30 = 36 etc.

Hint: the print statement will be similar to this:

printf("%4d %4d + %4d = %4d\n", index, array1[index], array2[index], arrays[index]);

Module 815 Data Structures Using C

Page 813-12

Objective 3 After working through this module you should be able to create manipulate and manage C pointers to data elements.

Pointers

Simply stated, a pointer is an address. Instead of being a variable, it is a pointer to a variable stored somewhere in the address space of the program. It is always best to use an example, so examine the next program [POINTER.C] which has some pointers in it.

#include "stdio.h" /* illustration of pointer use */ void main( ) { int index, *pt1, *pt2;

index = 39; /* any numerical value */ pt1 = &index; /* the address of index */ pt2 = pt1; printf("The value is %d %d %d\n", index, *pt1, *pt2); *pt1 = 13; /* this changes the value of index */ printf("The value is %d %d %d\n", index, *pt1, *pt2);

}

Ignore for the moment the data declaration statement where we define index and two other fields beginning with an star. (It is properly called an asterisk, but for reasons we will see later, let’s agree to call it a star.) If you observe the first statement, it should be clear that we assign the value of 39 to the variable index; this is no surprise. The next statement, however, says to assign to pt1 a strange looking value, namely the variable index with an ampersand (&) in front of it. In this example, pt1 and pt2 are pointers, and the variable index is a simple variable.

Now we have a problem. We need to learn how to use pointers in a program, but to do so requires that first we define the means of using the pointers in the program!

Two very important rules

The following two rules are very important when using pointers and must be thoroughly understood. They may be somewhat confusing to you at first but we need to state the definitions before we can use them. Take your time, and the whole thing will clear up very quickly.

1. A variable name with an ampersand (&) in front of it defines the address of the variable and therefore points to the variable. You can therefore read line 7 as ‘pt1 is assigned the value of the address

2. A pointer with a star in front of it refers to the value of the variable pointed to by the pointer. Line 10 of the program can be read as ‘The stored (starred) value to which the pointer pt1 points is

Module 815 Data Structures Using C

Page 813-13

assigned the value 13’. Now you can see why it is perhaps convenient to think of the asterisk as a star,: it sort of sounds like the word ‘store’!

Memory aids 1. Think of & as an address.

2. Think of * as a star referring to stored.

Assume for the moment that pt1 and pt2 are pointers (we will see how to define them shortly). As pointers they do not contain a variable value but an address of a variable and can be used to point to a variable. Line 7 of the program assigns the pointer pt1 to point to the variable we have already defined as index because we have assigned the address of index to pt1. Since we have a pointer to index, we can manipulate the value of index by using either the variable name itself, or the pointer.

Line 10 modifies the value by using the pointer. Since the pointer pt1 points to the variable index, then putting a star in front of the pointer name refers to the memory location to which it is pointing. Line 10 therefore assigns to index the value of 13. Anywhere in the program where it is permissible to use the variable name index, it is also permissible to use the name *pt1 since they are identical in meaning until the pointer is reassigned to some other variable.

Just to add a little intrigue to the system, we have another pointer defined in this program, pt2. Since pt2 has not been assigned a value prior to line 8, it doesn’t point to anything, it contains garbage. Of course, that is also true of any variable until a value is assigned to it. Line 8 assigns pt2 the same address as pt1, so that now pt2 also points to the variable index. So to continue the definition from the last paragraph, anywhere in the program where it is permissible to use the variable index, it is also permissible to use the name *pt2 because they are identical in meaning. This fact is illustrated in the first printf statement since this statement uses the three means of identifying the same variable to print out the same variable three times.

Note carefully that, even though it appears that there are three variables, there is really only one variable. The two pointers point to the single variable. This is illustrated in the next statement which assigns the value of 13 to the variable index, because that is where the pointer pt1 is pointing. The next printf statement causes the new value of 13 to be printed out three times. Keep in mind that there is really only one variable to be changed, not three.

This is admittedly a difficult concept, but since it is used extensively in all but the most trivial C programs, it is well worth your time to stay with this material until you understand it thoroughly.

Module 815 Data Structures Using C

Page 813-14

Declaring a pointer

Refer to the fifth line of the program and you will see the familiar way of defining the variable index, followed by two more definitions. The second definition can be read as the storage location to which pt1 points will be an int type variable. Therefore, pt1 is a pointer to an int type variable. Similarly, pt2 is another pointer to an int type variable.

A pointer must be defined to point to some type of variable. Following a proper definition, it cannot be used to point to any other type of variable or it will result in a type incompatibility error. In the same manner that a float type of variable cannot be added to an int type variable, a pointer to a float variable cannot be used to point to an integer variable.

Compile and run this program and observe that there is only one variable and the single statement in line 10 changes the one variable which is displayed three times.

A second pointer program

Consider the next program [POINTER2.C], which illustrates some of the more complex operations that are used in C programs:

#include "stdio.h" void main( ) { char strg[40],*there,one,two; int *pt,list[100],index;

strcpy(strg,"This is a character string."); one = strg[0]; /* one and two are identical */ two = *strg; printf("The first output is %c %c\n", one, two); one = strg[8]; /* one and two are indentical */ two = *(strg+8); printf("the second output is %c %c\n", one, two); there = strg+10; /* strg+10 is identical to strg[10] */ printf("The third output is %c\n", strg[10]); printf("The fourth output is %c\n", *there); for (index = 0; index < 100; index++)

list[index] = index + 100; pt = list + 27; printf("The fifth output is %d\n", list[27]); printf("The sixth output is %d\n", *pt);

}

In this program we have defined several variables and two pointers. The first pointer named there is a pointer to a char type variable and the second named pt points to an int type variable. Notice also that we have defined two array variables named strg and list. We will use them to show the correspondence between pointers and array names.

Module 815 Data Structures Using C

Page 813-15

String variables as pointers

In C a string variable is defined to be simply a pointer to the beginning of a string – this will take some explaining. You will notice that first we assign a string constant to the string variable named strg so we will have some data to work with. Next, we assign the value of the first element to the variable one, a simple char variable. Next, since the string name is a pointer by definition, we can assign the same value to two by using the star and the string name. The result of the two assignments are such that one now has the same value as two, and both contain the character ‘T’, the first character in the string. Note that it would be incorrect to write the ninth line as two = *strg[0]; because the star takes the place of the square brackets.

For all practical purposes, strg is a pointer. It does, however, have one restriction that a true pointer does not have. It cannot be changed like a variable, but must always contain the initial value and therefore always points to its string. It could be thought of as a pointer constant, and in some applications you may desire a pointer that cannot be corrupted in any way. Even though it cannot be changed, it can be used to refer to other values than the one it is defined to point to, as we will see in the next section of the program.

Moving ahead to line 9, the variable one is assigned the value of the ninth variable (since the indexing starts at zero) and two is assigned the same value because we are allowed to index a pointer to get to values farther ahead in the string. Both variables now contain the character ‘a’.

The C compiler takes care of indexing for us by automatically adjusting the indexing for the type of variable the pointer is pointing to.(This is why the data type of a variable must be declared before the variable is used.) In this case, the index of 8 is simply added to the pointer value before looking up the desired result because a char type variable is one byte long. If we were using a pointer to an int type variable, the index would be doubled and added to the pointer before looking up the value because an int type variable uses two bytes per value stored. When we get to the section on structures, we will see that a variable can have many, even into the hundreds or thousands, of bytes per variable, but the indexing will be handled automatically for us by the system.

Since there is already a pointer, it can be assigned the address of the eleventh element of strg by the statement in line 12 of the program. Remember that since there is a true pointer, it can be assigned any value as long as that value represents a char type of address. It should be clear that the pointers must be typed in order to allow the pointer arithmetic described in the last paragraph to be done properly. The third and fourth outputs will be the same, namely the letter ‘c’.

Module 815 Data Structures Using C

Page 813-16

Pointer arithmetic

Not all forms of arithmetic are permissible on a pointer: only those things that make sense. Considering that a pointer is an address somewhere in the computer, it would make sense to add a constant to an address, thereby moving it ahead in memory that number of places. Similarly, subtraction is permissible, moving it back some number of locations. Adding two pointers together would not make sense because absolute memory addresses are not additive. Pointer multiplication is also not allowed, as that would be a ‘funny’ number. If you think about what you are actually doing, it will make sense to you what is allowed, and what is not.

Integer pointers

The array named list is assigned a series of values from 100 to 199 in order to have some data to work with. Next we assign the pointer pt the address of the 28th element of the list and print out the same value both ways to illustrate that the system truly will adjust the index for the int type variable. You should spend some time in this program until you feel you fairly well understand these lessons on pointers.

Function data return with a pointer

You may recall that back in the objective dealing with functions it was mentioned that a function could use variable data if the parameter was declared as an array. This works because an array is really a pointer to the array elements. Functons can manipulate variable data if that data is passed to the function as a pointer. The following program [TWOWAY.C] illustrates the general approach used to manipulate variable data in a function.

#include "stdio.h" void fixup(nuts,fruit); /* prototype the function */

void main( ) { int pecans,apples;

pecans = 100; apples = 101; printf("The starting values are %d %d\n",pecans,apples); fixup(pecans,&apples);

/* when we call "fixup" we send the value */ /* of pecans and the address of apples */

printf("The ending values are %d %d\n", pecans, apples); }

fixup(nuts,fruit) /* nuts is an integer value */ int nuts,*fruit; /* fruit points to an integer */ {

printf("The values are %d %d\n", nuts, *fruit); nuts = 135; *fruit = 172; printf("The values are %d %d\n", nuts ,*fruit);

}

Module 815 Data Structures Using C

Page 813-17

There are two variables defined in the main program: pecans and apples; notice that neither of these is defined as a pointer. We assign values to both of these and print them out, then call the function fixup taking with us both of these values. The variable pecans is simply sent to the function, but the address of the variable apples is sent to the function. Now we have a problem. The two arguments are not the same, the second is a pointer to a variable. We must somehow alert the function to the fact that it is supposed to receive an integer variable and a pointer to an integer variable. This turns out to be very simple. Notice that the parameter definitions in the function define nuts as an integer, and fruit as a pointer to an integer. The call in the main program therefore is now in agreement with the function heading and the program interface will work just fine.

In the body of the function, we print the two values sent to the function, then modify them and print the new values out. The surprise occurs when we return to the main program and print out the two values again. We will find that the value of pecans will be restored to its value before the function call because the C language made a copy of the variable pecans and takes the copy to the called function, leaving the original intact. In the case of the variable apples, we made a copy of a pointer to the variable and took the copy of the pointer to the function. Since we had a pointer to the original variable, even though the pointer was a copy, we had access to the original variable and could change it in the function. When we returned to the main program, we found a changed value in apples when we printed it out.

By using a pointer in a function call, we can have access to the data in the function and change it in such a way that when we return to the calling program, we have a changed value for the data. It must be pointed out however, that if you modify the value of the pointer itself in the function, you will have a restored pointer when you return because the pointer you use in the function is a copy of the original. In this example, there was no pointer in the main program because we simply sent the address to the function, but in many programs you will use pointers in function calls.

Compile and run the program and observe the output.

Programming Exercises

Define a character array and use strcpy to copy a string into it. Print the string out by using a loop with a pointer to print out one character at a time. Initialise the pointer to the first element and use the double plus sign to increment the pointer. Use a separate integer variable to count the characters to print.

Module 815 Data Structures Using C

Page 813-18

Modify the program to print out the string backwards by pointing to the end and using a decrementing pointer.

Module 815 Data Structures Using C

Page 813-19

Objective 4 After working through this module you should be able to create and manage complex data types in C.

STRUCTURES

A structure is a user-defined data type. You have the ability to define a new type of data considerably more complex than the types we have been using. A structure is a collection of one or more variables, possibly of different types, grouped together under a single name for convenient handling. Structures are called “records” in some languages, notably Pascal. Structures help organise complicated data, particularly in large programs, because they permit a group of related variables to be treated as a unit instead of as separate entities.

The best way to understand a structure is to look at an example [STRUCT1.C].

#include "stdio.h" void main( ) { struct {

char initial; /* last name initial */ int age; /* childs age */ int grade; /* childs grade in school */ } boy, girl;

boy.initial = 'R'; boy.age = 15; boy.grade = 75; girl.age = boy.age - 1; /* she is one year younger */ girl.grade = 82; girl.initial = 'H'; printf("%c is %d years old and got a grade of %d\n",

girl.initial, girl.age, girl.grade); printf("%c is %d years old and got a grade of %d\n",

boy.initial, boy.age, boy.grade); }

The program begins with a structure definition. The key word struct is followed by some simple variables between the braces, which are the components of the structure. After the closing brace, you will find two variables listed, namely boy, and girl. According to the definition of a structure, boy is now a variable composed of three elements: initial, age, and grade. Each of the three fields are associated with boy, and each can store a variable of its respective type. The variable girl is also a variable containing three fields with the same names as those of boy but are actually different variables. We have therefore defined 6 simple variables.

A single compound variable

Let’s examine the variable boy more closely. As stated above, each of the three elements of boy are simple variables and can be used anywhere in a C program where a variable of their type can be used. For example,

Module 815 Data Structures Using C

Page 813-20

the age element is an integer variable and can therefore be used anywhere in a C program where it is legal to use an integer variable: in calculations, as a counter, in I/O operations, etc. The only problem we have is defining how to use the simple variable age which is a part of the compound variable boy. We use both names with a decimal point between them with the major name first. Thus boy.age is the complete variable name for the age field of boy. This construct can be used anywhere in a C program that it is desired to refer to this field. In fact, it is illegal to use the name boy or age alone because they are only partial definitions of the complete field. Alone, the names refer to nothing.

Assigning values to the variables

Using the above definition, we can assign a value to each of the three fields of boy and each of the three fields of girl. Note carefully that boy.initial is actually a char type variable, because it was assigned that in the structure, so it must be assigned a character of data. Notice that boy.initial is assigned the character R in agreement with the above rules. The remaining two fields of boy are assigned values in accordance with their respective types. Finally the three fields of girl are assigned values but in a different order to illustrate that the order of assignment is not critical.

Using structure data

Now that we have assigned values to the six simple variables, we can do anything we desire with them. In order to keep this first example simple, we will simply print out the values to see if they really do exist as assigned. If you carefully inspect the printf statements, you will see that there is nothing special about them. The compound name of each variable is specified because that is the only valid name by which we can refer to these variables.

Structures are a very useful method of grouping data together in order to make a program easier to write and understand. This first example is too simple to give you even a hint of the value of using structures, but continue on through these lessons and eventually you will see the value of using structures.

An array of structures

The next program [STRUCT2.C] contains the same structure definition as before but this time we define an array of 12 variables named kids. This program therefore contains 12 times 3 = 36 simple variables, each of which can store one item of data provided that it is of the correct type. We also define a simple variable named index for use in the for loops.

Module 815 Data Structures Using C

Page 813-21

#include "stdio.h" void main( ) { struct {

char initial; int age; int grade; } kids[12];

int index; for (index = 0; index < 12; index++) {

kids[index].initial = 'A' + index; kids[index].age = 16; kids[index].grade = 84;

} kids[3].age = kids[5].age = 17; kids[2].grade = kids[6].grade = 92; kids[4].grade = 57; kids[10] = kids[4]; /* Structure assignment */ for (index = 0; index < 12; index++)

printf("%c is %d years old and got a grade of %d\n", kids[index].initial, kids[index].age,

kids[index].grade); }

To assign each of the fields a value we use a for loop and each pass through the loop results in assigning a value to three of the fields. One pass through the loop assigns all of the values for one of the kids. This would not be a very useful way to assign data in a real situation, but a loop could read the data in from a file and store it in the correct fields. You might consider this the crude beginning of a data base – which, of course, it is.

In the next few instructions of the program we assign new values to some of the fields to illustrate the method used to accomplish this. It should be self explanatory, so no additional comments will be given.

Copying structures

C allows you to copy an entire structure with one statement. Line 17 is an example of using a structure assignment. In this statement, all 3 fields of kids[4] are copied into their respective fields of kids[10].

The last few statements contain a for loop in which all of the generated values are displayed in a formatted list. Compile and run the program to see if it does what you expect it to do.

Using pointers and structures together

The next program [STRUCT3.C] is an example of using pointers with structures; it is identical to the last program except that it uses pointers for some of the operations.

#include "stdio.h" void main( ) { struct {

char initial; int age;

Module 815 Data Structures Using C

Page 813-22

int grade; } kids[12], *point, extra;

int index; for (index = 0; index < 12; index++) {

point = kids + index; point->initial = 'A' + index; point->age = 16; point->grade = 84;

} kids[3].age = kids[5].age = 17; kids[2].grade = kids[6].grade = 92; kids[4].grade = 57; for (index = 0; index < 12; index++) {

point = kids + index; printf("%c is %d years old and got a grade of %d\n",

(*point).initial, kids[index].age, point->grade); } extra = kids[2]; /* Structure assignment */ extra = *point; /* Structure assignment */

}

The first difference shows up in the definition of variables following the structure definition. In this program we define a pointer named point which is defined as a pointer that points to the structure. It would be illegal to try to use this pointer to point to any other variable type. There is a very definite reason for this restriction in C as we have alluded to earlier and will review in the next few paragraphs.

The next difference is in the for loop where we use the pointer for accessing the data fields. Since kids is a pointer variable that points to the structure, we can define point in terms of kids. The variable kids is a constant so it cannot be changed in value, but point is a pointer variable and can be assigned any value consistent with its being required to point to the structure. If we assign the value of kids to point then it should be clear that it will point to the first element of the array, a structure containing three fields.

Pointer arithmetic

Adding 1 to point will now cause it to point to the second field of the array because of the way pointers are handled in C. The system knows that the structure contains three variables and it knows how many memory elements are required to store the complete structure. Therefore if we tell it to add one to the pointer, it will actually add the number of memory elements required to get to the next element of the array. If, for example, we were to add 4 to the pointer, it would advance the value of the pointer 4 times the size of the structure, resulting in it pointing 4 elements farther along the array. This is the reason a pointer cannot be used to point to any data type other than the one for which it was defined.

Now return to the program. It should be clear from the previous discussion that as we go through the loop, the pointer will point to the beginning of one of the array elements each time. We can therefore use

Module 815 Data Structures Using C

Page 813-23

the pointer to reference the various elements of the structure. Referring to the elements of a structure with a pointer occurs so often in C that a special method of doing that was devised. Using point->initial is the same as using (*point).initial which is really the way we did it in the last two programs. Remember that *point is the stored data to which the pointer points and the construct should be clear. The -> is made up of the minus sign and the greater than sign.

Since the pointer points to the structure, we must once again define which of the elements we wish to refer to each time we use one of the elements of the structure. There are, as we have seen, several different methods of referring to the members of the structure, and in the for loop used for output at the end of the program, we use three different methods. This would be considered very poor programming practice, but is done this way here to illustrate to you that they all lead to the same result. This program will probably require some study on your part to fully understand, but it will be worth your time and effort to grasp these principles.

Nested and named structures

The structures we have seen so far have been useful, but very simple. It is possible to define structures containing dozens and even hundreds or thousands of elements but it would be to the programmer’s advantage not to define all of the elements at one pass but rather to use a hierarchical structure of definition. This will be illustrated with the next program [NESTED.C], which shows a nested structure.

#include "stdio.h" void main( ) { struct person {

char name[25]; int age; char status; /* M = married, S = single */

} ; struct alldat {

int grade; struct person descrip; char lunch[25];

} student[53]; struct alldat teacher,sub; teacher.grade = 94; teacher.descrip.age = 34; teacher.descrip.status = 'M'; strcpy(teacher.descrip.name,"Mary Smith"); strcpy(teacher.lunch,"Baloney sandwich"); sub.descrip.age = 87; sub.descrip.status = 'M'; strcpy(sub.descrip.name,"Old Lady Brown"); sub.grade = 73; strcpy(sub.lunch,"Yogurt and toast"); student[1].descrip.age = 15; student[1].descrip.status = 'S'; strcpy(student[1].descrip.name,"Billy Boston"); strcpy(student[1].lunch,"Peanut Butter"); student[1].grade = 77;

comments (0)
no comments were posted
be the one to write the first!
This is only a preview
3 shown on 47 pages
Download the document