User-Defined Types in C++: Part 1

Data types such as int, float, char are known as built-in types. Although useful, built-in types do not provide the flexibility required to write complex applications. C++ circumvents this issue by providing a mechanism to create user-defined types. User-defined types provide a better representation of program objects used in complex applications.

User-defined types are made up of built-in types and the mechanism use to create them are:

  • Structures
  • Classes

In this article, I will talk you about Structures. In Part II of this article, I will talk about Classes.

Structures

A Data Structure provides a mechanism to organize several built-in types into a single entity. A Data Structure consist of the following syntax:

struct User_Defined_Type_Name{

built_in_type;
built_in_type;
built_in_type;

}

The struct keyword declares a structure of type "User_Defined_Type_Name" and defines the built-in types within the structure. Built-in data types within a structure are known as Data Members.

For example, the code snippet below declares a Structure of type Student with several data members.

struct Student{

    //Data members of the structure
    int age; 
    float GPA;
    char grade;
};

Student is an User-Defined Type. When you define a variable of type "Student," an object is created with a memory location and storage.

For example, in the snippet below, line 1 defines a structure, harold, of type Student. The definition allocates enough memory to hold all three built-in data types. In this instance: grade, GPA, and age.

int main(){

    Student harold; //1. Declaring a structure variable

    return 0;
}

Accessing data members

To access a data member in a structure, you must use the dot "." operator. For example, in the snippet below, the data member "age" is accessed using the dot operator (line 2).

int main(){

    Student harold; //1. Declaring a structure variable

    harold.age=29; //Access the structure data member "age"

    return 0;
}

The dot operator is used when a Structure is local to a function, has been declared globally or is "passed by value" to a function.

For example, in line 6, the structure is "passed by value" to the function "printAge." In line 2, the data member is accessed using the dot operator.

void printAge(Student uStudent); //1. Declaring function with "pass by value" argument

void printAge(Student uStudent){

    int age=uStudent.age; //2. Accessing the structure data member with "." operator

    std::cout<<"Print Age: "<<age<<std::endl; //3. Print student age

}

int main(){

    Student harold; //4. Declare a structure variable

    harold.age=29; //5. Set age of student

    printAge(harold); //6. call function and pass the structure by value

    return 0;
}

The "->" is also used to access the structure's data members. However, the "->" operator is used when a structure is "passed by reference" to a function.

For example, in line 5, the structure is "passed by reference" to the function "changeAge." In line 2, the data member is accessed and modified using the "->" operator.

void changeAge(Student *uStudent); //1. Declaring function with "pass by reference" argument

void changeAge(Student *uStudent){

    uStudent->age=30; //2. Accessing the structure data member with "->" operator

}

int main(){

    Student harold; //3. Declare a structure variable

    harold.age=29; //4. Set age of student

    changeAge(&harold); //5. call function and pass the structure by reference

    std::cout<<"Print age:"<<harold.age<<std::endl; //6. Print the new age of student

    return 0;
}

In Part II of this article, I will talk about the second mechanism used to create user-defined types. i.e., Classes.

Hope this helps.

Understanding References in C++

A C++ Pointer is a scary concept to beginners. The idea of a Pointer is simple, but its syntax is not. For example, the asterisk symbol "*" can be used to define or to dereference a pointer; the position of the asterisk determines if the Pointer is either being defined (see line 2 below) or is dereferenced (line 3).

int main() {

    int a=3; //1. Defining a variable

    int *myPointer=&a; //2. Defining a pointer

    int b=*myPointer; //3. Dereferencing a pointer

    return 0;
}

References are friendlier alternatives to pointers with nicer syntax. With References, the C++ compiler handles all the details of dereferencing a Pointer, so you don't have to.

Reference properties

A Reference is another name for a variable, i,e., an alias. A reference is not an object; It has no storage space and no memory location. In contrast, a variable and a pointer are objects. i.e., they have storage space and a memory location. This difference gives references unique requirements, such as:

  1. You must initialize a reference to an existing object.
  2. Once initialized, it can not refer to a different object.
  3. You can not manipulate a reference as an independent entity. They are simply a different name for an existing object.

