Functions, Pointers, and the Basics of C++ Classes

Similar documents
Pointers, Dynamic Data, and Reference Types

static CS106L Spring 2009 Handout #21 May 12, 2009 Introduction

Comp 11 Lectures. Mike Shah. June 26, Tufts University. Mike Shah (Tufts University) Comp 11 Lectures June 26, / 57

CISC220 Lab 2: Due Wed, Sep 26 at Midnight (110 pts)

Arrays. Returning arrays Pointers Dynamic arrays Smart pointers Vectors

CSE 374 Programming Concepts & Tools. Hal Perkins Spring 2010

CSE 374 Programming Concepts & Tools. Hal Perkins Fall 2015 Lecture 19 Introduction to C++

Variables. Data Types.

B16 Object Oriented Programming

Principles of Programming Pointers, Dynamic Memory Allocation, Character Arrays, and Buffer Overruns

The Stack, Free Store, and Global Namespace

Motivation was to facilitate development of systems software, especially OS development.

B16 Object Oriented Programming

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

QUIZ. What is wrong with this code that uses default arguments?

C++ for Java Programmers

Introduction to Programming in C Department of Computer Science and Engineering. Lecture No. #44. Multidimensional Array and pointers

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

Mastering Data Abstraction or Get nit-picky on design advantages

12. Pointers Address-of operator (&)

377 Student Guide to C++

CSCI-1200 Data Structures Spring 2018 Lecture 7 Order Notation & Basic Recursion

COSC 2P95. Procedural Abstraction. Week 3. Brock University. Brock University (Week 3) Procedural Abstraction 1 / 26

Array Elements as Function Parameters

Chapter 2 Basic Elements of C++

Final exam. Final exam will be 12 problems, drop any 2. Cumulative up to and including week 14 (emphasis on weeks 9-14: classes & pointers)

The Dynamic Typing Interlude

Memory Addressing, Binary, and Hexadecimal Review

C Review. MaxMSP Developers Workshop Summer 2009 CNMAT

Pointers and References

PIC 10A Objects/Classes

Lecture 05 I/O statements Printf, Scanf Simple statements, Compound statements

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

QUIZ How do we implement run-time constants and. compile-time constants inside classes?

printf( Please enter another number: ); scanf( %d, &num2);

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

Pointers. A pointer is simply a reference to a variable/object. Compilers automatically generate code to store/retrieve variables from memory

Lambda Correctness and Usability Issues

Intro. Scheme Basics. scm> 5 5. scm>

See the CS 2704 notes on C++ Class Basics for more details and examples. Data Structures & OO Development I

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Programming in C++ Indian Institute of Technology, Kharagpur

If Statements, For Loops, Functions

Chapter 1 Getting Started

Agenda. Peer Instruction Question 1. Peer Instruction Answer 1. Peer Instruction Question 2 6/22/2011

6. Pointers, Structs, and Arrays. March 14 & 15, 2011

Output of sample program: Size of a short is 2 Size of a int is 4 Size of a double is 8

nptr = new int; // assigns valid address_of_int value to nptr std::cin >> n; // assigns valid int value to n

IS0020 Program Design and Software Tools Midterm, Fall, 2004

CS31 Discussion 1E Spring 17 : week 08

Motivation was to facilitate development of systems software, especially OS development.

CS 61C: Great Ideas in Computer Architecture. Lecture 3: Pointers. Bernhard Boser & Randy Katz

III. Classes (Chap. 3)

Ch. 12: Operator Overloading

CS113: Lecture 5. Topics: Pointers. Pointers and Activation Records

Consider the above code. This code compiles and runs, but has an error. Can you tell what the error is?


Memory and Pointers written by Cathy Saxton

a data type is Types

Software Design and Analysis for Engineers

Lesson 10A OOP Fundamentals. By John B. Owen All rights reserved 2011, revised 2014

Welcome Back. CSCI 262 Data Structures. Hello, Let s Review. Hello, Let s Review. How to Review 8/19/ Review. Here s a simple C++ program:

CSE 303: Concepts and Tools for Software Development

6. Pointers, Structs, and Arrays. 1. Juli 2011

CS 376b Computer Vision

GDB Tutorial. A Walkthrough with Examples. CMSC Spring Last modified March 22, GDB Tutorial

A brief introduction to C programming for Java programmers

