Introduction to Computer Science by Huong Nguyen - HTML preview

PLEASE NOTE: This is an HTML preview only and some elements such as links or page numbers may be incorrect.
Download the book in PDF, ePub, Kindle for a complete version.

// Arguments: The number of rows, the number of columns, and the matrix.

// Return value: The value of the greatest element.

double maximum( int nrows, int ncols, double matrix[nrows][ncols] )

{

double max = matrix[0][0];

for ( int r = 0; r < nrows; ++r )

for ( int c = 0; c < ncols; ++c )

if ( max < matrix[r][c] )

max = matrix[r][c];

return max;

}

The parameter matrix is a pointer to an array with ncols elements.

Pointers as Function Parameters

Since C passes arguments to functions by value, there is no direct way for the called function to

alter a variable in the calling function. For instance, a sorting routine might exchange two out-of-

order arguments with a function called swap. It is not enough to write

swap(a, b);

where the swap function is defined as

void swap(int x, int y) /* WRONG */

{

int temp;

temp = x;

x = y;

y = temp;

}

Because of call by value, swap can't affect the arguments a and b in the routine that called it. The function above swaps copies of a and b.

The way to obtain the desired effect is for the calling program to pass pointers to the values to be

index-153_1.jpg

changed:

swap(&a, &b);

Since the operator & produces the address of a variable, &a is a pointer to a. In swap itself, the parameters are declared as pointers, and the operands are accessed indirectly through them.

void swap(int *px, int *py) /* interchange *px and *py */

{

int temp;

temp = *px;

*px = *py;

*py = temp;

}

