SlideShare a Scribd company logo
1 
(4) Basics of the C++ Programming Language 
Nico Ludwig (@ersatzteilchen)
2 
TOC 
● (4) Basics of the C++ Programming Language 
– Pointers: Call by Value versus Call by Reference 
– Automatic Arrays 
– Arrays and Pointer Decay 
– Pointers to Pointers 
– C-strings as Arrays and their Memory Representation 
– Basic C-string Functions 
● Sources: 
– Bruce Eckel, Thinking in C++ Vol I 
– Bjarne Stroustrup, The C++ Programming Language
3 
Passing Function Parameters by Value 
● By default, in C/C++ function parameters are getting passed by value. 
– This means that in a function a parameter is a copy of the passed argument. 
– Assigning to the parameter in the function won't affect the original argument! 
– A function like Swap() that swaps the contents of its arguments can't be implemented like so: 
int main(int argc, char* argv[]) 
{ 
int a = 12, b = 24; 
// Declaring Swap(): 
void Swap(int, int); 
// Calling Swap(): 
Swap(a, b); 
std::cout<<a<<" "<<b<<std::endl; 
return EXIT_SUCCESS; 
} 
// This is a buggy implementation of Swap()! 
void Swap(int first, int second) 
{ 
int temp = first; 
// Assignment affects only the parameter! 
first = second; 
// Assignment affects only the parameter! 
second = temp; 
}
4 
Addresses and Pointers 
● In C/C++ almost all "things" (e.g. in variables) have an address in memory. 
– At these addresses the addressed "things" reside in memory literally! 
– Addressable "things" are called l-values in C/C++. 
● The address of an l-value can be retrieved with the &-operator (the address-operator). Example: 
int i = 42; 
std::cout<<"The address of i is: "<<&i<<std::endl; 
● The address of an l-value can also be stored into another variable. 
– A variable that stores the address of another l-value is called pointer. 
– A pointer type has a syntax decoration of its addressed type with the *-symbol. 
int i = 42; // The addressed type is int. 
int* ip = &i; // Take the address of i and store it into the int-pointer ip. 
std::cout<<"The address of i is: "<<ip<<std::endl; // &-operator not used 
int *ip2 = &i, *ip3 = &i, * ip4 = &i; // Placement and pointer declarators. 
Just keep this simplified statement in mind: 
A pointer is a variable that stores the address of another variable. 
● Literals are objects that have no address in memory, 
so they are no l-values! C-string literals are l-values 
because of compatibility reasons. 
● W/o casting the address of a const can only be 
assigned to a const pointer.
5 
Pointers, Dereferencing and Indirection 
● Using pointers for indirect access to l-values: 
– Indirection: Via a pointer indirect access to the original l-value is possible. 
– Dereferencing: The prefix *-operator (the dereference-operator) allows to read/write the original l-value. 
int i = 42; 
std::cout<<"The value of i is: "<<i<<std::endl; // i's original value is 42. 
int* ip = &i; // Take the address of i and store it into the int-pointer ip. 
*ip = 300; // Dereference the pointer and assign 300 to the original l-value. 
std::cout<<"The value of i is: "<<i<<std::endl; // Will print 300 as i's value! 
● Pointers, indirection and dereferencing actually reflect real world scenarios: 
– (A) Indirection: blow up a ballon, and just pass around the cord. 
– (B) Dereferencing: means to coil up the ballon's cord, and catch the ballon. 
– (A) Indirection: tell a friend a URL to a site, instead of mailing a copy of the webpage. 
– (B) Dereferencing: loading the URL in a browser. 
– Semantic picture: Pointers are shortcuts to the objects they're pointing to!
6 
Features of Pointers 
● The size of all pointer types is the size of the architecture's address space. 
– On a 32-bit system: 4 = sizeof(int*), on a 64-bit system: 8 = sizeof(int*), etc. 
● Pointers of different types are incompatible generally. 
– Although just addresses (of equal size), an int* can't legally point to, e.g. a double*! 
– There is a generic pointer type, void*, compatible to almost all pointer types. 
● The value of an uninitialized pointer is undefined. 
– Pointers can be assigned to "pointing to nothing" with 0 (or NULL). 
● Pointers can be used in logical expressions, 0-pointers evaluate to false. 
● Dereferencing 0-pointers is undefined. 
● Other pointers: 
– It is also possible to define pointers to pointers to..., e.g. declared as int**, etc. 
– Finally it's possible to define function pointers, i.e. pointers to functions. 
C++11 – null pointer constant 
double* dp = nullptr; 
● In which "unit" does the sizeof operator return its 
result? 
● In std::size_t, a std::size_t of value 1 represents 
the sizeof(char). The type std::size_t is defined in 
<cstddef>. 
● The conversion between int* and double* can be 
forced, we'll discuss it on the next slide. 
● We can assign pointers of any pointer type to a 
void* without casting, this is why it is called "generic" 
pointer type. Exceptions: function pointers that need 
to be converted to void* with a reinterpret_cast and 
const pointers that need to be converted with a 
const_cast.
7 
Simple Features of Pointers in Code 
int i = 42; 
int* ip = &i; 
double* dp = ip; // Invalid! The pointer types int* and double* are incompatible. 
void* vp = ip; // OK: int* can be assigned to void*. 
// vp and ip point to same object (i); understand them both as shortcuts to i! 
int* ip2 = static_cast<int*>(vp); // Retrieve the int* from the generic void*. 
vp = 0; // Assigning 0 to a void*. 
if (!vp) { // vp evaluates to false, because its value is 0. 
std::cout<<"vp is 0!"<<std::endl; 
} 
int** ipp = &ip; // The address of an int* can be assigned to an int**. 
● We need a reinterpret_cast to convert from double* 
to int* and vice versa, because these types are 
unrelated. We'll discuss such so called "bit pattern" 
conversions and other possibly dangerous 
techniques in a future lecture. 
● We can assign any pointer type to a void* without 
casting, this is why it is called "generic" pointer type. 
Exceptions: function pointers that need to be 
converted to void* with a reinterpret_cast and const 
pointers that need to be converted with a 
const_cast.
8 
int main(int argc, char* argv[]) 
{ 
int a = 12, b = 24; 
// Declare Swap(): 
void Swap(int*, int*); 
// Calling Swap() passing addresses: 
Swap(&a, &b); 
std::cout<<a<<" "<<b<<std::endl; 
return EXIT_SUCCESS; 
} 
Passing Addresses as Arguments to Functions 
● Our Swap()-dilemma can be solved with indirection and dereferencing! 
– It is required to rewrite Swap() to handle addresses of variables via pointers! 
– So the arguments are not getting copied, but indirected via pointer. 
// This is a good implementation of Swap()! 
void Swap(int* first, int* second) 
{ 
// Dereference first and assign it. 
int temp = *first; 
// Assignment affects the addressed a! 
*first = *second; 
// Assignment affects the addressed b! 
*second = temp; 
} 
12 24 
12 24 
24 
12 
24 12 
0xbffff68, 
0xbffff64 
● Be aware that this no call by reference! - Pointers 
will still be passed by value, but the value to which 
the pointer points to can be modified by 
dereferencing the pointer, which allows indirect 
access to the value.
9 
Arrays – Part I 
● What is an array? In brief: arrays are like tables. 
– A table or list of elements of the same (static) type in a contiguous block of memory. 
– Its elements can be accessed randomly with O(1) complexity. 
– Arrays can neither grow nor shrink! Arrays can not be assigned. 
● What kinds of arrays exist? 
– One dimensional and "multidimensional" (rectangular only). 
– Automatically (stack) and dynamically (heap/freestore) sized arrays can be defined. 
– Also, statically (static memory) sized arrays can be defined (e.g. c-string literals). 
● => Array creation and initialization. 
– Can be created/initialized with a const length (w/ undefined values) w/ the []-declarator. 
● Automatic arrays cannot have the length 0! 
– Can be created/initialized with array initializers (also w/ a const length). 
– Can be filled with loops (esp. with for loops) using an index and the []-operator. 
● Mind that we can only create (dimension (verb)) 
automatic arrays of const length with our current 
knowledge. In the next lecture we learn how to 
handle arrays of dynamic size. 
• It should be mentioned that C99 does support 
variable length arrays (VLAs) on the stack.
10 
Arrays – Part II 
● Accessing array elements and array length. 
– The []-operator (aka index-, or subscript-operator) is used to access elements. 
– On array creation, the length of the array is specified with the []-declarator. 
– Arrays don't expose their (immutable) length. The program must carry it along. 
– The array-indexes are 0-based. - So the indexes' range is [0, length[. 
– If array access exceeds this range, the behavior is undefined. 
– Automatic arrays can't be returned from functions. 
● In code, arrays often get decayed to a pointer to their first element automatically: 
– If they're passed to functions or used with operators to apply pointer arithmetics. 
– In fact, arrays can't be passed by value, it would be too expensive. 
● Terminology alert for German programmers: Stick to calling an array array, not "Feld", even if German literature does! 
– A Feld is a field of a UDT! This is an example where translation is really inappropriate, leading to ridiculous misunderstandings. 
● Why is passing arrays by value too expensive 
● Mind that compiler and runtime usually also 
always use the term array. Either they are itself 
only printing English messages, or they print 
German messages, but stick to special terms. - 
The word array is a special term, not a word that 
needs to be translated!
Contiguous block of memory 
11 
Arrays in Brief – Code and Memory Representation 
// Creates an int-array with array initializer. int is the element type of this array. 
int myArray[] = {1, 2, 3, 4}; 
16B 
? 1 
2 3 4 myArray 
4B 
// Creates an array w/ a constant length of 4, with uninitialized int-elements. 
int myArray2[4]; 
// We can also use a partial initialization: 
int myArray3[4] = {1}; // Initializes remaining elements to 0. 
// This is invalid: we can't specify more values in the array initializer than 
// specified in the declarator. 
int myArray4[3] = {1, 2, 3, 4}; 
?? ? ? ? myArray2 
// For loops come in handy w/ arrays! In this loop the values from 1 to 4 get 
// assigned to each element of myArray2 with the []-operator. 
for (int i = 0; i < 4; ++i) { 
myArray2[i] = i + 1; 
} 
C++11 – C++/STL arrays 
#include <array> 
std::array<int, 4> myArray3{{0, 1, 2, 3}}; 
auto nCount = myArray3.size(); // Get array-size 
myArray3 = {4, 5, 6, 7}; // Assign 
1 2 3 4 myArray2 
C++11 – range-based for loop 
for (int item : myArray) { 
std::cout<<item<<std::endl; 
} 
● Array, pointer and const types of other types need 
not to be declared ahead like other UDTs. As 
compound types they are declared by their usage 
with the []- and *-declarators, respectively.
Arrays in Code – Passing to Functions and Decay to Pointer 
12 
// Foo() outputs the first length elements of the content of a. 
void Foo(int a[], int length) { 
for (int i = 0; i < length; ++i) { 
std::cout<<"Value at index "<<i<<": "<<a[i]<<std::endl; 
} 
} 
int anArray[] = {1, 2, 3, 4}; // Define and initialize an array of size 4. 
Foo(anArray, 4); // Pass the array and its size to Foo(). 
// Here an equivalent definition, where a is an explicitly declared pointer. 
void Foo(int* a, int length) { 
for (int i = 0; i < length; ++i) { 
std::cout<<"Value at index "<<i<<": "<<a[i]<<std::endl; 
} 
} 
● In C/C++ arrays of the same element type but 
having different lengths are of different type! So 
int[2] and int[4] are different types, but pointer-decay 
makes them compatible somewhat, then both are 
just int*.
13 
"Multidimensional" Arrays in C++ 
● C++ allows the definition of arrays that act like "multidimensional" (m.d.) arrays. 
– Multidimensional arrays are equivalent to "normal" arrays in C/C++. 
● The memory layout is equivalent for both. 
● The memory layout of C/++ arrays is done by row-major order, in which the rows are laid down in linear memory after another. 
– C++ provides alternative syntaxes for defining and accessing "mimicked" m.d. arrays. 
– The definition/initialization syntax differs: 
// Creates a "multidimensional" 2x3 array: 
int mArray[2][3]; 
// With array literals: 
int mArray2[2][3] = {{1, 2, 3}, {4, 5, 6}}; 
// The last dimension must be specified: 
int mArray3[][3] = {{1, 2, 3}, {4, 5, 6}}; 
// Creates a "normal" 6 array. 
int array[6]; 
– The syntax accessing elements is done via multiple []-operators respectively. 
for (int i = 0; i < 6; ++i) { 
array[i] = 0; // Uses i as index. 
} 
for (int i = 0; i < 2; ++i) { // 1. "dimension" (columns) 
for (int j = 0; j < 3; ++j) { // 2. "dimension" (rows) 
mArray[i][j] = 0; // Uses i and j as "coordinates". 
} 
} 
1 2 3 4 5 6 array 
1 2 3 4 5 6 mArray 
● Multidimensional arrays are often used to mimic 
matrices in very-beginner's C/C++ exercises. 
● As a matter of fact multidimensional arrays are 
nowhere used in the C++ standard libraries. There 
are better alternatives and they are usually not 
used in application programming. Sometimes 
multidimensional arrays can be useful in very low 
level code to get more performance, but these 
performance benefits are typically very small. 
● The memory layout of arrays and multidimensional 
arrays is equivalent. For multidimensional arrays no 
"rectangular", multidimensional region in memory is 
reserved, it is just a "one-dimensional" sequence of 
bytes as for "normal" arrays. 
● A m.d. array can consume very much memory if it 
has many dimensions (even if the array is not 
filled).
14 
A Cause why multidimensional Arrays should be avoided 
● Functions accepting multidimensional arrays are awkward! 
// Wrong! Straight forward: pass dimensions extra! NO! This leads to wrong implementation. 
void Bar(int ma[][], int dim1, int dim2) { // int ma[][] is an invalid syntax for a parameter type! 
for (int i = 0; i < dim1; ++i) { // 1. "dimension" (columns) 
for (int j = 0; j < dim2; ++j) { // 2. "dimension" (rows) 
ma[i][j] = 0; 
} 
} 
} 
// Correct! Explicit: Bad, not flexible. 
void Bar(int ma[2][3], int dim1, int dim2) { /* pass */ } 
// Correct! Pass dimensions extra: bad, weird implementation. 
void Bar(int* ma, int dim1, int dim2) { 
for (int i = 0; i < dim1; ++i) { // 1. "dimension" (columns) 
for (int j = 0; j < dim2; ++j) { // 2. "dimension" (rows) 
ma[i * dim2 + j] = 0; // Correct, but awkward syntax! 
} 
} 
} 
// Correct! Explicit: Bad, not flexible, the last 
// dimension needs to be passed at minimum. 
void Bar(int ma[][3], int dim1) { /* pass */ } 
Correct Wrong 
● As can be seen in the last correct example, 
accessing an array defines, whether it is a "normal" 
one or a multidimensional one.
15 
Typedefs 
● C/C++ allow to define syntactic "shortcuts" for compound type names/definitions with typedefs: 
typedef int Triple[3]; // typedef of int[3] named Triple. 
typedef int TripleCubeMatrix[3][3]; // typedef of int[3][3] named TripleCubeMatrix. 
typedef int* IntPointer; // typedef of int* named IntPointer. 
– Mind, how typedefs do also allow to name compound types nicely. 
● When the typedefs are in place, we can use them instead of the shortcut type name: 
void TransposeMatrix(TripleCubeMatrix matrix){ /* pass */ } 
TripleCubeMatrix mesh = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 
TransposeMatrix(mesh); 
void TransposeMatrix(int matrix[3][3]){ /* pass */ } 
int[3][3] mesh = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 
TransposeMatrix(mesh); 
● typedefs are examples of user defined types (UDTs), we'll come back to those in future lectures. 
– Mind, that we wrote the name of the UDT in PascalCase notation, this will be our convention to name UDTs. 
● typedefs play an important role in the STL to hide 
the virtual type behind a typedef to allow library 
vendors/compiler builders to create individual 
solutions. 
● Another kind of types, whose full names can be 
shortcut nicely with typedefs, are template 
instances. This idiom is also present in the STL.
16 
Arrays and Pointers 
● Pointers allow sharing data: 
– Passing arguments as (differing) pointers to the same data (shortcuts). 
● Pointers avoid data copies: 
– Big blocks of memory (like arrays and structs) need not to be copied. 
– The key of C's performance is using pointers that way! 
● Arrays and pointers enable dealing with raw memory in C/C++: 
– Manual memory management with dynamic memory. 
– Pointer arithmetics. 
– Binding pointers to memory allows programming of hardware-near drivers. 
– Arrays are a primary construct of imperative programming. 
● Operations on c-strings! 
● What is pointer arithmetics? 
● Arithmetics is the theory of basic calculation with 
numbers. Elementary arithmetics describe the 
operators +, - ,* and /. 
● Arithmetics with pointers deal with elementary 
arithmetic operators with pointers.
17 
From chars to C-strings 
● Working with c-strings is awkward, but required and widely used! 
● Generally, string datatypes are those types that hold textual data. 
● Individual letters can be held by char/wchar_t elements each. 
● So, a collection of multiple char/wchar_ts will make up a complete string. 
– Each char/wchar_t will represent a letter respectively. 
– C/C++ provide an intrinsic way to represent "collections of elements": arrays. 
● To distinguish bare char/wchar_t arrays from such representing c-strings, the "c-string-arrays" need to be 0-terminated! 
– This means that the very last item of the char-array needs to be a 0 (or '0')! 
– Considering the length of a char-array to be len, then the count of letters in a c-string is indeed len - 1!
18 
C-string Literals and their Array Nature 
● C-string literals are represented by literally written text within double-quotes. 
"bar"; // C-string literal, this is an array of 4 chars, 3 + 0-termination. 
L"foo"; // W-c-string literal, this is an array of 4 wchar_ts, 3 + 0-termination. 
● The type of a c-string literal is const char[] or const wchar_t[]. 
– C-string literals are stored in the so-called static portion of memory. 
– The decayed form of a c-string boils down to the types const char* or const wchar_t*. 
● For c-strings are arrays, neither can they be assigned nor resized directly. 
– Special functions and dynamic memory must be used instead. 
● Esp. the comparison of c-strings can not be done via relational operators! 
– Relational operators would compare the decayed pointers, not the c-string contents! 
– Pointer comparison is about identity, but c-string comparison is about equality. 
● Instead of relational operators, special functions must be used as well. 
● What does "comparison of decayed pointers" 
mean? 
● => It means that the addresses (i.e. the contents 
of these pointers) will be compared.
19 
C-string Traps: Assignment and Comparison 
● Invalid examples (initialization, invalid c-string assignment and invalid c-string "extension"): 
const char* aString = "Mallorca"; // Initialization of a c-string. 
aString = "Teneriffa"; // Invalid! Can't assign a c-string (or array)! 
const wchar_t* aWString = L"Weyland Yutani"; // Initialization of a w-c-string. 
aWString += L" at LV-426"; // Invalid! Can't extend a w-c-string (or array)! 
● Example of wrong comparison: 
const char* fstName = "Frank"; 
const char* sndName = "Frank"; 
// Semantically wrong! The == operator compares the pointers for identity 
// (i.e. the addresses), not the c-strings' contents for equality! 
if (fstName == sndName) { 
std::cout<<"fstName and sndName are equal!"<<std::endl; 
}
20 
C-strings: Literals with Escape Sequences 
● Escape sequences are char-sequences with special meaning. 
● Within a c-string literal we can't use the "-char directly, it must be "escaped". 
– Why is it impossible? Because the compiler has to know the limits of a c-string literal. 
const char text[] = "Wen"dy"; // Compiler in trouble: is that "Wen" or "Wen"dy"? 
– In C/C++ there exists a set of escape sequences, one of them solves this problem: 
const char text[] = "Wen"dy" // OK, just use the escape sequence ". "Wen"dy" 
● Some "letters" can't be expressed as chars, escape sequences will rescue us. 
– Such "letters" are often so called "control codes", let's examine some of them: 
● Inserting a newline into a literal (rn means "carriage return" and "newline"): 
std::cout<<"Jarn"<<std::endl; // rn will add a blank line below "Ja" on console. 
● Inserting a tab into a literal (t): 
std::cout<<"atb"<<std::endl; // t will add a tab between a and b on console.
// A c-string. 
const char* aString = "bar"; 
// The size of aString is 4, but its length is 3! 
std::size_t size = sizeof(aString); ? 'a' 'r' 0 aString 
21 
C-strings in Memory – Length and Size 
'b' 
0 
● … but we need to get the count of letters in a c-string, not the size (i.e. the size in bytes)! 
– There are always the 0-termination's extra bytes contributing to the size in bytes. 
– The size is inappropriate in the case of w-c-strings altogether! 
– Extra C-functions must be used with c-strings to work with string lengths. 
– Let's learn about these functions... 
char 1B 
4B 
0-termination 
// A w-c-string. 
const wchar_t* aWString = L"foo"; 
// The size of aWString is 8, but its length is 3! 
std::size_t wsize = sizeof(aWString); ? 'f' 0 'o' aWString 
wchar_t 2B 
(big endian) 
0-termination 
0? 'o' 0 0 
8B 
● What is "big endian"? 
● When we have data that is composed of multiple 
bytes (i.e. integers greater than 1B or character 
types greater than 1B (But not multiple chars of a 
c-string!)), these bytes can be arranged in 
memory in different byte orders. 
● On big endian byte order, the most significant bits 
resides (i.e. the bits contributing the highest 
amount to the value) on lowest address of the 
value in memory. This order directly reflects the 
"reading direction" of the value. -> 68000 and 
PowerPC (default) A c-string is always stored in 
big endian order (but not necessarily its 
char/wchar_t elements), because pointer 
arithmetics must work w/ all kinds of arrays. 
● On little endian byte order, the most significant 
bits reside on the highest address of the value in 
memory. This order reverses the byte sequence 
and the "reading direction" of the value in 
memory. -> Intel
22 
Basic C-string Functions 
● Via the []-operator, all elements (the "letters") of a c-string can be accessed. 
– However, because we deal with a const char-array, the elements can't be assigned! 
● Following functions in <cstring> specially deal with c-strings: 
– Getting the length (count of "letters" w/o 0) of a c-string with std::strlen(). 
– Comparing two c-strings with std::strcmp(). 
– Searching a single char within a c-string with std::strchr() (and std::strrchr()). 
– Searching a substring within a c-string with std::strstr(). 
● The functions operating with w-c-strings, can be found in <cwchar>. 
● General implementation of the c-string functions: 
– Parameters are always char-pointers, passed char-arrays decay to pointers. 
– The implementation is based on a loop over the c-string until 0-termination. 
● In a past lecture we've already discussed how to read lines of c-strings via std::cin.getline().
23 
C-strings: Length and Element Access 
● Correct way of getting the length of a c-string: 
const char* aString = "bar"; // A c-string. 
std::size_t size = sizeof(aString); // The size of aString is 4, but its length is 3! 
std::size_t len = std::strlen(aString); // Correct: The length of aString is 3. 
● Having len, we can access each element ("letter") of aString via the []-operator: 
for (int i = 0; i < len; ++i) { // Virtually i should be of std::size_t, but declaring i 
// as int is the canonical form... 
std::cout<<aString[i]<<std::endl; // Accessing the c-string as array. 
} 
● But, we can't assign/modify the elements of aString, because it's const. 
aString[1] = 'u'; // Invalid! Assignment to const not allowed.
24 
C-strings: Comparison 
int strcmp(const char* lhs, const char* rhs); 
● The function accepts two c-strings to compare. 
– The returned int is 0, if the compared c-strings are case-sensitively equal. 
– The returned int is less than 0, if lhs is lexicographically less than rhs. 
– The returned int is greater than 0, if lhs is lexicographically greater than rhs. 
● Let's review and correct the earlier example of c-string comparison: 
const char* fstName = "Frank"; 
const char* sndName = "Frank"; 
// Correct. std::strcmp() returns 0, because these c-strings are equal! 
if (0 == std::strcmp(fstName, sndName)) 
{ 
std::cout<<"fstName and sndName are equal!"<<std::endl; 
} 
● Upper case letters are considered "less than" lower 
case letters. 
● C/C++ don't provide a way to perform a case-insensitive 
c-string comparison. We have to code it 
ourself (e.g. via std::tolower() or std::toupper()).
25 
C-strings: Searching individual chars 
● Searching an individual char: 
const char* aString = "bar"; // Search the first 'a' in aString, 
const char* result = std::strchr(aString, 'a'); // result will point to substring "ar". 
result = std::strchr(aString, 'z'); // There is no 'z' in aString, so result is 0. 
● Searching all occurrences of an individual char: 
const char* aString = "bananas"; 
const char* result = std::strchr(aString, 'a'); // Search the first 'a' in aString. 
int occurrences = 0; 
while (0 != result) { // While the substring addressed by result is not 0: 
++occurrences; // 1. Increment occurrences. 
++result; // 2. Advance result to next char. 
result = std::strchr(result, 'a'); // 3. Search next 'a' in result. 
}
26 
C-strings: Searching Substrings 
● A substring is simply a part or portion of a whole string. 
● Searching a substring in another string: 
const char* aString = "thinking"; // Search substring "ki" in aString, 
const char* result = std::strstr(aString, "ki"); // result will point to substring "king". 
result = std::strstr(aString, "zap"); // There is no "zap" in aString, so result is 0. 
● Searching all occurrences of a substring in another string: 
– The implementation follows the same pattern as searching the occurrences of individual chars.
27 
An Example for Pointers to Pointers: Arrays of C-strings 
● Pointer to pointers are not rare in C/C++. 
– In C/C++ we often need to deal with arrays of pointers. 
– In general programming we have often to deal with arrays of c-strings. 
– As c-strings are char* and C's arrays decay to pointers we end in a char**. 
// An array of c-strings (the usage of []-declarator is needed in order to use the array initializer). 
const char* names[] = {"Mary", "Jake", "Diane"}; 
// An array of c-strings decays to a char-pointer-pointer. 
const char** alsoNames = names; 
● Array initializers can not be used to initialize a 
char**.
28 
Thank you!

