Tutorial 8.4: Passing Arrays to Functions

An array can be passed as an argument to a function. Remember the mechanism of call-by-value. When we pass variables to a function, copy of their values are made for the function. Therefore any changes to the copy do not affect the original variables' value. But in the case of passing an array to a function, we are actually passing the memory location of the array which is its address. It is because the name of arrays evaluates to the address of the first element of the array. Thus, the called function can modifies the actual values in the original array since it knows exactly where the array is stored in the memory. The following program demonstrates that an array name is actually the address of its first element.
#include <stdio.h>

int main()
{
 int a[5] = {1, 2, 3, 4, 5};
 printf("&a[0] = %p\n", &a[0]);
 printf("   &a = %p\n", &a);
 printf("    a = %p\n", a);
 return 0;
}
Sample output:

&a[0] = 0022FF20
   &a = 0022FF20
    a = 0022FF20


Printing the address of the array's first element and its name yields the same output. The %p is a conversion specifier for printing address. As usual we will look at an example on how to pass an array to a function. It also demonstrates that a function can modify the elements in an array.
#include <stdio.h>

#define SIZE 5

/* function prototype */
void squareArray(int arr[], int size);

int main()
{
 int a[SIZE] = {1, 2, 3, 4, 5};
 int i;
 for(i = 0; i < 5; i++) printf("%d\t", a[i]);
 printf("\n");
 squareArray(a, SIZE);
 for(i = 0; i < 5; i++) printf("%d\t", a[i]);
 printf("\n");
 
 return 0;
}

/* function definition of squareArray */
void squareArray(int arr[], int size)
{
 int i;
 for(i = 0; i < size; i++) {
  arr[i] *= arr[i];
 }
}
Sample output:

1    2    3     4    5
1    4    9    16    25

Explanation:

First, an integer array a which contains five elements is declared.
 for(i = 0; i < 5; i++) printf("%d\t", a[i]);
 printf("\n");
Then we use for repetition statement to display the elements of the array. \t is an escape sequence that is used to insert horizontal tab. Once all the elements are displayed, a newline escape sequence is outputted to position the cursor at the beginning of the next line.
 squareArray(a, SIZE);
Next function squareArray is invoked. The array a and its size are passed as the arguments to the called function.

Finally we re-display the elements of the array to see changes made by function squareArray.

The following is the function definition of squareArray.
void squareArray(int arr[], int size)
{
 int i;
 for(i = 0; i < size; i++) {
  arr[i] *= arr[i];
 }
}
The function expects two arguments, an integer array and integer variable. It does not returns any value to the caller. The definition consists of integer variable i declaration and for repetition statement.

 for(i = 0; i < size; i++) {
  arr[i] *= arr[i];
 }
The for statement repeats for the number of elements (size of the array) and performs square operation on each element of the array.

Tutorial 8.3: Two-dimensional Arrays

Introduction
Up until now, we have been dealing with arrays with one index value as reference to its elements. These arrays are called one-dimensional arrays. In C we can declare arrays of two dimensions. Two-dimension arrays is illustrated in the following figure.



The array contains three rows and four columns (3-by-4 array). Two-dimensional arrays are commonly used to represent table of values that are arranged in rows and columns. For example, we could use a two-dimensional array to store information of student's course works for C programming course. What if we have several courses? We could use a three-dimensional array to store the information. One dimension would be for student's ids, one dimension for the scores and the third for the courses.

Defining and Initializing Two-dimensional Arrays
Now lets look at how we can declare a two-dimensional array. A two-dimensional array is declared as

int coursework[20][5];

The statement declares an array coursework containing twenty rows and five columns. As one-dimensional array, the index value of two-dimensional arrays with 0. Therefore, the reference for the first row and columns is coursework[0][0].

The basic structure of initializing a two-dimensional array much like a one-dimensional array. For example

int a[3][4] = { {2, 4, 6, 8}, {1, 3, 5, 7}, {2, 5, 3, 6} };

The values for each row are grouped in braces. The first group of values in the braces initializes the row 0. The next group initializes row 1 and the last group is for row 2. If we specify not enough initializing values for a given elements in a row, that elements will be initialized to zero.

Next: Passing Arrays to Functions

Tutorial 8.2: Using Character Arrays

Defining and Initializing Character Arrays
We have discussed integer arrays in the previous tutorials. Now we will be looking at how character arrays can be used to store strings. For example, we initialize a char array string which has 20 elements as follows

char string1[20];