These are notes for the third lecture; if statements and loops.

Agenda. The main body and cout. Fundamental data types. Declarations and definitions. Control structures

Pointers. 1 Background. 1.1 Variables and Memory. 1.2 Motivating Pointers Massachusetts Institute of Technology

Computer Science II Lecture 1 Introduction and Background

CSCI 262 Data Structures. Arrays and Pointers. Arrays. Arrays and Pointers 2/6/2018 POINTER ARITHMETIC

Operator overloading

CSCI-1200 Data Structures Fall 2017 Lecture 5 Pointers, Arrays, & Pointer Arithmetic

Fast Introduction to Object Oriented Programming and C++

Objectives. Chapter 2: Basic Elements of C++ Introduction. Objectives (cont d.) A C++ Program (cont d.) A C++ Program

Chapter 2: Basic Elements of C++

CS93SI Handout 04 Spring 2006 Apr Review Answers

Chapter 10 Pointers and Dynamic Arrays. GEDB030 Computer Programming for Engineers Fall 2017 Euiseong Seo

Chapter 10. Pointers and Dynamic Arrays. Copyright 2016 Pearson, Inc. All rights reserved.

Object-Oriented Programming, Iouliia Skliarova

Chapter 2: Basic Elements of C++ Objectives. Objectives (cont d.) A C++ Program. Introduction

Welcome Back. CSCI 262 Data Structures. Hello, Let s Review. Hello, Let s Review. How to Review 1/9/ Review. Here s a simple C++ program:

I m sure you have been annoyed at least once by having to type out types like this:

Object Oriented Software Design II

Pointers in C/C++ 1 Memory Addresses 2

Object-Oriented Principles and Practice / C++

Instructor (Jerry Cain)

Lecture Notes on Memory Layout

QUIZ. What are 3 differences between C and C++ const variables?

Maciej Sobieraj. Lecture 1

Compilers and Interpreters

Functions, Arrays & Structs

8. The C++ language, 1. Programming and Algorithms II Degree in Bioinformatics Fall 2017

CSE 143. Complexity Analysis. Program Efficiency. Constant Time Statements. Big Oh notation. Analyzing Loops. Constant Time Statements (2) CSE 143 1

Lecture 2, September 4

Programming in C ++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

CSCI-1200 Data Structures Spring 2016 Lecture 7 Iterators, STL Lists & Order Notation

PIC 10A Pointers, Arrays, and Dynamic Memory Allocation. Ernest Ryu UCLA Mathematics

Pointers. Reference operator (&) ted = &andy;

by Pearson Education, Inc. All Rights Reserved.

Transcription:

Functions, Pointers, and the Basics of C++ Classes William E. Skeith III Functions in C++ Vocabulary You should be familiar with all of the following terms already, but if not, you will be after today. function prototype function header function body call by value call by reference actual parameter (the view from outside the function) formal parameter (the view from inside the function) default parameters function overloading By-Value vs. By-Reference When parameters are passed by-value, the formal parameters of a function refer to copies of the actual parameters which are discarded as soon as the function call returns. In byreference calls on the other hand, the formal parameters become synonyms (or aliases, if you will) of the actual parameters. So, changes to by-reference parameters are of course reflected in the actual parameters. To completely drive the point home, let s look at a few examples. Consider the following function that increments the formal parameter, which is passed by value. 1