More Related Content

PPT
Advanced C programming
PPTX
Integers pointers | By Vikram Snehi
PPT
Void pointer in c
PPT
Practical Meta Programming
PPT
Bsc cs 1 pic u-5 pointer, structure ,union and intro to file handling
PPT
pointer, structure ,union and intro to file handling
PPT
Mca 1 pic u-5 pointer, structure ,union and intro to file handling
Advanced C programming
Integers pointers | By Vikram Snehi
Void pointer in c
Practical Meta Programming
Bsc cs 1 pic u-5 pointer, structure ,union and intro to file handling
pointer, structure ,union and intro to file handling
Mca 1 pic u-5 pointer, structure ,union and intro to file handling

What's hot (20)

PPT
pointer, structure ,union and intro to file handling
PDF
C Programming Assignment
DOC
Assignment c programming
PPTX
Presentation 2nd
PPT
C++ Advanced
PDF
Pointers-Computer programming
PPTX
Computer programming(CP)
PDF
C reference manual
PDF
12 computer science_notes_ch01_overview_of_cpp
PDF
Strings-Computer programming
PDF
C Programming - Refresher - Part II
PPT
Glimpses of C++0x
PPTX
Structured Languages
PPTX
C traps and pitfalls for C++ programmers
PPTX
Modern C++
PPSX
INTRODUCTION TO C PROGRAMMING
PPTX
Presentation 5th
PPT
Lap trinh C co ban va nang cao
PDF
Data types in c++
pointer, structure ,union and intro to file handling
C Programming Assignment
Assignment c programming
Presentation 2nd
C++ Advanced
Pointers-Computer programming
Computer programming(CP)
C reference manual
12 computer science_notes_ch01_overview_of_cpp
Strings-Computer programming
C Programming - Refresher - Part II
Glimpses of C++0x
Structured Languages
C traps and pitfalls for C++ programmers
Modern C++
INTRODUCTION TO C PROGRAMMING
Presentation 5th
Lap trinh C co ban va nang cao
Data types in c++
Ad