Although array string1 is defined to have 20 elements, actually it can hold up to 19 characters only. In C, a special string-termination character '\0' called null character is added at the end of a string. The null-character is there to indicate where a string end. Therefore when declaring a char array, we should always remember to define it large enough to hold the number of characters and the null character. The following figure illustrates a char array s holding a string "hello". The null character is added as the last character in the string.



Now lets look at how to initialize a char array. For example

char string2[] = "Good Morning";

Each element of the array is initialized to contain one character of the string. Note that we haven't specified the size of the array. We let the compiler assigns the size of the array based on the length of the string. Character arrays also can be initialize as follows.

char string3[20] = "The end";

The first seven elements will contain the specified string and the null character will be added to the seventh element. The rest still can be used because the memory locations are already allocated for string3.

I/O Character Arrays

A string can be inputted into a character array using scanf with conversion specifier %s. For example,

char string1[10]; scanf("%s", string1);

Note that the normally used & is omitted in the statement. This is because the name of the array is already an address which is corresponding to the address of the first element of the array. Function scanf will read characters until a space, tab or newline is encountered. Another important matter that we have to consider is the length of the string inputted. It should be no longer than 9 characters because the last element is reserved for the null character. Therefore it is better to use the conversion specifier 9%s to make sure only 9 characters will be read during the process of input.

A character array is printed using printf with conversion specifier %s. For example,

printf("The string is %s.\n", string1);

Function printf will print the characters in the array until null character is encountered.

An example of using character array.
#include <stdio.h>

int main()
{
 int i;
 char string1[20];
 char string2[] = "Good Morning!";
 printf("Enter your name: ");
 scanf("%s", string1)
 printf("%s %s\n", string2, string1);
 /* print char array using for statement */
 for(i = 0; string1[i] != '\0'; i++) {
  printf("%c", string1[i]);
 }
 printf("\n");
 return 0;
}
Sample output:

Enter your name: Haris
Good Morning! Haris
Haris

Explanation:
 int i;
 char string1[20];
 char string2[] = "Good Morning!";
Here we have declared integer variable i and two character arrays namely string1 and string2. string1's size is set to 20 while string2 is initialized to hold a string "Good Morning!".
 printf("Enter your name: ");
 scanf("%s", string1)
 printf("%s %s\n", string2, string1);
A prompt message is printed to ask the user to enter his/her name. The entered name is stored in array string1. Then both arrays' contents are printed using function printf.
 for(i = 0; string1[i] != '\0'; i++) {
  printf("%c", string1[i]);
 }
The for repetition statement prints the content of string1 element-by-element until the null character is encountered. This is achieved by specifying the loop condition to string1[i] != '\0'. Note that conversion specifier %c is used since we are printing a character in each iteration.

Next: Two-dimensional Arrays

Tutorial 8.1: Arrays

Introduction
Lets revise what is a variable? A variable is a memory location that can store a value. An array is sequence of memory locations that have the same name and type. Thus we can say that an array is a collection of the same type of variables.

The following illustrates the graphical representation of an array.



The array name is a and it has 10 elements. The name of an array can be declared like other variable names. It can contain letters, digit, underscore and cannot begins with digit. All the array's elements have the same data type, int, char or any legal type in C. Each element has its index number and we refer to an element using their index number. Thus if we want to access the fifth element for example, we refer it as a[4]. Notice that the first element of arrays start with zero.

So what is the usefulness of arrays? Arrays are used when we want to store information that have relation such as student's scores, item's prices etc. Of course we can use variables to store the student's scores such as follows.

int s1,s2,s3,s4,s5,s6,s7,s8,s9,s10;
printf("Enter 7 scores: \n");
scanf("%d%d%d%d%d%d%d%d%d%d",&s1,&s2,&s3,&s4,&s5,&s6,&s7,&s8,&s9,&s10);

This would work but what if we need to store 100 scores or 1000 scores. Its almost impossible to program such task. Well, this is where an array can be useful.

Defining and Initializing Arrays
Lets look at how to declare an array. Its like how we declare a variable except that we need to specify its size in square bracket.

int a[10];

Here we declare an integer array a that has 10 elements. We may define arrays to contain other data types such as char, float and double.

char a[10]; float a[10]; double a[10];

Now we know how to declare an array, lets looks at how to initialize it. The simplest way to initialize an array is as follows.

int a[10] = {32, 78, 64, 90, 27, 82, 18, 60, 94, 58};

Here we assign 32 to the the 1st element, 78 to the second element and so on. If there are fewer specified values than elements, the remaining elements are initialized to zero. For example,

int a[10] = {32, 78, 64, 90};

All elements of an array could have been initialized to zero as follows.

int a[10] = {0};

Now we know how to declare and initialize an array, lets look at an example. The program utilizes for statement structure to store 10 student's scores into an array.
#include <stdio.h>