Reference in action

When used in a declaration statement, the ampersand symbol "&" initializes a reference. For example, the code snippet below initializes the reference 'myReference' to the variable 'myVariable.' (see line 2)

int main(){

    int myVariable=3; //1. Defining a variable

    int &myReference=myVariable; //2. Declearing a reference and initializing it to myVariable

    return 0;
}

If you modify the value of 'myVariable,' the reference's value also changes. Remember, a reference is simply another name for a variable. The code snippet below shows this property.

In the snippet below, we modify the 'myVariable' value to 5 (line 3).

Lines 4 and 5 prints the value of 'myVariable' and 'myReference.' In this example, the project prints the value of 5 for the variable and reference.

int main(){

    int myVariable=3; //1. Defining a variable

    int &myReference=myVariable; //2. Declaring a reference and initializing it to myVariable

    myVariable=5; //3. Modify the variable

    std::cout<<myVariable<<std::endl; //4. Print the value of the variable

    std::cout<<myReference<<std::endl; //5. Print the value of the reference

 return 0;

 }

In the same manner, if 'myReference' changes value, 'myVariable' also changes value.

So, if a reference is simply another name for an existing object, why go through the trouble of using them?

The answer is that references provide a simpler syntax than pointers. When using pointers, you need to deal with passing an address and dereferencing a pointer. With references, the compiler takes care of these details for you.

For example, the following code snippet uses pointers. The function's arguments is a Pointer (line 1). Inside the function's definition, you must dereference the pointer to retrieve its value (line 2). And if you want to change the value, you must dereference the pointer (line 3).

int add(int *a); //1. argument is a pointer

int add(int *a){

    int b=*a+1; //2. dereference the pointer and increment the value by 1

    *a=5; //3. modify the value of the variable

    return b; //4. return the value of b
}

In practice, the function call requires the address of the variable. See line 2 in the snippet below:

int main() {

    int myVariable=2; //1. define a variable

    int myAnswer=add(&myVariable); //2. pass the address of the variable

    return 0;

}

The same function becomes a lot cleaner with references. Take a look at the code snippet below:

int add(int &a); //1. Function arguement requires a reference

int add(int &a){

    int b=a+1; //2. No need to dereference the variable being passed

    a=5; //3. No need to use dereference when you modify the variable

    return b;

}

The function's argument is a reference instead of a pointer (line 1). Inside the function's definition, there is no need to dereference the variable being passed to the function (lines 2 & 3). With references, you treat the variable like any other variable inside the function.

In practice, the function call does not require special syntax, such as passing its address. See line 2 in the snippet below:

int main(){

    int myVariable=2; //1. Define a variable

    int myAnswer=add(myVariable); //2. pass the variable without the need to pass its address

    return 0;
}

In summary, references were created to alleviate the pain of working with Pointers. However, references are NOT pointers. They are simply aliases for existing variables or pointers.

Hope this helps

Passing by value vs Passing by reference in C++

The concept of passing a variable to a function by value or by reference is somewhat confusing to beginners. It was difficult for me to comprehend until I learned the essential elements of a variable.

A variable is a named memory location that stores a value. However, there is more to this. A variable is composed of a rvalue (right value) and a lvalue (left value). The rvalue represents the value stored in the memory location. Whereas, the lvalue designates the address of the memory location.

When you pass a variable to a function, you either pass the variable's rvalue or lvalue. If you pass the rvalue to a function's argument, you are passing the variable by value. However, if you pass the variable's lvalue, you are passing the variable by reference. Passing a variable by reference equates to saying "passing its address to the function."

So what's the point of all of this? The point is this: Passing the address of a variable is the only way to have a function modify the content of a variable.

Let's talk about the differences between each method.

Difference in function declaration

Functions that receive a value through its argument are declared as:

int add(int a);

In practice, the function is use as follows:

int main(){

int myVariable=2; //1. define a variable
int myAnswer=add(myVariable); //2. pass the variable by value

return 0;
}

In line 1, you define a variable named 'myVariable.' In line 2, the variable is "passed by value" to the function 'add.'

In contrast, functions that receive an address through its argument are declared as:

int add(int *a);

The argument is declared as a pointer since pointers can receive addresses.

In practice, the function is use as follows:

int main(){

int myVariable=2; //1. define a variable
int myAnswer=add(&myVariable); //2. pass the variable by reference

return 0;
}

In line 1, you define a variable named 'myVariable.' However, in line 2, the variable is "passed by reference" to the function 'add.' The symbol '&' means "The address of."

Difference in function definition

There are differences in the function definition for each method. In a "pass by value" method, a function is defined as:

int add(int a){

int b=a+1; //1. increment the incoming value by 1

return b; //2. return the value of b
}

In the code snippet above, the function increments the value of 'a' by 1 (see line 1). Line 2, returns the value of b.

In a "pass by reference" method, a function is defined as:

int add(int *a){

int b=*a+1; //1. dereference the pointer and increment the value by 1

*a=5; //2. modify the value of the variable

return b; //3. return the value of b
}

Line 1 dereferences the pointer 'a.'; it accesses the value the pointer 'a' points. The value is then incremented by 1.

Line 2 modifies the value the pointer 'a' points to and sets it equal to 5. Line 3 returns the value of b.

Examples of each method

Let's go through a complete example of each method:

"Pass by value" method

In the code snippet below, lines 1 and 2 declare and define the function 'add.'

Line 5 shows the start of the 'main()' function. Line 6 defines a variable 'myVariable.' This variable is "passed by value" to the function 'add' in line 7.

Lines 8 and 9 prints the value of 'myAnswer' and 'myVariable.'

int add(int a); //1. declare a pass by value function

//2. define a pass by value function
int add(int a){

    int b=a+1; //3. increment the incoming value by 1

    return b; //4. return the value of b
}

//5. main function
int main() {

    int myVariable=2; //6. define a variable

    int myAnswer=add(myVariable); //7. pass the variable by value

    std::cout<<myAnswer<<std::endl; //8. print the value of myAnswer

    std::cout<<myVariable<<std::endl; //9. print the value of myVariable

    return 0;
}

When you run this program, the output of 'myAnswer' is 3, and 'myVariable' is 2. As expected, the function did not change the value of 'myVariable.'

"Pass by reference" method

In the code snippet below, lines 1 and 2 declare and define the function 'add.'

Line 6 shows the start of the 'main()' function. Line 7 defines a variable 'myVariable.' This variable is "passed by reference" to the function 'add' in line 8.

Lines 9 and 10 prints the value of 'myAnswer' and 'myVariable.'

int add(int *a); //1. declare a pass by reference function

//2. define a pass by reference function
int add(int *a){

    int b=*a+1; //3. dereference the pointer and increment the value by 1

    *a=5; //4. modify the value of the variable

    return b; //5. return the value of b
}

//6. main function
int main() {

    int myVariable=2; //7. define a variable

    int myAnswer=add(&myVariable); //8. pass the variable by reference

    std::cout<<myAnswer<<std::endl; //9. print the value of myAnswer

    std::cout<<myVariable<<std::endl; //10. print the value of myVariable

    return 0;
}

When you execute the program above, the output of 'myAnswer' is 3. However, 'myVariable' was modified and now equals 5.

The concept of "pass by value" vs. "pass by reference" may be difficult to grasp. In doubt always remember: "passing by reference" is the only way to have a function modify the content of a variable.

Hope this helps

Reference: C++ Pointers and Dynamic Memory Management

Understanding Pointers in C++

Pointers have the fame of being hard to understand. However, this is not true. Pointers are simple to comprehend. What makes them confusing is how powerful and flexible they can be.

Imagine your computer's entire memory as a long row of containers; where each container has a unique address and can store a value.