Viewers also liked (7)

PPT
C chap22
PPT
General Functors ...
DOCX
C++ Template
PPTX
Templates
PPT
Templates
PPTX
Templates presentation
PPTX
Templates in C++
C chap22
General Functors ...
C++ Template
Templates
Templates
Templates presentation
Templates in C++
Ad

Similar to (4) cpp automatic arrays_pointers_c-strings (20)

ODP
(2) cpp imperative programming
PDF
Session 2 - Objective-C basics
PDF
(2) cpp imperative programming
PDF
(3) cpp procedural programming
PDF
C programming language
PDF
(5) cpp dynamic memory_arrays_and_c-strings
PPT
btech-1picu-5pointerstructureunionandintrotofilehandling-150122010700-conver.ppt
PDF
C Pointers
PDF
(4) cpp abstractions references_copies_and_const-ness
PPT
Introduction to C#
PPT
Diploma ii cfpc- u-5.1 pointer, structure ,union and intro to file handling
PDF
Review of c_sharp2_features_part_iii
PPT
Btech 1 pic u-5 pointer, structure ,union and intro to file handling
PDF
Embedded C The IoT Academy
PPTX
Introduction Of C++
PDF
C- language Lecture 5
PDF
C tour Unix
PPTX
venkatesh.pptx
PDF
(3) c sharp introduction_basics_part_ii
PDF
Functions And Header Files In C++ | Bjarne stroustrup
(2) cpp imperative programming
Session 2 - Objective-C basics
(2) cpp imperative programming
(3) cpp procedural programming
C programming language
(5) cpp dynamic memory_arrays_and_c-strings
btech-1picu-5pointerstructureunionandintrotofilehandling-150122010700-conver.ppt
C Pointers
(4) cpp abstractions references_copies_and_const-ness
Introduction to C#
Diploma ii cfpc- u-5.1 pointer, structure ,union and intro to file handling
Review of c_sharp2_features_part_iii
Btech 1 pic u-5 pointer, structure ,union and intro to file handling
Embedded C The IoT Academy
Introduction Of C++
C- language Lecture 5
C tour Unix
venkatesh.pptx
(3) c sharp introduction_basics_part_ii
Functions And Header Files In C++ | Bjarne stroustrup