{

Pictorially in Figure 2.18

Figure 2.18.

swap function with pointer parameters

2.6. Strings*

Basic of strings

A string is a continuous sequence of characters terminated by '\0', the null character. The length of a string is considered to be the number of characters excluding the terminating null character.

There is no string type in C, and consequently there are no operators that accept strings as

operands.

Instead, strings are stored in arrays whose elements have the type char or wchar_t. Strings of wide characters that is, characters of the type wchar_tare also called wide strings. The C standard library provides numerous functions to perform basic operations on strings, such as comparing,

copying, and concatenating them.

Declarations and Uses of Strings

You can initialize arrays of char or wchar_t using string literals. For example, the following two

array definitions are equivalent:

char str1[30] = "Let's go"; // String length: 8; array length: 30.

char str1[30] = { 'L', 'e', 't', '\'', 's',' ', 'g', 'o', '\0' };

An array holding a string must always be at least one element longer than the string length to

accommodate the terminating null character. Thus the array str1 can store strings up to a

maximum length of 29. It would be a mistake to define the array with length 8 rather than 30,

because then it wouldn't contain the terminating null character.

If you define a character array without an explicit length and initialize it with a string literal, the array created is one element longer than the string length. An Example

char str2[ ] = " to London!";// String length: 11 (note leading space);

// array length: 12.

The following statement uses the standard function strcat() to append the string in str2 to the string in str1. The array str1 must be large enough to hold all the characters in the concatenated

string.

#include <string.h>

char str1[30] = "Let's go";

char str2[ ] = " to London!";

/* ... */

strcat( str1, str2 );

puts( str1 );

The output printed by the puts() call is the new content of the array str1:

Let's go to London!

The names str1 and str2 are pointers to the first character of the string stored in each array. Such a pointer is called a pointer to a string, or a string pointer for short. String manipulation functions such as strcat() and puts() receive the beginning addresses of strings as their arguments. Such functions generally process a string character by character until they reach the terminator, '\0'. The function in is one possible implementation of the standard function strcat(). It uses pointers to step through the strings referenced by its arguments.

Built-in Functions for Character and String Processing

Character Processing Functions

The standard library provides a number of functions to classify characters and to perform

conversions on them. The header ctype.h declares such functions for byte characters, with

character codes from 0 to 255.

The results of these functions, except for isdigit() and isxdigit(), depends on the current locale setting for the locale category LC_CTYPE. You can query or change the locale using the

setlocale() function.

Character Classification Functions

The functions listed in Table 2.22 test whether a character belongs to a certain category. Their return value is nonzero, or true, if the argument is a character code in the given category.

Table 2.22. Character classification functions

Category

Functions

Letters

isalpha( )

Lowercase letters

islower( )

Uppercase letters

isupper( )

Decimal digits

isdigit( )

Hexadecimal digits

isxdigit( )

Letters and decimal digits

isalnum( )

Printable characters (including whitespace)

isprint( )

Printable, non-whitespace characters

isgraph( )

Whitespace characters

isspace( )

Whitespace characters that separate words in a line of text isblank( )

Punctuation marks

ispunct( )

Control characters

iscntrl( )

The functions isgraph() and iswgraph() behave differently if the execution character set contains other byte-coded, printable, whitespace characters (that is, whitespace characters which are not

control characters) in addition to the space character (' '). In that case, iswgraph() returns false for all such printable whitespace characters, while isgraph() returns false only for the space character (' ').

Case Mapping Functions

The functions listed in Table 2.23 yield the uppercase letter that corresponds to a given lowercase letter, and vice versa. All other argument values are returned unchanged.

Table 2.23. Character conversion functions

Conversion

Functions in ctype.h

Upper- to lowercase tolower( )

Lower- to uppercase toupper( )

String Processing Functions

A string is a continuous sequence of characters terminated by '\0', the string terminator character.

The length of a string is considered to be the number of characters before the string terminator.

Strings are stored in arrays whose elements have the type char or wchar_t. Strings of wide

characters that is, characters of the type wchar_tare also called wide strings.

C does not have a basic type for strings, and hence has no operators to concatenate, compare, or

assign values to strings. Instead, the standard library provides numerous functions, listed in

Table 2.24 to perform these and other operations with strings. The header string.h declares the functions for conventional strings of char. The names of these functions begin with str.

Like any other array, a string that occurs in an expression is implicitly converted into a pointer to its first element. Thus when you pass a string as an argument to a function, the function receives

only a pointer to the first character, and can determine the length of the string only by the position of the string terminator character.

Table 2.24. String-processing functions

Purpose

Functions

Find the length of a string.

strlen( )

strcpy( ),

Copy a string.

strncpy( )

strcat( ),

Concatenate strings.

strncat( )

strcmp( ),

Compare strings.

strncmp( ),

strcoll( )

Transform a string so that a comparison of two transformed strings using strcmp(

) yields the same result as a comparison of the original strings using the locale-

strxfrm( )

sensitive function strcoll( ).

In a string, find:

strchr( ),

- The first or last occurrence of a given character

strrchr( )

- The first occurrence of another string

strstr( )

strcspn( ),

- The first occurrence of any of a given set of characters

strpbrk( )

- The first character that is not a member of a given set

strspn( )

Parse a string into tokens

strtok( )

Example 2.13.

#include <stdio.h>

#include <conio.h>

#include <string.h> // You must declare the library string.h

// to use functions strcpy, strcmp...

void main()

{

char str1[10] = “abc”;

char str2[10] = “def”;

clrscr();

printf(“ str1: %s”,str1);

printf(“\n str2: %s”,str2);

printf(“\n strcmp(str1,str2) = %d”,strcmp(str1,str2));

printf(“\n strcat(str1,str2) = %s”,strcat(str1,str2));

printf(“\n str1: %s”,str1);

printf(“\n str2: %s”,str2);

printf(“\n strcpy(str1,str2) = %s”,strcpy(str1,str2));

printf(“\n str1: %s”,str1);

printf(“\n str2: %s”,str2);

strcpy(str1,”ab”);

strcpy(str2,”abc”);

printf(“\n strcmp(str1,str2) = %d”,strcmp(str1,str2));

getch();

}

here is the sample session with the above program

str1: abc

str2: def

strcmp(str1,str2) = -3

strcat(str1,str2) = abcdef

str1: abcdef

str2: def

strcpy(str1,str2) = def

str1: def

str2: def

strcmp(str1,str2) = -3

2.7. Structures*

Introduction

A structure type can contain a number of dissimilar data objects within it. Unlike a simple

variable (which contains only one data object) or an array (which, although it contains more than

one data item, only contains items of a single data type),a structure is a collection of related data of different types. a name, for example, might be array of characters, an age might be integer. A

structure representing a person, say, could contain both a name and an age, each represented in the

appropriate format.

Declarations and Usage of Structures

Until now, all the data that we have dealt with has been either of a basic type such as char, int and double…, or an array of those types. However, there are many situations in real life where a data

item needs to be made up from other more basic types. We could do this with an array if the

constituent types were all the same, but often they are different. For example, suppose we want to

record the details of each student in a class. The detail of each student might be as follow:

A unique student number, which could be represented as a string (an array of char).

The student’s name, which could be represented as a string (an array of char).

Final mark for the Introduction to computer science course, which is a floating point value (a

float).

Creating Structures as New Data Types

The definition of a structure type begins with the keyword struct, and contains a list of

declarations of the structure's members, in braces:

struct structTag

{

<list of members>;

};

Definition ends with semicolon (;)

Example 2.14.

The three components above can be placed in a structure declared like this:

struct Student

{

char StudentID[10];

char name[30];

float markCS ;

};

The keyword struct introduces a structure declaration, which is a list of declarations enclosed in braces. An optional name called a structure tag may follow the word struct (as with Student here).

The tag names this kind of structure, and can be used subsequently as a shorthand for the part of

the declaration in braces. The variables named in a structure are called members. A structure

member or tag and an ordinary (i.e., non-member) variable can have the same name without

conflict, since they can always be distinguished by context. Furthermore, the same member names

may occur in different structures, although as a matter of style one would normally use the same

names only for closely related objects.

Creating variable of a struct type

Structure types are not considered a variable declaration, just definition of a new type, so they

cannot store anything until we declare variable of this type. Here is how we would create:

type_name_of_struct name_of_variable;

Example 2.15.

Creating three variables a, b, c of the Student type:

Student a, b, c;

Creating an array of the Student type:

Student studentCS[50];

A member of a structure may have any desired complete type, including previously defined

structure types. They must not be variable-length arrays, or pointers to such arrays. For instance,

now we want to record more information of students, for example their date of birth, which

comprises the day, month and year. So first, let's start with the date, because that is a new type

that we may be able to use in a variety of situations. We can declare a new type for a Date thus: struct Date

{

int day;

int month;

int year;

};

We can now use this Date type, together with other types, as members of a Student type which we can declare as follows:

struct Student

{

char studentID[10];

char name[30];

float markCS ;

Date dateOfBirth;

};

Or

struct Student

{

char studentID[10];

char name[30];

float markCS;

struct Date {

int day;

int month;

int year;

} dateOfBirth;

};

We can also declare structured variables when we define the structure itself:

struct Student

{

char studentID[10];

char name[30];

float markCS ;

Date dateOfBirth;

} a, b, c;

C permits to declare untagged structures that enable us to declare structure variables without

defining a name for their structures. For example, the following structure definition declares the

variables a, b, c but omits the name of the structure:

struct

{

char studentID[10];

char name[30];

float markCS ;

Date dateOfBirth;

} a, b, c;

A structure type cannot contain itself as a member, as its definition is not complete until the

closing brace (}). However, structure types can and often do contain pointers to their own type.