A pointer is just container that has a unique address but instead of storing a value it stores the address of a variable. For example, the image below shows the address of the variable myChar stored inside the container myPointer.

The key point is this: A variable stores a value. A Pointer stores the Address of the variable.

Defining a Pointer

A Declaration announces a variable or function to the compiler so that it knows the data type before it compiles it. A Definition is a declaration that reserves storage.

So in the following code:

int main(){

char myChar='b'; //define variable myChar

return 0;
}

The variable myChar is being declared and defined. That is, memory space has been reserved for the variable, and it contains the value: 'b.'

To define a pointer, you specify the data type your pointer will be holding the address of and include the asterik symbol "*" before the pointer's name.

For example:

int main(){

char myChar='b'; //1. define variable myChar

char *myPointer;  //2. pointer definition

return 0;
}

Assigning an address to a pointer

To assign the address of a variable to a pointer, you use the "&" symbol as shown in line 3 below. In C++, the symbol "&" means "the address of."

int main(){

char myChar='b'; //1. define variable myChar

char *myPointer;  //2. pointer definition

myPointer=&myChar; //3. assigning the address of myChar to the pointer myPointer

return 0;
}

If you were to print the value of "myPointer" you will get the address of the variable "myChar."

Dereferencing a Pointer

You can retrieve the value a pointer points to by dereferencing it.

Let's go through a quick example:

int main(){

char myChar='b'; //1. define variable myChar

char myOtherChar; //2. define a variable myOtherChar

char *myPointer;  //3. pointer definition

myPointer=&myChar; //4. assigning the address of myChar to the pointer myPointer

myOtherChar=*myPointer;  //5. dereferencing myPointer

//myOtherChar now holds the value 'b'

return 0;
}

In line 5, we dereference the pointer using the dereferencing operator "*".

In other words, we accessed what the pointer points to, i.e., "myChar" and assigned the value of "myChar" to the variable "myOtherChar."

The dereferencing operator "*" is the same asterisk used to declared a pointer. However, its behavior differs depending on the position of the asterisk in a program. When the asterisk is not used in a declaration, it means "access what the pointer points to." I know this is confusing, but that is how it works in C++.

Hope this helps

Understanding Data Types in C++

How you represent an integer, a letter or a word in C++ differs. For example, representing the integer 23 requires the keyword int before the variable name:

int myNumber=23;

Representing the letter "L" requires the keyword char before the variable name:

char myLetter='L';

The keywords char and int along with float, bool and double are known as Data Types. A Data Type defines the set of possible values allowed in a variable and its memory size. These five data types constitute the fundamental data types in C++.

The Basic Integer Type: int

To represent an integer such as 201, -33, 1024, etc., C++ requires the keyword int before the variable name. For example:

int numberA=201;
int numberB=-33;
int numberC=1024;

The Floating Number Type: float

To represent a decimal number such as 21.3, 0.42, 0.10, etc., you must use the keyword float before the variable name. For example:

float numberA=21.3;
float numberB=0.42;
float numberC=0.10;

The Extended Precision Type: double

The double data type is similar to float but can store roughly twice as many significant digits than a float data type. To represent numbers such as -243.16, 2453345.2, C++ requires the keyword double before the variable name. For example:

double numberA=-243.16;
double numberB=2453345.2;

The Single Character Type: char

To represent a character such as 'a,' 'B,' '9', etc., use the keyword char. For example:

char myCharacterA='a';
char myCharacterB='B';
char myCharacterC='9';

The Boolean Data Type: bool

To represent the value of 0 or 1. Or true or false, use the keyword bool. For example:

bool myValueA=false;
bool myValueB=true;

Also, a data type specifies the memory allocated for the variable. The memory allocated is machine dependent, and it varies from machine to machine. For example, on my Mac:

  • An int takes 4 bytes of memory
  • A char takes 1 byte of memory
  • A float takes 4 bytes of memory
  • A double takes 8 bytes of memory
  • A bool takes 1 byte of memory

Hope this helps.