int main()
{
 int i;
 int a[10];
 printf("Enter student's scores: \n");
 for(i = 0; i < 10; i++) {
  scanf("%d", &a[i]);
 }
 printf("Your students' scores are: \n\n");
 for(i = 0; i < 10; i++) {
  printf("%d\n", a[i]);
 }
 return 0;
}
Sample output:

Enter student's scores:
15
48
68
92
37
82
64
79
57
62

Your student's scores are:
15
48
68
92
37
82
64
79
57
62
Next: Character Arrays

Tutorial 7.4: Computer-aided Learning Multiplication Problem

PROBLEM
We are writing a program that will aid an elementary school student learns multiplication. Use random function to generate positive one digit integers and it should display questions of multiplication such as:

How much is 5 x 8 ?

The student then input the answer. The program should check the answer and response with correct or wrong message. Then another multiplication question is displayed. The process should be repeated until -1 is inputted by the student meaning to exit the program. Finally the program displays the number of correct answer and questions asked.

The program also should have three level of difficulties of question. The first level is multiplication of two integers. As the level goes up, the multiplication question consists of three integers and four integers for the highest level. The program should be able to adjust the level difficulty automatically according to the performance of the student. For example it should increase the level if the student able to answer correctly for five consecutive questions and vice-versa.

SOLUTION

PROGRAM ALGORITHM (FLOW OF PROGRAM)
1. Display user instructions
2. Display a multiplication question and compute the answer
3. Get data: user answer
4. Check the user answer with the computed answer
5. Determine the level of difficulty
6. Display the performance of the user

Steps 2-5 are repeated until the user exit the program.

PROGRAM DESIGN
We use functions to perform all required task in the program. There are six (6) functions have been defined accordingly, display the user instructions, generate integers, print the question, read user answer and check it with the correct answer, adjust the level of difficulty and display user performance.

Design of Function PrintUserInstructions

Input Parameter
None

Program Variable
None

Return Value
None



The definition consists of three statements to display user instructions.

Design of Function GenerateNumber

Input Parameter
None

Program Variable
None

Return Value
rand() % 9 + 1



The expression rand() % 9 + 1 always returns a value in the range 1 ≤ integer ≤ 9. Function rand() returns a pseudo-random number each time it is invoked. Pseudo-random number is a sequence of numbers that appears to be random that is generated using an initial value (seed). For a given seed, the sequence is always the same. If we use function rand() with the default seed, we will always get the same sequence. Therefore, in order to obtain a random number, we have to randomize the seed.

In C, there is a function called srand() that can be used to initialize the pseudo-random generator by supplying a seed value as an argument to it. Now what we have to do is to supply a different value each time the program is run. This can be achieved by using function time() which returns the number of seconds that have passed since 00:00:00 GMT January 1, 1970.

Design of Function PrintQuestion

Input Parameter
int level /* level of difficulty */

Program Variables
int i /* loop counter */
int num /*store generated integer */
int ans /* store the computed answer */

Return Value
int ans /* store the computed answer */