Such self-referential structures are used in implementing linked lists and binary trees, for

example. The following example defines a type for the members of a singly linked list:

struct List

{ struct Student stu; // This record's data.

struct List *pNext; // A pointer to the next student.

};

Referencing Structure Members with the Dot Operator

Whenever we need to refer to the members of a structure, we normally use the dot operator.

For example, if we wanted to access the number member of newStudent we could do so as

follows:

newStudent.studentID

We can then access the member as if it were a normal variable. For instance, we can write to this

member as follows.

newStudent.studentID= “C0681008”;

We can also read from the member in a similar fashion.

printf("Student identification: %s", newStudent.studentID);

The following code outputs the contents of an Student structure.

printf("Student Details\n");

printf("Identification: %s\n", newStudent.studentID);

printf("Name: %s\n", newStudent.name);

printf("Mark: %.2f\n", newStudent.markCS);

printf("Date of Birth: %i/%i/%i\n",

newStudent.dateOfBirth.day,

newStudent.dateOfBirth.month,

newStudent.dateOfBirth.year

);

Suppose we wish to input the details of this employee from a user. We could do so as follows.

Student newStudent;

printf("Enter student identification: ");

scanf("%s", &newStudent.studentID);

printf("Enter student name: ");

fflush(stdin);gets(newStudent.name);