More from Nico Ludwig (20)

PPTX
Grundkurs fuer excel_part_v
PPTX
Grundkurs fuer excel_part_iv
PPTX
Grundkurs fuer excel_part_iii
PPTX
Grundkurs fuer excel_part_ii
PPTX
Grundkurs fuer excel_part_i
PDF
(2) gui drawing
ODP
(2) gui drawing
PDF
(1) gui history_of_interactivity
ODP
(1) gui history_of_interactivity
PDF
New c sharp4_features_part_vi
PDF
New c sharp4_features_part_v
PDF
New c sharp4_features_part_iv
ODP
New c sharp4_features_part_iii
PDF
New c sharp4_features_part_ii
PDF
New c sharp4_features_part_i
PDF
New c sharp3_features_(linq)_part_v
PDF
New c sharp3_features_(linq)_part_iv
ODP
New c sharp3_features_(linq)_part_iv
PDF
New c sharp3_features_(linq)_part_iii
PDF
New c sharp3_features_(linq)_part_ii
Grundkurs fuer excel_part_v
Grundkurs fuer excel_part_iv
Grundkurs fuer excel_part_iii
Grundkurs fuer excel_part_ii
Grundkurs fuer excel_part_i
(2) gui drawing
(2) gui drawing
(1) gui history_of_interactivity
(1) gui history_of_interactivity
New c sharp4_features_part_vi
New c sharp4_features_part_v
New c sharp4_features_part_iv
New c sharp4_features_part_iii
New c sharp4_features_part_ii
New c sharp4_features_part_i
New c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_ii

