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