printf("Enter mark for Introduction to computer science course: ”);

scanf("%f", &newStudent.markCS);

printf("Enter birth date (dd/mm/yyyy): ");

scanf("%i/%i/%i",

&newStudent.dateOfBirth.day,

&newStudent.dateOfBirth.month,

&newStudent.dateOfBirth.year

);

Initializing Structure Variables

When we declare a new variable of a basic data type we can initialize its value at declaration. We

can also initialize structure variables at declaration as shown below.

Student newStudent = {

"C0681008",

"Cao Anh Huy",

8.50,

{1, 2, 1985}

};

Notice how we include the initialization values in curly brackets, just like when we initialize an

array. Furthermore, we include the values for any nested structure type (in this case the

dateOfBirth member is a nested structure), in a further set of curly brackets.

Copying Structure Variables

One of the most convenient features of structures is that we can copy them in a single assignment

operation. This is unlike an array, which must be copied item-by-item. The name of a structure

variable when it appears on its own represents the entire structure. If a structure contains an array as a member, that array is copied if the entire structure is copied.

Student newStudent1, newStudent2;

// Get the values for newStudent2

...

// Copy newStudent2's value to newStudent1

newStudent1 = newStudent2;

Comparing Values of Structures

We cannot compare structures in a single operation. If we wish to compare the values of two

structure variables, we need to compare each of their members.

Arrays of Structures

Just as we can have an array of basic data types, we can also have an array of structures. Suppose

that we created an array of Student structures as follows. We could then copy newStudent into each position in the array.

Student students[100];

Student newStudent;

int i;

for (i=0; i<100; i++)

{

// Get the values for newStudent

...

// Copy into the next position in the array

students[i] = newStudent;

}

Operations on Structures

Passing Structures to and from Functions

Structures can be passed to functions just like any other data type. Functions can also return

structures, just as they can return any basic type. Structures can be also be passed to functions by reference.

Just like passing variable of a basic data type, when we pass a structure as an argument to a

function, a copy is made of the entire structure. Structures are passed by value. We can easily take the code that output a student and put it into a function as follows.

void outputStudent(Student stu)

{

printf("Student Details\n");

printf("Identification: %s\n", stu.studentID);

printf("Name: %s\n", stu.name);

printf("Mark: %.2f\n, stu.markCS);

printf("Date of Birth: %i/%i/%i\n",

stu.dateOfBirth.day,

stu.dateOfBirth.month,

stu.dateOfBirth.year

);

}

If we had an array of 100 students and wanted to output them this would be straightforward:

Student students[100];

int i;

...

for (i=0; i<100; i++) {

outputStudent(students[i]);

}

We could similarly place the code to input a student into a function, but now we have a problem.

The function can return a structure of type Student as follows.

Student inputStudent()

{

Student tempStudent;

printf("Enter Student identification: ");

scanf("%s", &tempStudent.studentID);

printf("Enter Student name: ");

fflush(stdin);gets(tempStudent.name);

printf("Enter final mark: ");

scanf("%f", &tempStudent.markCS);

printf("Enter birth date (dd/mm/yyyy):");

scanf("%i/%i/%i",

&tempStudent.dateOfBirth.day,

&tempStudent.dateOfBirth.month,

&tempStudent.dateOfBirth.year

);

return tempStudent;

}

In the example above we are filling the structure variable tempStudent with values. At the end of the function, the value of tempStudent is returned as the return value of the function. The code to input 100 students can now be modified to use this function:

Student students[100];

int i;

for (i=0; i<100; i++) {

students[i] = inputStudent();

}

The Arrow Operator

In order to dereference a pointer we would normally use the dereferencing operator (*) and if we

our pointer was to a structure, we could subsequently use the dot '.' operator to refer to a member

of the structure. Suppose we have declared a pointer which could be used to point to a structure of

type employee as follows.

Student stuVariable;

Student *stuPtr;

stuPtr = &stuVariable;

To refer to the student identification we could say:

(*stuPtr).studentID

Note that the brackets are necessary because the dereference operator has lower precedence than

the dot operator. This form of syntax is a little cumbersome, so another operator is provided to us

as a convenient shorthand:

stuPtr->studentID

This method of accessing the number member through a pointer is completely equivalent to the

previous form. The '->' operator is called the indirect member selection operator or just the arrow operator and it is almost always used in preference to the previous form.

Passing Structures by Reference

Passing structures to a function using pass-by-value can be simple and successful for simple

structures so long as we do not wish to do so repeatedly. But when structures can contain a large

amount of data (therefore occupying a large chunk of memory) then creating a new cop