void addone(long x) { x++; return; int main(void) { long y = 23; cout << "y == " << y << endl; //y contains 23. addone(y); cout << "y == " << y << endl; //y is unchanged: still contains 23. In this case the formal parameter x is a local copy of the actual parameter y. The lifetime of x is only that of the function call, so certainly the changes will not be reflected outside the scope of the function. Now let s look at a similar example using by-reference parameters. void addonebyref(long& x) { x++; return; int main() { long y = 23; cout << "y == " << y << endl; //y contains 23. addonebyref(y); cout << "y == " << y << endl; //y now contains 24. Again, since the formal parameter x is a synonym for the actual parameter y, changing x will of course change y. Note: unless you explicitly instruct for parameters to be passed by reference, they are always passed by value in C++. It is natural for us as humans to condense incoming information, describing new ideas in terms of old ones, and only accepting new concepts when necessary. In an attempt to speed up the process, consider the following example which does away with by-reference parameters altogether. Suppose you have a function that takes a by-reference parameter of some type- it doesn t matter what. For now, we ll stick with long although it is irrelevant. The function may look something like this: 2

void somefunction(long& x) { x = x+7; //other stuff... We can make a function that is equivalent in almost every way with pointers as follows: void somefunction(long* px) { long& x = (*px); //explicitly alias x to be what px points to. //the rest of the code is the same: x = x+7; //other stuff... This will change the way that you must call the function in C++ (you ll have to send &x rather than just x), but beyond that, they should be basically identical. Here s gcc s assembly output (with optimization enabled) for the two versions: # version that uses call by reference: _Z12someFunctionRl:.LFB30:.cfi_startproc addq $7, (%rdi) #, *x_2(d) ret.cfi_endproc # version that passed a pointer by value: _Z13someFunction2Pl:.LFB31:.cfi_startproc addq $7, (%rdi) #, *px_1(d) ret.cfi_endproc Note that they are identical. Now consider the following example: void mulbytwo(long A[], unsigned long n) { for(unsigned long i=0; i<n; i++) A[i] = A[i]*2; return; int main() { long Arr[10]; 3

unsigned long i; for(i=0; i<10; i++) Arr[i] = i; for(i=0; i<10; i++) cout << Arr[i] << " "; //will print 0...9 cout << endl; mulbytwo(arr,10); for(i=0; i<10; i++) cout << Arr[i] << " "; //will print 0,2,...,18 cout << endl; At this point, you may be thinking, Hey, I didn t see any ampersands! I thought you just told me everything was by-value unless I said otherwise? to which I would respond, Yes I did, but only because it s true. The confusion you may be experiencing is simply due to a failure to see C++ arrays for what they really are: arrays are just pointers. So, an array parameter like long A[] is actually a pointer: long* A, and that pointer is passed by-value. 1 If you were to change the value of the pointer from inside the function, it would not change anywhere else. But if you dereference that address and change what s in memory, of course that change will persist. There s only one array, but you now have two copies of its address. In fact, I would encourage you to not use the bracket notation ([]) when passing array parameters as a general rule. Just pass them as pointers. In my experience it has never lead to confusion, and use of this convention is a standard practice. Function Overloading You can provide more than one function with the same name, as long as the compiler has a way to figure out what function you are referencing just by examining a function call. From this premise, you can figure out exactly what is legal and what is not in terms of overloads. You could memorize the rules, but there are subtleties that make for a good number of them. The best thing to do is really to just focus on that premise: you can then replace knowing with understanding which is always a good thing. As a simple self-test, suppose you have a function like double avg(double x, double y). Which of the following would you suspect are legal overloads of avg? 1. double avg(double x, double y, double z) 1 If you want to be really picky and technical, there is a subtle difference between long[] and long*: when you make a static array, like long A[10];, the pointer that corresponds to A isn t actually stored anywhere, as it can be computed as an offset in a stack frame. Nevertheless, whenever you need to reference the pointer that would correspond to A, you get the address of A[0], just as if A had datatype long*. 4

2. double avg(double a, double b) 3. long avg(double x, double y) 4. double avg(long x, long y) Now suppose you have some function bool fn1(long x, double y). Would bool fn1(double x, long y) be ok? The Basics of Classes in C++ The real point behind classes in C++ is their role in abstract, object oriented programming (which we re not quite ready for at the moment) but at a minimum, classes allow you to define your own datatypes which is already very useful. We re all very familiar with the intrinsic datatypes (long, double, char, etc.) but as we ll see, there is often a desire for more. Making our own datatypes greatly simplifies our code, letting us write programs that line-up a bit better with the abstract constructs in our minds. Strictly speaking, it isn t ever necessary, but it is often useful enough to seem like it. We could of course write all of our programs using nothing more than the intrinsic types (or better yet, just program in machine language)- but it doesn t mean that we should. A more refined, abstract approach is often a better idea. Typically one dives into the lower levels of abstraction only when additional performance is needed. For example, suppose we want to do some operation on complex numbers. Let x, c C and consider a sequence of the form ( ((x 2 + c) 2 + c) 2 + c ) 2 + c i.e., the sequence is defined by the recurrence a 0 = x and a i = a 2 i 1 + c. Suppose for a particular seed value x we d like to see (via computational approximation) if this sequence diverges. We ll use the following method: compute up to n terms of the sequence, measuring the magnitude at each step. If the magnitude is larger than some threshold t, then we ll assume it diverges. What would the code for this look like? bool willdiverge(double rex, double imx, double rec, double imc) { const double t = 8; unsigned long i; double rerslt,imrslt; for(i=0; i<n; i++) { // first, compute x 2 rerslt = rex*rex - imx*imx; imrslt = 2*reX*imX; 5

// now add c rerslt += rec; imrslt += imc; // compute the magnitude so we know if we should return if(rerslt*rerslt+imrslt*imrslt > t) return true; // finally, update with the new value for x: rex = rerslt; imx = imrslt; return false; // made it through all the iterations This code is manageable, but it isn t very pretty. Really, we re just doing basic arithmetic, so it seems like there should be an easier way. The problem is that there is no intrinsic datatype that represents C. Fortunately, C++ gives us a way to make our own datatypes. class complex { public: //first we ll define the data members. //To store a complex number, we ll use two doubles: double re; double im; //now we ll define the public interface. //what do complex numbers do? complex(double r=0, double i=0); //constructor ~complex(); //destructor complex operator+(const complex& z); complex operator-(const complex& z); complex operator*(const complex& z); complex operator*(const double s); //function overloading complex operator/(const complex& z); double norm(); Now, using our fancy complex number datatype, we could have re-written the code as follows: bool willdiverge(complex x, complex c) { const double t = 8; unsigned long i; for(i=0; i<n; i++) { 6

// compute x 2 + c x = x*x+c; if(x.norm() > t) return true; return false; // made it through all the iterations Much nicer, right? Indeed. It gives a very pleasing semantic and syntactic representation. However, keep in mind that if your application needs to be extremely high-performance, this may not be the way to go. Pointers At this point, you should be familiar with quite a few C++ datatypes (e.g. long, int, double, float, unsigned char... and in the last section, we covered ways to make your own (via structs or classes). Often times it is convenient to explicitly keep track of where (in main memory) some variable of ours is being stored. How does one accomplish this? Well, every datatype has a corresponding pointer datatype for exactly this purpose. Pointers are variables that store memory addresses. Think of them just as any other datatype. There really is nothing special about them- they are not scary, they are not complicated, they are just variables that store memory addresses. Ok, let s get on to a few details. So, I mentioned that every datatype has a corresponding pointer datatype, but what is the name of it? Just append a star (*) to your existing datatype, and you have a pointer datatype. Easy, right? Here s an example: int x; //x is an integer. int* p; //p is a pointer to an integer. Alright, so pointers store memory addresses. If I m going to make much use out of that feature, there are two things I certainly need to be able to do: 1. Given a pointer (i.e., an address) I should be able to read the contents of memory at that address. 2. Given a variable, I should be able to obtain the address where it is stored. C++ gives us the * operator (a.k.a. the dereference operator) and the & operator (a.k.a. the address of operator) for these purposes, respectively. They can be used as in the following example: int x = 23; //x is an integer. int* p; //p is a pointer to an integer. p = &x; //p now holds the address of our variable x. cout << x << " " << *p << endl; //should print 23 23 7

For any variable, say x, the symbol &x will evaluate to the address of x. So, if x has datatype int, then &x has datatype int*. And for any pointer, say p, the symbol *p will evaluate to whatever is at the address stored in p. So if p has datatype int* then *p has datatype int. Pretty simple, right? You can think of the * and & operators as sort of inverses. For any datatype K, we have K & K such that & = 1 K and & = 1 K. One more time, for emphasis, you should interpret these operators as follows: &x tell me where x is in memory p go get me what s at memory address p Self test: In the following code segments, what is the output? int main() { long *p, x = 3; p = &x; cout << x << endl; cout << *p << endl; x = 4; cout << x << endl; cout << *p << endl; *p = 59; cout << x << endl; cout << *p << endl; int main() { long *p1, *p2, x1 = 3, x2 = 2; p1 = &x1; p2 = &x2; cout << x1 << " " << *p1 << " " << x2 << " " << *p2 << endl; p1 = p2; cout << x1 << " " << *p1 << " " << x2 << " " << *p2 << endl; x2++; cout << x1 << " " << *p1 << " " << x2 << " " << *p2 << endl; 8

p2 = &x1; x1 = 10; x2 = 23; cout << x1 << " " << *p1 << " " << x2 << " " << *p2 << endl; 9