Recently uploaded (20)

PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Electronic commerce courselecture one. Pdf
PDF
Empathic Computing: Creating Shared Understanding
PDF
Machine learning based COVID-19 study performance prediction
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PPTX
Programs and apps: productivity, graphics, security and other tools
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Big Data Technologies - Introduction.pptx
PDF
Network Security Unit 5.pdf for BCA BBA.
PPTX
Cloud computing and distributed systems.
PPTX
sap open course for s4hana steps from ECC to s4
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Chapter 3 Spatial Domain Image Processing.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
Per capita expenditure prediction using model stacking based on satellite ima...
Electronic commerce courselecture one. Pdf
Empathic Computing: Creating Shared Understanding
Machine learning based COVID-19 study performance prediction
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Spectral efficient network and resource selection model in 5G networks
Building Integrated photovoltaic BIPV_UPV.pdf
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Dropbox Q2 2025 Financial Results & Investor Presentation
Programs and apps: productivity, graphics, security and other tools
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Unlocking AI with Model Context Protocol (MCP)
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Big Data Technologies - Introduction.pptx
Network Security Unit 5.pdf for BCA BBA.
Cloud computing and distributed systems.
sap open course for s4hana steps from ECC to s4
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...

(4) cpp automatic arrays_pointers_c-strings

  • 1. 1 (4) Basics of the C++ Programming Language Nico Ludwig (@ersatzteilchen)
  • 2. 2 TOC ● (4) Basics of the C++ Programming Language – Pointers: Call by Value versus Call by Reference – Automatic Arrays – Arrays and Pointer Decay – Pointers to Pointers – C-strings as Arrays and their Memory Representation – Basic C-string Functions ● Sources: – Bruce Eckel, Thinking in C++ Vol I – Bjarne Stroustrup, The C++ Programming Language
  • 3. 3 Passing Function Parameters by Value ● By default, in C/C++ function parameters are getting passed by value. – This means that in a function a parameter is a copy of the passed argument. – Assigning to the parameter in the function won't affect the original argument! – A function like Swap() that swaps the contents of its arguments can't be implemented like so: int main(int argc, char* argv[]) { int a = 12, b = 24; // Declaring Swap(): void Swap(int, int); // Calling Swap(): Swap(a, b); std::cout<<a<<" "<<b<<std::endl; return EXIT_SUCCESS; } // This is a buggy implementation of Swap()! void Swap(int first, int second) { int temp = first; // Assignment affects only the parameter! first = second; // Assignment affects only the parameter! second = temp; }
  • 4. 4 Addresses and Pointers ● In C/C++ almost all "things" (e.g. in variables) have an address in memory. – At these addresses the addressed "things" reside in memory literally! – Addressable "things" are called l-values in C/C++. ● The address of an l-value can be retrieved with the &-operator (the address-operator). Example: int i = 42; std::cout<<"The address of i is: "<<&i<<std::endl; ● The address of an l-value can also be stored into another variable. – A variable that stores the address of another l-value is called pointer. – A pointer type has a syntax decoration of its addressed type with the *-symbol. int i = 42; // The addressed type is int. int* ip = &i; // Take the address of i and store it into the int-pointer ip. std::cout<<"The address of i is: "<<ip<<std::endl; // &-operator not used int *ip2 = &i, *ip3 = &i, * ip4 = &i; // Placement and pointer declarators. Just keep this simplified statement in mind: A pointer is a variable that stores the address of another variable. ● Literals are objects that have no address in memory, so they are no l-values! C-string literals are l-values because of compatibility reasons. ● W/o casting the address of a const can only be assigned to a const pointer.
  • 5. 5 Pointers, Dereferencing and Indirection ● Using pointers for indirect access to l-values: – Indirection: Via a pointer indirect access to the original l-value is possible. – Dereferencing: The prefix *-operator (the dereference-operator) allows to read/write the original l-value. int i = 42; std::cout<<"The value of i is: "<<i<<std::endl; // i's original value is 42. int* ip = &i; // Take the address of i and store it into the int-pointer ip. *ip = 300; // Dereference the pointer and assign 300 to the original l-value. std::cout<<"The value of i is: "<<i<<std::endl; // Will print 300 as i's value! ● Pointers, indirection and dereferencing actually reflect real world scenarios: – (A) Indirection: blow up a ballon, and just pass around the cord. – (B) Dereferencing: means to coil up the ballon's cord, and catch the ballon. – (A) Indirection: tell a friend a URL to a site, instead of mailing a copy of the webpage. – (B) Dereferencing: loading the URL in a browser. – Semantic picture: Pointers are shortcuts to the objects they're pointing to!
  • 6. 6 Features of Pointers ● The size of all pointer types is the size of the architecture's address space. – On a 32-bit system: 4 = sizeof(int*), on a 64-bit system: 8 = sizeof(int*), etc. ● Pointers of different types are incompatible generally. – Although just addresses (of equal size), an int* can't legally point to, e.g. a double*! – There is a generic pointer type, void*, compatible to almost all pointer types. ● The value of an uninitialized pointer is undefined. – Pointers can be assigned to "pointing to nothing" with 0 (or NULL). ● Pointers can be used in logical expressions, 0-pointers evaluate to false. ● Dereferencing 0-pointers is undefined. ● Other pointers: – It is also possible to define pointers to pointers to..., e.g. declared as int**, etc. – Finally it's possible to define function pointers, i.e. pointers to functions. C++11 – null pointer constant double* dp = nullptr; ● In which "unit" does the sizeof operator return its result? ● In std::size_t, a std::size_t of value 1 represents the sizeof(char). The type std::size_t is defined in <cstddef>. ● The conversion between int* and double* can be forced, we'll discuss it on the next slide. ● We can assign pointers of any pointer type to a void* without casting, this is why it is called "generic" pointer type. Exceptions: function pointers that need to be converted to void* with a reinterpret_cast and const pointers that need to be converted with a const_cast.
  • 7. 7 Simple Features of Pointers in Code int i = 42; int* ip = &i; double* dp = ip; // Invalid! The pointer types int* and double* are incompatible. void* vp = ip; // OK: int* can be assigned to void*. // vp and ip point to same object (i); understand them both as shortcuts to i! int* ip2 = static_cast<int*>(vp); // Retrieve the int* from the generic void*. vp = 0; // Assigning 0 to a void*. if (!vp) { // vp evaluates to false, because its value is 0. std::cout<<"vp is 0!"<<std::endl; } int** ipp = &ip; // The address of an int* can be assigned to an int**. ● We need a reinterpret_cast to convert from double* to int* and vice versa, because these types are unrelated. We'll discuss such so called "bit pattern" conversions and other possibly dangerous techniques in a future lecture. ● We can assign any pointer type to a void* without casting, this is why it is called "generic" pointer type. Exceptions: function pointers that need to be converted to void* with a reinterpret_cast and const pointers that need to be converted with a const_cast.
  • 8. 8 int main(int argc, char* argv[]) { int a = 12, b = 24; // Declare Swap(): void Swap(int*, int*); // Calling Swap() passing addresses: Swap(&a, &b); std::cout<<a<<" "<<b<<std::endl; return EXIT_SUCCESS; } Passing Addresses as Arguments to Functions ● Our Swap()-dilemma can be solved with indirection and dereferencing! – It is required to rewrite Swap() to handle addresses of variables via pointers! – So the arguments are not getting copied, but indirected via pointer. // This is a good implementation of Swap()! void Swap(int* first, int* second) { // Dereference first and assign it. int temp = *first; // Assignment affects the addressed a! *first = *second; // Assignment affects the addressed b! *second = temp; } 12 24 12 24 24 12 24 12 0xbffff68, 0xbffff64 ● Be aware that this no call by reference! - Pointers will still be passed by value, but the value to which the pointer points to can be modified by dereferencing the pointer, which allows indirect access to the value.
  • 9. 9 Arrays – Part I ● What is an array? In brief: arrays are like tables. – A table or list of elements of the same (static) type in a contiguous block of memory. – Its elements can be accessed randomly with O(1) complexity. – Arrays can neither grow nor shrink! Arrays can not be assigned. ● What kinds of arrays exist? – One dimensional and "multidimensional" (rectangular only). – Automatically (stack) and dynamically (heap/freestore) sized arrays can be defined. – Also, statically (static memory) sized arrays can be defined (e.g. c-string literals). ● => Array creation and initialization. – Can be created/initialized with a const length (w/ undefined values) w/ the []-declarator. ● Automatic arrays cannot have the length 0! – Can be created/initialized with array initializers (also w/ a const length). – Can be filled with loops (esp. with for loops) using an index and the []-operator. ● Mind that we can only create (dimension (verb)) automatic arrays of const length with our current knowledge. In the next lecture we learn how to handle arrays of dynamic size. • It should be mentioned that C99 does support variable length arrays (VLAs) on the stack.
  • 10. 10 Arrays – Part II ● Accessing array elements and array length. – The []-operator (aka index-, or subscript-operator) is used to access elements. – On array creation, the length of the array is specified with the []-declarator. – Arrays don't expose their (immutable) length. The program must carry it along. – The array-indexes are 0-based. - So the indexes' range is [0, length[. – If array access exceeds this range, the behavior is undefined. – Automatic arrays can't be returned from functions. ● In code, arrays often get decayed to a pointer to their first element automatically: – If they're passed to functions or used with operators to apply pointer arithmetics. – In fact, arrays can't be passed by value, it would be too expensive. ● Terminology alert for German programmers: Stick to calling an array array, not "Feld", even if German literature does! – A Feld is a field of a UDT! This is an example where translation is really inappropriate, leading to ridiculous misunderstandings. ● Why is passing arrays by value too expensive ● Mind that compiler and runtime usually also always use the term array. Either they are itself only printing English messages, or they print German messages, but stick to special terms. - The word array is a special term, not a word that needs to be translated!
  • 11. Contiguous block of memory 11 Arrays in Brief – Code and Memory Representation // Creates an int-array with array initializer. int is the element type of this array. int myArray[] = {1, 2, 3, 4}; 16B ? 1 2 3 4 myArray 4B // Creates an array w/ a constant length of 4, with uninitialized int-elements. int myArray2[4]; // We can also use a partial initialization: int myArray3[4] = {1}; // Initializes remaining elements to 0. // This is invalid: we can't specify more values in the array initializer than // specified in the declarator. int myArray4[3] = {1, 2, 3, 4}; ?? ? ? ? myArray2 // For loops come in handy w/ arrays! In this loop the values from 1 to 4 get // assigned to each element of myArray2 with the []-operator. for (int i = 0; i < 4; ++i) { myArray2[i] = i + 1; } C++11 – C++/STL arrays #include <array> std::array<int, 4> myArray3{{0, 1, 2, 3}}; auto nCount = myArray3.size(); // Get array-size myArray3 = {4, 5, 6, 7}; // Assign 1 2 3 4 myArray2 C++11 – range-based for loop for (int item : myArray) { std::cout<<item<<std::endl; } ● Array, pointer and const types of other types need not to be declared ahead like other UDTs. As compound types they are declared by their usage with the []- and *-declarators, respectively.
  • 12. Arrays in Code – Passing to Functions and Decay to Pointer 12 // Foo() outputs the first length elements of the content of a. void Foo(int a[], int length) { for (int i = 0; i < length; ++i) { std::cout<<"Value at index "<<i<<": "<<a[i]<<std::endl; } } int anArray[] = {1, 2, 3, 4}; // Define and initialize an array of size 4. Foo(anArray, 4); // Pass the array and its size to Foo(). // Here an equivalent definition, where a is an explicitly declared pointer. void Foo(int* a, int length) { for (int i = 0; i < length; ++i) { std::cout<<"Value at index "<<i<<": "<<a[i]<<std::endl; } } ● In C/C++ arrays of the same element type but having different lengths are of different type! So int[2] and int[4] are different types, but pointer-decay makes them compatible somewhat, then both are just int*.
  • 13. 13 "Multidimensional" Arrays in C++ ● C++ allows the definition of arrays that act like "multidimensional" (m.d.) arrays. – Multidimensional arrays are equivalent to "normal" arrays in C/C++. ● The memory layout is equivalent for both. ● The memory layout of C/++ arrays is done by row-major order, in which the rows are laid down in linear memory after another. – C++ provides alternative syntaxes for defining and accessing "mimicked" m.d. arrays. – The definition/initialization syntax differs: // Creates a "multidimensional" 2x3 array: int mArray[2][3]; // With array literals: int mArray2[2][3] = {{1, 2, 3}, {4, 5, 6}}; // The last dimension must be specified: int mArray3[][3] = {{1, 2, 3}, {4, 5, 6}}; // Creates a "normal" 6 array. int array[6]; – The syntax accessing elements is done via multiple []-operators respectively. for (int i = 0; i < 6; ++i) { array[i] = 0; // Uses i as index. } for (int i = 0; i < 2; ++i) { // 1. "dimension" (columns) for (int j = 0; j < 3; ++j) { // 2. "dimension" (rows) mArray[i][j] = 0; // Uses i and j as "coordinates". } } 1 2 3 4 5 6 array 1 2 3 4 5 6 mArray ● Multidimensional arrays are often used to mimic matrices in very-beginner's C/C++ exercises. ● As a matter of fact multidimensional arrays are nowhere used in the C++ standard libraries. There are better alternatives and they are usually not used in application programming. Sometimes multidimensional arrays can be useful in very low level code to get more performance, but these performance benefits are typically very small. ● The memory layout of arrays and multidimensional arrays is equivalent. For multidimensional arrays no "rectangular", multidimensional region in memory is reserved, it is just a "one-dimensional" sequence of bytes as for "normal" arrays. ● A m.d. array can consume very much memory if it has many dimensions (even if the array is not filled).
  • 14. 14 A Cause why multidimensional Arrays should be avoided ● Functions accepting multidimensional arrays are awkward! // Wrong! Straight forward: pass dimensions extra! NO! This leads to wrong implementation. void Bar(int ma[][], int dim1, int dim2) { // int ma[][] is an invalid syntax for a parameter type! for (int i = 0; i < dim1; ++i) { // 1. "dimension" (columns) for (int j = 0; j < dim2; ++j) { // 2. "dimension" (rows) ma[i][j] = 0; } } } // Correct! Explicit: Bad, not flexible. void Bar(int ma[2][3], int dim1, int dim2) { /* pass */ } // Correct! Pass dimensions extra: bad, weird implementation. void Bar(int* ma, int dim1, int dim2) { for (int i = 0; i < dim1; ++i) { // 1. "dimension" (columns) for (int j = 0; j < dim2; ++j) { // 2. "dimension" (rows) ma[i * dim2 + j] = 0; // Correct, but awkward syntax! } } } // Correct! Explicit: Bad, not flexible, the last // dimension needs to be passed at minimum. void Bar(int ma[][3], int dim1) { /* pass */ } Correct Wrong ● As can be seen in the last correct example, accessing an array defines, whether it is a "normal" one or a multidimensional one.
  • 15. 15 Typedefs ● C/C++ allow to define syntactic "shortcuts" for compound type names/definitions with typedefs: typedef int Triple[3]; // typedef of int[3] named Triple. typedef int TripleCubeMatrix[3][3]; // typedef of int[3][3] named TripleCubeMatrix. typedef int* IntPointer; // typedef of int* named IntPointer. – Mind, how typedefs do also allow to name compound types nicely. ● When the typedefs are in place, we can use them instead of the shortcut type name: void TransposeMatrix(TripleCubeMatrix matrix){ /* pass */ } TripleCubeMatrix mesh = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; TransposeMatrix(mesh); void TransposeMatrix(int matrix[3][3]){ /* pass */ } int[3][3] mesh = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; TransposeMatrix(mesh); ● typedefs are examples of user defined types (UDTs), we'll come back to those in future lectures. – Mind, that we wrote the name of the UDT in PascalCase notation, this will be our convention to name UDTs. ● typedefs play an important role in the STL to hide the virtual type behind a typedef to allow library vendors/compiler builders to create individual solutions. ● Another kind of types, whose full names can be shortcut nicely with typedefs, are template instances. This idiom is also present in the STL.
  • 16. 16 Arrays and Pointers ● Pointers allow sharing data: – Passing arguments as (differing) pointers to the same data (shortcuts). ● Pointers avoid data copies: – Big blocks of memory (like arrays and structs) need not to be copied. – The key of C's performance is using pointers that way! ● Arrays and pointers enable dealing with raw memory in C/C++: – Manual memory management with dynamic memory. – Pointer arithmetics. – Binding pointers to memory allows programming of hardware-near drivers. – Arrays are a primary construct of imperative programming. ● Operations on c-strings! ● What is pointer arithmetics? ● Arithmetics is the theory of basic calculation with numbers. Elementary arithmetics describe the operators +, - ,* and /. ● Arithmetics with pointers deal with elementary arithmetic operators with pointers.
  • 17. 17 From chars to C-strings ● Working with c-strings is awkward, but required and widely used! ● Generally, string datatypes are those types that hold textual data. ● Individual letters can be held by char/wchar_t elements each. ● So, a collection of multiple char/wchar_ts will make up a complete string. – Each char/wchar_t will represent a letter respectively. – C/C++ provide an intrinsic way to represent "collections of elements": arrays. ● To distinguish bare char/wchar_t arrays from such representing c-strings, the "c-string-arrays" need to be 0-terminated! – This means that the very last item of the char-array needs to be a 0 (or '0')! – Considering the length of a char-array to be len, then the count of letters in a c-string is indeed len - 1!
  • 18. 18 C-string Literals and their Array Nature ● C-string literals are represented by literally written text within double-quotes. "bar"; // C-string literal, this is an array of 4 chars, 3 + 0-termination. L"foo"; // W-c-string literal, this is an array of 4 wchar_ts, 3 + 0-termination. ● The type of a c-string literal is const char[] or const wchar_t[]. – C-string literals are stored in the so-called static portion of memory. – The decayed form of a c-string boils down to the types const char* or const wchar_t*. ● For c-strings are arrays, neither can they be assigned nor resized directly. – Special functions and dynamic memory must be used instead. ● Esp. the comparison of c-strings can not be done via relational operators! – Relational operators would compare the decayed pointers, not the c-string contents! – Pointer comparison is about identity, but c-string comparison is about equality. ● Instead of relational operators, special functions must be used as well. ● What does "comparison of decayed pointers" mean? ● => It means that the addresses (i.e. the contents of these pointers) will be compared.
  • 19. 19 C-string Traps: Assignment and Comparison ● Invalid examples (initialization, invalid c-string assignment and invalid c-string "extension"): const char* aString = "Mallorca"; // Initialization of a c-string. aString = "Teneriffa"; // Invalid! Can't assign a c-string (or array)! const wchar_t* aWString = L"Weyland Yutani"; // Initialization of a w-c-string. aWString += L" at LV-426"; // Invalid! Can't extend a w-c-string (or array)! ● Example of wrong comparison: const char* fstName = "Frank"; const char* sndName = "Frank"; // Semantically wrong! The == operator compares the pointers for identity // (i.e. the addresses), not the c-strings' contents for equality! if (fstName == sndName) { std::cout<<"fstName and sndName are equal!"<<std::endl; }
  • 20. 20 C-strings: Literals with Escape Sequences ● Escape sequences are char-sequences with special meaning. ● Within a c-string literal we can't use the "-char directly, it must be "escaped". – Why is it impossible? Because the compiler has to know the limits of a c-string literal. const char text[] = "Wen"dy"; // Compiler in trouble: is that "Wen" or "Wen"dy"? – In C/C++ there exists a set of escape sequences, one of them solves this problem: const char text[] = "Wen"dy" // OK, just use the escape sequence ". "Wen"dy" ● Some "letters" can't be expressed as chars, escape sequences will rescue us. – Such "letters" are often so called "control codes", let's examine some of them: ● Inserting a newline into a literal (rn means "carriage return" and "newline"): std::cout<<"Jarn"<<std::endl; // rn will add a blank line below "Ja" on console. ● Inserting a tab into a literal (t): std::cout<<"atb"<<std::endl; // t will add a tab between a and b on console.
  • 21. // A c-string. const char* aString = "bar"; // The size of aString is 4, but its length is 3! std::size_t size = sizeof(aString); ? 'a' 'r' 0 aString 21 C-strings in Memory – Length and Size 'b' 0 ● … but we need to get the count of letters in a c-string, not the size (i.e. the size in bytes)! – There are always the 0-termination's extra bytes contributing to the size in bytes. – The size is inappropriate in the case of w-c-strings altogether! – Extra C-functions must be used with c-strings to work with string lengths. – Let's learn about these functions... char 1B 4B 0-termination // A w-c-string. const wchar_t* aWString = L"foo"; // The size of aWString is 8, but its length is 3! std::size_t wsize = sizeof(aWString); ? 'f' 0 'o' aWString wchar_t 2B (big endian) 0-termination 0? 'o' 0 0 8B ● What is "big endian"? ● When we have data that is composed of multiple bytes (i.e. integers greater than 1B or character types greater than 1B (But not multiple chars of a c-string!)), these bytes can be arranged in memory in different byte orders. ● On big endian byte order, the most significant bits resides (i.e. the bits contributing the highest amount to the value) on lowest address of the value in memory. This order directly reflects the "reading direction" of the value. -> 68000 and PowerPC (default) A c-string is always stored in big endian order (but not necessarily its char/wchar_t elements), because pointer arithmetics must work w/ all kinds of arrays. ● On little endian byte order, the most significant bits reside on the highest address of the value in memory. This order reverses the byte sequence and the "reading direction" of the value in memory. -> Intel
  • 22. 22 Basic C-string Functions ● Via the []-operator, all elements (the "letters") of a c-string can be accessed. – However, because we deal with a const char-array, the elements can't be assigned! ● Following functions in <cstring> specially deal with c-strings: – Getting the length (count of "letters" w/o 0) of a c-string with std::strlen(). – Comparing two c-strings with std::strcmp(). – Searching a single char within a c-string with std::strchr() (and std::strrchr()). – Searching a substring within a c-string with std::strstr(). ● The functions operating with w-c-strings, can be found in <cwchar>. ● General implementation of the c-string functions: – Parameters are always char-pointers, passed char-arrays decay to pointers. – The implementation is based on a loop over the c-string until 0-termination. ● In a past lecture we've already discussed how to read lines of c-strings via std::cin.getline().
  • 23. 23 C-strings: Length and Element Access ● Correct way of getting the length of a c-string: const char* aString = "bar"; // A c-string. std::size_t size = sizeof(aString); // The size of aString is 4, but its length is 3! std::size_t len = std::strlen(aString); // Correct: The length of aString is 3. ● Having len, we can access each element ("letter") of aString via the []-operator: for (int i = 0; i < len; ++i) { // Virtually i should be of std::size_t, but declaring i // as int is the canonical form... std::cout<<aString[i]<<std::endl; // Accessing the c-string as array. } ● But, we can't assign/modify the elements of aString, because it's const. aString[1] = 'u'; // Invalid! Assignment to const not allowed.
  • 24. 24 C-strings: Comparison int strcmp(const char* lhs, const char* rhs); ● The function accepts two c-strings to compare. – The returned int is 0, if the compared c-strings are case-sensitively equal. – The returned int is less than 0, if lhs is lexicographically less than rhs. – The returned int is greater than 0, if lhs is lexicographically greater than rhs. ● Let's review and correct the earlier example of c-string comparison: const char* fstName = "Frank"; const char* sndName = "Frank"; // Correct. std::strcmp() returns 0, because these c-strings are equal! if (0 == std::strcmp(fstName, sndName)) { std::cout<<"fstName and sndName are equal!"<<std::endl; } ● Upper case letters are considered "less than" lower case letters. ● C/C++ don't provide a way to perform a case-insensitive c-string comparison. We have to code it ourself (e.g. via std::tolower() or std::toupper()).
  • 25. 25 C-strings: Searching individual chars ● Searching an individual char: const char* aString = "bar"; // Search the first 'a' in aString, const char* result = std::strchr(aString, 'a'); // result will point to substring "ar". result = std::strchr(aString, 'z'); // There is no 'z' in aString, so result is 0. ● Searching all occurrences of an individual char: const char* aString = "bananas"; const char* result = std::strchr(aString, 'a'); // Search the first 'a' in aString. int occurrences = 0; while (0 != result) { // While the substring addressed by result is not 0: ++occurrences; // 1. Increment occurrences. ++result; // 2. Advance result to next char. result = std::strchr(result, 'a'); // 3. Search next 'a' in result. }
  • 26. 26 C-strings: Searching Substrings ● A substring is simply a part or portion of a whole string. ● Searching a substring in another string: const char* aString = "thinking"; // Search substring "ki" in aString, const char* result = std::strstr(aString, "ki"); // result will point to substring "king". result = std::strstr(aString, "zap"); // There is no "zap" in aString, so result is 0. ● Searching all occurrences of a substring in another string: – The implementation follows the same pattern as searching the occurrences of individual chars.
  • 27. 27 An Example for Pointers to Pointers: Arrays of C-strings ● Pointer to pointers are not rare in C/C++. – In C/C++ we often need to deal with arrays of pointers. – In general programming we have often to deal with arrays of c-strings. – As c-strings are char* and C's arrays decay to pointers we end in a char**. // An array of c-strings (the usage of []-declarator is needed in order to use the array initializer). const char* names[] = {"Mary", "Jake", "Diane"}; // An array of c-strings decays to a char-pointer-pointer. const char** alsoNames = names; ● Array initializers can not be used to initialize a char**.