Function PrintQuestion uses for loop statement to print the multiplication question. In each iteration, an integer is generated by calling function GenerateNumber and multiplied with variable ans. The loop condition uses level (function's argument) in the loop condition. Initially, level has the value of 1 (level 1), therefore the loop is repeated twice which means the multiplication question will be consisted of two numbers.

Design of Function InputAnswer

Input Parameter
int correct_ans /* store the correct answer */

Program Variable
int user_ans /* store the user answer */

Global Variables
int cnt_question /* count the total questions have been asked */
int cnt_true /* count total true answer */
int cnt_consecutive_true /* count consecutive true answer */
int cnt_consecutive_false /* count consecutive false answer */

Return Value
QUIT 0
CONT 1



User answer is read by using scanf and stored in variable user_ans. Then user_ans is tested. If the value is -1, symbolic constant QUIT is returned. Else variable cnt_question is incremented and user_ans is tested. If user_ans is equal to correct_ans, variables cnt_true and cnt_consecutive_true are incremented and zero is assigned to cnt_consecutive_false.

Design of Function AdjustDifficulty

Input Parameter
int level

Program Variable
None

Return Value
int level



Difficulty level is adjusted based on the value of variables cnt_consecutive_true and cnt_consecutive_false.

Design of Function PrintResult

Input Parameter
None

Program Variable
None

Return Value
None



The definition consists of two statements to display the total number of correct answers and total number of questions asked.

IMPLEMENTATION

Begin by writing the #define directives for the constant data and global variables. In the main(), declare the variables for correct answer, level of difficulty and loop control variable. Then start coding each program algorithm steps. Call function PrintUserInstructions to display the user instruction/prompt. Then call the functions PrintQuestion, InputAnswer and AdjustDifficulty. These functions should be placed in the body of the program loop since they will be repeated until the user wants to exit. Finally call the function PrintResult to display the result. Don't forget to use comments in your program so as you won't get lost. Good luck and Happy Coding!

Tutorial 7.3: Defining a Function

Defining a Function
Function definition consists of two parts, the function header and the function body (block). The function header specifies the function's return value type, function name and function parameters. The function body defines the operation that the function performs when it is called. The general form of a function definition is as follows.

return-type function-name (parameters)
{
declarations and statements;
}

The function-name can be any valid identifier that is not a keyword such as int, break, char etc. Of course you can't use a name that already been assigned to another function. The parameters is the list of variable names and their types that carry the values received by the function from the caller. The values supplied to the function is called arguments. The return-type specifies the type of the value returned by the function. The type of value can be specified as any of the available type in C. If the return-type is omitted, int is assumed. The void return-type indicates that the function does not returns a value.

The following program uses a function GetAverage to compute an average of three values.
#include <stdio.h>

/% function prototype of calcAverage */
float calcAverage(float num1, float num2, float num3, int N);

int main()
{
 int N = 3;
 float n1, n2, n3;
 float average;
 num1 = 15.5;
 num2 = 20.2;
 num3 = 25.6;
 average = calcAverage(n1, n2, n3, N);
 printf("The average is %f\n", average); 
 return 0;
}

/* function definition of calcAverage */
float calcAverage(float num1, float num2, float num3, int N)
{
 float average;
 average = (num1 + num2 + num3) / N;
 return average;
}
Sample output:

The average is 20.433334

Explanation:

In the pre-processor section, we have the following line.
/% function prototype of calcAverage */
float calcAverage(float num1, float num2, float num3, int N);
This is a function prototype. It is there to tell the compiler the specification of a function. The function prototype includes specification for the return type, the parameters and the function name. Basically function prototype is the same as the function header plus the semicolon at the end.
/* function definition of calcAverage */
float calcAverage(float num1, float num2, float num3, int N)
{
 float average;
 average = (num1 + num2 + num3) / N;
 return average;
}
Lets look at the function definition of GetAverage. The function has four parameters namely num1, num2 and num3 which are of type float and an integer called N. It is defined to computes the average of three values and returns a float type value which is the average. The return statement is used when the function is required to return a value. If the function is defined not to return a value, we are not required to put the return statement because the control is returned simply when the close brace is reached. Note that the return value should be of the same type as the declared return type in the function header.

As usual, in function main(), we have variables declaration and assignment. In this case we have three float variables and a single integer variable. Then we have the function call statement.
 average = calcAverage(num1, num2, num3, N);
We simply call by writing the function's name followed by the arguments to be supplied to the function. It is important to note that the supplied arguments must be of the same type as the expected type. When the arguments are supplied to a function, copies of the values in n1, n2, n3 and N are made for the function. The copies are then stored in num1, num2 and num3 which have been declared in the function header. This means the function cannot modifies the values in n1, n2 and n3. This mechanism is called call-by-value. There is another mechanism called call-by-reference. These two mechanism will be discussed in the next section. The result (returned value) of the function is assigned to variable res. Finally the value of res is displayed using printf.

Next: Arrays

Tutorial 7.2: Variable Scope

Variable Scope
All examples that have been presented in the previous tutorials declared variables in the block of function main(). These variables are known only within the block of function main() which means, the variables are not accessible outside of the block. This is also applied to variables which are defined within a block that is inside other block. But variables which are defined in the outer block are accessible in the inner block. This is illustrated in the following example.
#include <stdio.h>

int main()
{
 int a = 0;
 printf("a\tb\n");
 
 while(++a < 10) {
  int b = 1;
  printf("%d\t%d\n", a, b);
  ++b;
 }
 
 return 0;
}
In the example there are two variables declared,. Variable a is declared within function main() block and variable b is declared within while loop block. a is the outer block variable therefore it is accessible within inner block. But b is not accessible in the outer block because it is while loop variable. Thus if you try to print the value of b outside the while loop block, you will get an error message when you compile the program.

Variables declared outside any function is called global variables. A global variable is a variable that can be accessed in any function. Global variables are declared in the normal way except that (normally) they are declared before function main(). For example, variable c is a global variable since it is declared outside (before) function main().
#include <stdio.h>

int c = 10; // global variable

int main()
{
 ...
 
 return 0;
}

Next: Defining a Function