Parameters-Arguments

advertisement
Parameters & Arguments
Passing arguments to void-functions is no different than passing information to explicit-functions. The arguments passed
to void-functions may be variables, constants, pointers (to addresses in memory), and/or expressions.
DisplayAdditionProblem
DisplayAdditionProblem
DisplayAdditionProblem
DisplayAdditionProblem
DisplayAdditionProblem
(3, 22);
(Add1, Add2);
(2+3, 12-X+Y);
(2, Add2);
(*Ptr1, *Ptr2);
/*
/*
/*
/*
/*
Constant
Variable
Expression
Constant & Variable
Pointers-Section 4.5
*/
*/
*/
*/
*/
void DisplayAdditionProblem ( int FirstNumber, int SecondNumber)
{
/* Code Necessary To Complete The Task */
}
When the first line of this function is executed, the memory manager will allocate two bytes of contiguous memory
for integer value parameter FirstNumber and initialize it with the integer value of the first argument. The memory manager
will also allocate two bytes of contiguous memory for integer value parameter SecondNumber and initialized with it with the
integer value of the second argument.
Program PrtNum.c will provide an opportunity to examine the scope of variables in the selective memory maps
embedded within the code.
PROGRAM
PrtNum.c
# include <stdio.h>
void PrintNum (int N1, int N2 ,float N3);
main ()
{
int
Num1, Num2;
float
Num3 ;
Num1 = 5;
Num2 = 8;
Num3 = Num2 / Num1;
/* Note Integer Division */
PrintNum (Num1, Num2, Num3);
/* prototype */
}
/************************************************/
void PrintNum (int N1, int N2 ,float N3)
{
printf ("N1 = %3d\n", N1);
printf ("N2 = %3d\n", N2);
printf ("N3 = %6.2f\n", N3);
N1 = N1 * N2;
}
The output from PrtNum.c is as follows:
N1 =
N2 =
N3 =
5
8
1.00
The formal parameters of PrintNum are N1, N2, and N3. Subprogram PrintNum is called from main; Num1, Num2,
and Num3 are arguments (actual parameters) in this call statement. Let us now examine the relationship between the
parameter list in the header
void PrintNum (int N1, int N2 ,float N3)
and the call
PrintNum (Num1, Num2, Num3);
In this case, Num1 corresponds to N1, Num2 corresponds to N2, and Num3 corresponds to N3. Notice that both
the number and data type of variables in the parameter list correspond with the number and type of variables listed in the
call.
As previously explained, N1 (&2655332) is a copy of Num1 (&2477876); changes made to N1 within PrintNum
have no effect on Num1 (out-of-scope). Changing N1 to 40 had no effect on Num1! See memory map PrtNum-5.
Pointer Declaration and Assignment
Some high-level languages allow two-way passing of variables called passing by reference. Pascal is one such
language. When a variable is passed by reference, changes made in a subprogram actually change the original variable.
Although C has no mechanism for passing by reference, we will learn to change original variables by passing pointers.
The concept of pointers is very important in most programming languages. Knowledge of pointers in C is critical;
pointers shall be used with arrays, strings, files, and the passing of parameters.
In C we can display addresses associated with symbolic variables in several ways. In review, we have already
printed out the address associated with symbolic variable N1 with printf statements like the following:
int N1;
printf("The Hex Address Associated with N1 = %X\n",&N1);
printf("The Address Associated with N1 = %lu\n",&N1);
We have already allowed the scanf function to fill the address associated with N1 with a statement like:
scanf("%d",&N1);
Let us declare the following local variables in function main:
int
Age = 18,
*PtrToAge;
The first variable, Age, is an integer; the memory manager allocates two bytes of contiguous memory for Age and the
compiler initializes Age to 18. The second variable is a pointer to an integer; PtrToAge shall be used to hold the address of
some integer variable; the content of this variable is unknown (Memory Map A). The memory manager will allocate the
number of bytes necessary to store a pointer variable.
Since the contents of a pointer is an address in memory, pointers need be only large enough to store the largest
address possible for the specific computer. The number of bytes allocated to a pointer will vary because (1) all computers
do not have the same memory capacity and (2) all computers do not use the same addressing. The following line of code
will allow you to determine the size of a pointer on your computer.
printf("Pointers Are Allocated %ld bytes\n",sizeof(PtrToAge));
Pointers Are Allocated 4 bytes
Four-byte pointers are common; the thirty-two bits would allow the computer memory to be expanded to 232 bytes
(4,294,967,296). We shall assume a four-byte pointer size throughout this text.
PtrToAge = &Age;
Pointers may be assigned to an address (of matching data type) or another pointer (of matching data type). The
pointer assignment statement above places the address, associated with symbolic integer variable Age, into variable
PtrToAge. Examine Memory Map B. Age is stored at address 1196538 (abbreviated &1196538). A compilation error will be
generated if PtrToAge were assigned to the address of a float variable or the address of a char variable; the data types
must match.
The arrow, on memory map above, is used to illustrate the relationship between the pointer and the variable to
which it points. The following code segment could be used to display the critical components of the memory map above.
printf ("%14s%20s\n","Age[int]","PtrToAge[int *]");
printf (" ---------------------------\n");
printf (" |%6d
|
|%10p |\n",Age,PtrToAge);
printf(" ---------------------------\n");
printf ("%11p-%d%17p-%d\n",&Age,sizeof(Age),
&PtrToAge,sizeof(PtrToAge));
Output:
Age[int]
-------------|
18
|
-------------1196538-2
PtrToAge[int *]
-------------|
1196538 |
-------------1196534-4
Let us now create Memory Map Ptr-1 for the following declarations:
float
PayPerHour = 7.50,
*PayPtr;
char
MiddleInitial = 'E',
*InitialPtr;
Without looking at Memory Map Ptr-2, attempt to show the memory map as it would be after the following pointer
assignment statements:
InitialPtr = & MiddleInitial;
PayPtr = & PayPerHour;
Now check your work!
Let us now create Memory Map Quantity-1 for the following declarations and assignments:
unsigned long int
QuantityInStock= 200000;
float
PayPerHour = 7.50;
unsigned long int
*QuantityPtr1,
*QuantityPtr2;
QuantityPtr1 = &QuantityInStock;
QuantityPtr2 = QuantityPtr1;
The address in one pointer may be assigned to the address in another pointer (of matching data types). In the
illustration above, both QuantityPtr1 and QuantityPtr2 point to QuantityInStock.
De-referencing Pointers
Thus far we have printed the addresses of pointers and the addresses contained within pointers. We have also
assigned pointers to the address of a variable (of appropriate data type). We have transferred the address contained in
one pointer to another pointer (of like data type). It is now time to use the pointer to change the contents of the original
memory location; we shall do this by dereferencing the pointer.
As previously mentioned, all parameters passed to C subprograms are passed by value. Pointers are a valid data
type and may be included within the parameter list. In program Switch.c, the main function has two local integer variables
X, and Y.
Let us examine a program which uses a void–function, SwitchIntegers, to switch the contents of variables X and Y.
PROGRAM
Switch1.c
# include <stdio.h>
void SwitchIntegers (int *FirstPtr, int *SecondPtr);
main ()
{
int
X=5, Y=8;
printf ("%d - %d\n",X,Y);
SwitchIntegers (&X,&Y);
printf ("%d - %d\n",X,Y);
}
void SwitchIntegers (int *FirstPtr, int *SecondPtr)
{
int
Temp;
Temp = *FirstPtr;
*FirstPtr = *SecondPtr;
*SecondPtr = Temp;
}
Output from Switch1.c is as follows:
5 - 8
8 - 5
The addresses of X and Y are arguments in the call to function SwitchIntegers. The argument (&X) is matched
with the parameter pointer (FirstPtr) and the argument (&Y) is matched with parameter pointer (SecondPtr). It is by
dereferencing these pointers that the contents X and Y are exchanged.
Program Switch2.c provides a memory dump that might help you to better understand what has happened in
program Switch1.c. This type of memory dump will be quite helpful in debugging errors related to the transfer of
information between subprograms.
PROGRAM
Switch2.c
# include <stdio.h>
void SwitchIntegers (int *FirstPtr, int *SecondPtr);
main ()
{
int
X=5, Y=8;
puts("------------------ Beginning of main ---------------------\n");
printf ("%14s%16s\n","X[int]","Y[int]");
printf (" ---------------------------\n");
printf (" |%6d
|
|%6d
|\n",X,Y);
printf(" ---------------------------\n");
printf ("%11p-%d%17p-%d\n\n",&X,sizeof(X),&Y,sizeof(Y));
SwitchIntegers (&X,&Y);
puts("-------------------- End of main ------------------------\n");
printf ("%14s%16s\n","X[int]","Y[int]");
printf (" ---------------------------\n");
printf (" |%6d
|
|%6d
|\n",X,Y);
printf(" ---------------------------\n");
printf ("%11p-%d%17p-%d\n\n",&X,sizeof(X),&Y,sizeof(Y));
}
void SwitchIntegers (int *FirstPtr, int *SecondPtr)
{
int
Temp = 0; /* Initialized to 0 for memory map output only - not efficient */
puts("------------- Beginning of SwitchIntegers ---------------\n");
printf ("%16s%18s%16s\n","FirstPtr[int]","SecondPtr[int]","Temp[int]");
printf (" -----------------------------------------\n");
printf (" |%10p |
|%10p |
|%6d
|\n",FirstPtr,SecondPtr,Temp);
printf (" -----------------------------------------\n");
printf (" |->%4d
|
|->%4d
|\n",*FirstPtr,*SecondPtr);
printf(" ---------------------------\n");
printf ("%11p-%d%17p-%d%17p-%d\n\n",&FirstPtr,sizeof(FirstPtr),
&SecondPtr,sizeof(SecondPtr),&Temp,sizeof(Temp));
Temp = *FirstPtr;
*FirstPtr = *SecondPtr;
*SecondPtr = Temp;
puts("---------------- End of SwitchIntegers -----------------\n");
printf ("%16s%18s%16s\n","FirstPtr[int]","SecondPtr[int]","Temp[int]");
printf (" -----------------------------------------\n");
printf (" |%10p |
|%10p |
|%6d
|\n",
FirstPtr,SecondPtr,Temp);
printf (" -----------------------------------------\n");
printf (" |->%4d
|
|->%4d
|\n",*FirstPtr,*SecondPtr);
printf(" ---------------------------\n");
printf ("%11p-%d%17p-%d%17p-%d\n\n",&FirstPtr,sizeof(FirstPtr),
&SecondPtr,sizeof(SecondPtr),&Temp,sizeof(Temp));
}
Output from Switch2.c is as follows:
------------------ Beginning of main --------------------X[int]
-------------|
5
|
-------------1349514-2
Y[int]
-------------|
8
|
-------------1349512-2
------------- Beginning of SwitchIntegers --------------FirstPtr[int]
-------------|
1349514 |
-------------|->
5
|
-------------1349504-4
SecondPtr[int]
-------------|
1349512 |
-------------|->
8
|
-------------1349508-4
Temp[int]
--------------|
0
|
---------------
1349494-2
---------------- End of SwitchIntegers ----------------FirstPtr[int]
-------------|
1349514 |
-------------|->
8
|
-------------1349504-4
SecondPtr[int]
-------------|
1349512 |
-------------|->
5
|
-------------1349508-4
Temp[int]
--------------|
5
|
---------------
1349494-2
-------------------- End of main -----------------------X[int]
-------------|
8
|
-------------1349514-2
Y[int]
-------------|
5
|
-------------1349512-2
Variable Temp was initialized to 0 only for display purposes. The printf statements that provide the memory dumps could
be better accomplished using one or more subprograms; this will be left to the student.
The dereferencing of pointers is the same for void-functions and explicit-functions. Memory maps will prove to be
helpful in debugging until you are comfortable with the concept.
Download