254 Intermediate C Programming
as when passing other types of arguments, such as int and double: A copy of the argument
is passed. The following example shows a separate function for printing Vector objects:
// vector3 .c1
#in clude < stdio .h >2
#in clude < stdlib .h >3
#in clude < string .h >4
#in clude " vector .h "5
void printVe ctor ( Vector v)6
{7
printf (" The vector is (% d, %d , % d) . n ", v .x, v .y, v .z) ;8
}9
10
int main ( i n t argc , char * argv [])11
{12
Vector v1 ;13
v1 .x = 3;14
v1 .y = 6;15
v1 .z = -2;16
printV ector ( v1 );17
return EXIT _SUCCES S ;18
}19
Frame Symbol Address Value
printVector
v.z 124 2
v.y 120 6
v.x 116 3
return location 112 line 18
main
v1.z 108 2
v1.y 104 6
v1.x 100 3
How do we know that the attributes are copied? In the following program changeVector
changes the Vector object passed to it. However, inside main, the attributes of v1 are
unchanged.
// vector4 .c1
#in clude < stdio .h >2
#in clude < stdlib .h >3
#in clude < string .h >4
#in clude " vector .h "5
void printVe ctor ( Vector v)6
{7
printf (" The vector is (% d, %d , % d) . n ", v .x, v .y, v .z) ;8
}9
10
void change Vector ( Vector v )11
{12
v. x = 5;13
v. y = -3;14
v. z = 7;15
printV ector ( v) ;16
Programmer-Defined Data Types 255
}17
18
int main ( i n t argc , char * argv [])19
{20
Vector v1 ;21
v1 .x = 3;22
v1 .y = 6;23
v1 .z = -2;24
printV ector ( v1 );25
chang eVector ( v1 );26
printV ector ( v1 );27
return EXIT _SUCCES S ;28
}29
The output of this program is:
The vector is (3, 6, -2).
The vector is (5, -3, 7).
The vector is (3, 6, -2).
What really happens when a function’s argument is an object? This can be explained
by showing the call stack before calling changeVector:
Frame Symbol Address Value
main
v1.z 108 2
v1.y 104 6
v1.x 100 3
Calling changeVector pushes a new frame to the call stack. The argument is an object
that has three attributes. The values are copied from the calling function into the new
frame.
Frame Symbol Address Value
changeVector
v.z 124 2
v.y 120 6
v.x 116 3
return location 112 line 27
main
v1.z 108 2
v1.y 104 6
v1.x 100 3
The function changeVector changes the attributes of the object in its own frame.
Frame Symbol Address Value
changeVector
v.z 124 7
v.y 120 3
v.x 116 5
return location 112 line 27
main
v1.z 108 2
v1.y 104 6
v1.x 100 3
When changeVector finishes, the frame is popped and the program resumes at main.
The call stack is shown below:
256 Intermediate C Programming
Frame Symbol Address Value
main
v1.z 108 2
v1.y 104 6
v1.x 100 3
Note that the attributes of v1 are unchanged.
16.3 Objects and Pointers
Is it possible to change an object’s attributes inside a function and keep the changes
even after the function returns? The answer is yes. To do this, we need to use pointers.
// vect orptr . c1
#in clude < stdio .h >2
#in clude < stdlib .h >3
#in clude < string .h >4
#in clude " vector .h "5
void printVe ctor ( Vector v)6
{7
printf (" The vector is (% d, %d , % d) . n ", v .x, v .y, v .z) ;8
}9
10
void change Vector ( Vector * p )11
{12
p -> x = 5;13
p -> y = -3;14
p -> z = 7;15
printV ector (* p) ;16
}17
18
int main ( i n t argc , char * argv [])19
{20
Vector v1 ;21
v1 .x = 3;22
v1 .y = 6;23
v1 .z = -2;24
printV ector ( v1 );25
chang eVector (& v1 );26
printV ector ( v1 );27
return EXIT _SUCCES S ;28
}29
At line 11 changeVector’s argument is a pointer:
void change Vector ( Vector * p )11
This means that p is a pointer in the frame of the function changeVector. If you refer
back to Table 4.1, this is the first way of using *. When calling changeVector at line 26,
main must provide the address of a Vector object, i.e., & v1. This is best understood by
showing the call stack:
Programmer-Defined Data Types 257
Frame Symbol Address Value
changeVector
p 116 100
return location 112 line 27
main
v1.z 108 2
v1.y 104 6
v1.x 100 3
Instead of copying the whole object, attribute by attribute, the argument p stores only
the address of the object v1. This is the address of the first attribute.
What is the -> symbol inside changeVector? The -> symbol takes the value at the
address, and then gets the attribute as if applying a . to a structure. Pointers are used with
structures often and C has this special syntax. It is equivalent to saying:
p -> x13
is the same as
(* p) .x13
This dereferences p first, and then applies . for x. Dereferencing is the second way of using
* as explained in Table 4.1. Note that this means -> can only be used on a pointer to a
structure. It is illegal to use it in any other circumstance. If -> is at the left hand side (LHS)
of an assignment, then the attribute is modified (i.e., written). If -> is at the right hand
side (RHS) of an assignment, then the attribute is read. The statement,
p -> x = 5;13
changes the value at address 100.
Frame Symbol Address Value
changeVector
p 116 100
return location 112 line 27
main
v1.z 108 2
v1.y 104 6
v1.x 100 3 5
p -> y = -3;14
changes the value at address 104.
Frame Symbol Address Value
changeVector
p 116 100
return location 112 line 27
main
v1.z 108 2
v1.y 104 6 -3
v1.x 100 5
Why do we need to add * in front of p when changeVector calls printVector? In
changeVector, p is a pointer. However, printVector expects an object because there is
no * in the line:
void printVe ctor ( Vector v)6
In changeVector, adding * in front of p dereferences the pointer, as explained in
Table 4.1. Thus, the object stored at addresses 100–108 is copied to the argument of
printVector. How do we know that the object is copied? In C, arguments are always copied
when passed to functions. If the argument were Vector *, then a copy of the pointer would
258 Intermediate C Programming
be passed. There is no * after Vector in printVector and the argument is an object. As
a result, the object is copied. If v’s attributes are changed inside printVector, then the
changes will be lost when the function finishes. The syntax for using objects is:
If p’s value is an address of an object, use p -> x. It is allowed to put a space before
or after -> but no space can be added between - and >.
If v is an object (not an address), use v.x.
16.3.1 Returning an Object
Can a function return a Vector object? Yes. The following example shows a constructor
function that creates and initializes a new object:
// vector5 .c1
#in clude < stdio .h >2
#in clude < stdlib .h >3
#in clude < string .h >4
#in clude " vector .h "5
Vector Ve ctor_ constr uct ( i n t a , i n t b , in t c)6
{7
Vector v;8
v. x = a;9
v. y = b;10
v. z = c;11
return v ;12
}13
14
void Vector _print ( Vector v )15
{16
printf (" The vector is (% d, %d , % d) . n ", v .x, v .y, v .z) ;17
}18
19
int main ( i n t argc , char * argv [])20
{21
Vector v1 = Vecto r_con struct (3 , 6 , -2) ;22
Vecto r_print ( v1 );23
return EXIT _SUCCES S ;24
}25
What is the advantage of creating constructor functions? One good reason is that they
make programs easier to read. The three arguments remind programmers that a Vector
object has three attributes. Constructors should guarantee that all attributes are always
initialized. Uninitialized variables can make your programs behave in surprising ways. Before
calling the constructor, v1 is already on the call stack in the frame of the main function.
When the constructor returns the object, the attributes of v are copied to v1’s attributes
one by one. Then, the constructor’s frame is popped and v does not exist any more.
16.3.2 Objects and malloc
Is it possible to create an object that exists in heap memory, instead of stack memory?
Yes. Here is how to do it:
// ve ctormal l oc . c1
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset