cstring library access with #include or the c way, #include provides two sets of functions for...

67
cstring Library • Access with #include <cstring> • Or the C way, #include <string.h> • Provides two sets of functions for dealing with strings

Post on 22-Dec-2015

215 views

Category:

Documents


0 download

TRANSCRIPT

cstring Library

• Access with #include <cstring>

• Or the C way, #include <string.h>

• Provides two sets of functions for dealing with strings

C-Style String Functions

• The str* functions work with C-style strings

• A few examples

– strcpy - copies strings

– strcat - concatenates two strings

– strcmp - compares two strings

strlen

• The most used of the str* functions

• Returns the length of a string

• It is declared as:

• size_t strlen(const char *str);

strcpy and strncpy

• Copies a string

• char* strcpy(char *dest, const char *src);

• char* strncpy*char *dest, const char *src, size_t n);

• If the length is unknown use strncpy

strcat and strncat

• Concatenates two strings

• char* strcat(char *dest, const char *src);

• char* strncat(char *dest, const char *src, size_t n);

• Again, use strncat if you don’t know the length

strcmp and strncmp

• Compares two strings

• int strcmp(const char *s1, const char *s2);

• int strncmp(const char *s1, const char *s2, size_t n);

• Use strncmp to compare just the first n characters

• Returns 0 (false) if the strings are the same!

#include <iostream>

#include <cstring>

int main() {

const char *s1 = “The first string”;

const char *s2 = “The second string”;

if (std::strcmp(s1,s2) == 0)

std::cout << “Strings the same\n”;

else if (std::strcmp(s1,s2) < 0)

std::cout << “s1 less than s2\n”;

else

std::cout << “s2 less than s1\n”;

}

memory functions

• The mem* functions work with known length strings (arrays of chars)

• Instead of using a nul terminator

• A few examples:

– memcpy - copies an array

– memchr - find a char in an array

– memcmp - compares two arrays

memcpy

• Copies a memory area

• void* memcpy(void *dest, const void *src, size_t n);

• Can be used to copy any memory area

int array1[] = {1,2,3,4};int array2[10];std::memcpy(array1,array2,sizeof(int)*4);

strlen implementationsize_t strlen(const char *str) {size_t count = 0;while (str[count] != ‘\0’)

count++;return count;

}size_t strlen(const char *str) {const char *s;for(s=str;*s;s++)

/*nothing*/;return s - str;

}

Structures

• A struct is an heterogeneous aggregate of typesstruct person {char name[80];char phone[20];unsigned short age;

};int main() {Person p;std::strcpy(p.name,”Johhny”);std::strcpy(p.phone,”99999999”);p.age = 30;

}

Object Oriented C++

• C++ is hybrid language - it allows Object Oriented Code, Procedural Code, and Generic Code

• We’ll look at the OO style of C++

• OO in C++ is just classes and objects

Class Syntax• A class is just like a struct.class Person {public :

Person(string name);Person(const Person&);Person& operator=(const Person&);~Person();string get_name();

private:string name;

};

Classes in C++

• C++ is a reasonably low level OO object• You have to do more to write a class than in

a language like Java• There are three basic functions you need to

provide:– A way to create objects of the class– A way to copy objects of the class– A way to discard objects of the class

Constructors

• Objects are created from classes by constructors

• Constructors are defined like methods– they have no return type– they have the same name as the class

• Constructors are often used by the compiler to create objects implicitly

Default Constructor

• The default constructor is a constructor that takes no arguments

• If you do not write any constructors the compiler will create a default constructor– it will set members to their ‘default’ values

• Default constructors are used by the C++ libraries so it is wise to have one if possible

• Write it yourself - unless efficiency is vital

Copy Constructor

• The copy constructor is a constructor which is passed an object of the class

• If you don’t write a copy constructor the compiler will provide one– it will just copy the values of the members

• Used by the compiler and libraries so if possible one should be provided

• Write it yourself - unless efficiency is vital

Destructor

• Objects are discarded by the destructor

• It is defined just like a method– it has no return type– it has the name of the class prefixed with ~

• The destructor should free any resources the object is using

• The compiler will provide a do nothing destructor if you don’t write one

Assignment Operator

• We’ll look at operator overloading later• Most classes should have an assignment

operator written• Foo& operator=(const Foo&);• It is called whenever an object is assigned to

another (Foo a; Foo b; a = b;)• Writing one is usually a mechanical process

we’ll look at soon

A Linked List

• We’ll look at a simple linked list class to see how classes are written

• If you actually need a list you are much better off using the one provided by the STL

struct Node; //we’ll define this laterclass List {public:

List(); // Default constructorList(const List&); // copy constructorList& operator=(const List&); //assign

operator~List(); // destructorint length();void insert_at_front(int value);bool insert_after_current(int value);void delete_first();void delete_after_current();void set_current_to_front();void advance_current();int get_current_value();bool check_current_in_list();

private:Node *head;Node *current;

};

Default Constructor

• Should construct a default valued list

• We’ll make that an empty listList::List() {

head = 0;current = 0;

}

• Can also write it inside the class definition:List() : head(0), current(0) {}

Copy ConstructorList::List(const List& o) {if (o.head == 0) {

head = current = 0;} else {

head = new Node(*(o.head));current = 0;for (Node *c1=head,*c2=o.head;c2->next;c1=c1->next;c2=c2->next) {

c1->next=new Node(*(c2->next));if (o.current == c2) current = c1;

}}

};

Destructor

List::~List() {Node *current = head;while (current) {

Node *remove = current;current = current->next;delete remove;

}}

Assignment Operator

• Normally an assignment operator does the following:– Check for equivalence– destroy the current object– copy the object across– return a reference to the object (to allow

chaining)

List& List::operator=(const List &o) {if (this == &orig)

return *this;Node *current = head;while (current) {

Node *remove = current;current = current->next;delete remove;

}if (o.head == 0) {

head = current = 0;} else {

head = new Node(*(o.head));current = 0;

for (Node *c1=head,*c2=o.head;c2->next;c1=c1->next;c2=c2->next) {

c1->next = new Node(*c2->next);if (o.current == c2)

current = c1;}

}return *this;

}

Member Functions

• Also known as methods

• Perform operations on the object

• Must always leave the object in a consistent state

length

int List::length() {int len = 0;for(Node *c=head;c;c=c->next)

count++;return count;

}

insert_at_front

void List::insert_at_front(intvalue){

Node *node = new Node;node->number = value;node->next = head;head = node;

}

insert_after_currentbool List::insert_after_current(int

value) {if (current == 0)

return false;Node *node = new Node;node->number = value;node->next = current->next;current->next = node;return true;

}

delete_firstvoid List::delete_first() {if (head==0)

return;Node *remove = head;head = head->next;if (current == remove)

current = 0;delete remove;

}

delete_after_current

void List::delete_after_current() {if (current==0 ||

current->next==0)return;

Node *remove = current->next;current->next =

current->next->next;delete remove;

}

set_current_to_front

void List::set_current_to_front()

{current = head;

}

advance_current

void List::advance_current() {if (current == 0)

return;current = current->next;

}

get_current_value

int List::get_current_value() {if (current == 0)

return 0;return current->number;

}

check_current_in_list

bool List::check_current_in_list()

{return current != 0;

}

The Node Struct

• In writing the List class some assumptions about the Node struct were made

• Now we have to write the Node struct so that those assumptions are met

Node

struct Node {int number;Node *next;

Node() : number(0),next(0){};Node(const Node &o) : number(o.number),next(0) {};

};

Memory Management

• C++ does not have a garbage collector

• The programmer much manually manage memory

• Memory needs to be allocated when needed

• It must be deallocated when not needed

• Not managing memory correctly is a major source of bugs in C++ code

C++ Memory Model

• Memory can be allocated from the stack or the heap

• Variables are allocated on the stack

• That memory is automatically deallocated

• Objects can be created on the heap with new

• That memory can be deallocated with delete

Allocating Memory

• new creates an object on the heap

• The appropriate constructor is called

• new[] creates an array on the heap

• The default constructor is called for each element of the array

int *i_array = new int[100];string *a_string = new string(“fred”);

Deallocating Memory• delete calls an objects destructor

• The memory used is then released

• delete[] calls the destructor of each element of an array

• The memory used is then released

• Every object created with new must be deleted

• Every array created with new[] must be delete[]ed

More of the story

• new and delete don’t just manage memory

• They also call constructors and destructors

• Other resources are also allocated and released

• File handles, network connections, and file locks must be released along with memory

More about main()

• main can be passed argumentsint main(int argc, char **argv);int main(int argc, char *argv[]);

• This allows a program to access the command line arguments

• So a text editor can know what file to open

main() example

#include <iostream>int main(int argc, char **argv){for(int i=0;i<argc;i++)

std::cout << argv[i]<< std::endl;

}

Functions

• You can have many functions with the same name

• They just need different arguments

• This is very useful, but can get confusing

Example Functionsvoid foo(int val) {std::cout << “int\n”;

}void foo(char c) {std::cout << “char\n”;

}int main() {int I;char c;long l;foo( i );foo( c );foo( l );

}

Function Resolution

• C++ will often call functions implicitly in order to compile your code

• This is very useful since it means you can often write simpler code

• It is also dangerous since sometimes you don’t get what you meant

• It can also make code hard to understand

An Example

class Complex {public: Complex(int re=0, int im=0);};int distance( const Complex &a,

const Complex &b);

int main() {distance(1,2);

}

Classes as Types

• C++ allows you to create classes which act like built-in types

• Operator overloading is the tool for this

• It can be used for both good and evil

• Do not overuse it

• Do use it for output via ostream objects

Output via operator overloading

class List {friend ostream& operator<<(ostream &os,

const List &list);};ostream& operator<<(ostream &os,

const List &list) {for (Node *c=list.head;c;c=c->next)

os << c->number << ‘ ‘;}

Inheritance

• Inheritance in C++ is a little complicated

• The default behaviour is often not what you want

• The default behaviour is usually the most efficient behaviour not the most useful

class Warning_Indicator {public:

void turn_on() {std::cout << “Indicator on\n”;

}};class Warning_Buzzer {public:

void turn_on() {std::cout << “Buzzer on\n”;

}};void alarm(Warning_Indicator wi) {

wi.turn_on();}int main() {

Warning_Buzzer buzzer;alarm(buzzer);

}

A problem

• What does alarm(buzzer) do?• It is known as slicing - it is usually an error• The compiler creates a Warning_Indicator

object via it’s Copy Constructor from the Warning_Buzzer

• The fix is to pass a reference instead of an Object:

• void alarm(const Warning_Indicator &wi);

More Problems

• The program will still output “Indicator on”

• Now the problem is due to binding

• C++ defaults to compile time binding

• wi.turn_on() becomes a call to the turn_on member function of Warning_Indicator

• Even when a Warning_Buzzer is used, the Warning_Indicator member is called

The Solution

• The solution is to use run time binding

• In C++ that is done with the keyword virtual

class Warning_Indicator {public:virtual void turn_on();

};

Virtual

• A virtual function takes more time to call• An object with virtual functions takes up

more memory• The actual function to call is looked up at run

time• Looking up takes time• Storing the function in the object takes space

Accessibility and Inheritance

• private members can only be accessed by the class itself (and friends)

• protected members can also be accessed by classes that inherit from the class

• That is almost always a bad thing

• It prevents implementation changes later - the main benefit or OO programming

class Base {

public : i;

protected : j;

private : k;

};

class Child : public Base {

public:

void test() {

i = 1; // legal

j = 1; // illegal

k = 1; // illegal

}

};

Constructors and Inheritance

• If a base class has a constructor then it must be called

• By default the default constructor is called

• If you want to call a different constuctor then you need to use an initialiser

class Person {

public:

Person(const string& name);

};

class Student : public Person {

public:

Student(const string& name,

const string& sid) : Person(name) {

}

};

Destructors and Inheritance

• Destructors are automatically called

• However, if a class is to inherited from its destructor must be declared virtual

• Not doing so can result in resource leaks

Person *p =new Student(”Sam”,”9222194”);

delete p;

Abstract Classes

• Seperating interface and implementation is often wise

• In C++ you can do this with abstract classes

• An abstract class is one with at least one pure virtual function

An Abstract Example

class Security_Device {public:virtual turn_on() = 0;virtual turn_off() = 0;virtual is_on() = 0;

};

Multiple Inheritance

• C++ supports multiple inheritance

• Sometimes useful, but leads to problems

• Problems occur with diamond inheritance trees

• Multiple inheritance will not be needed for this course

Non-public Inheritance

• class B : private A– public and protected members of A are treated

as private– this applies to users of B, but not B itself

• class B : protected A– public members of A are treated as protected

• This allows implementation inheritance without interface inheritance