Introducing C++ Part 3 (More on pointers)

In this article “a C program” means a program written in C or C++.

Any area of knowledge can be understood at varying degrees, ranging from a cursory overview to an in-depth, intuitive understanding. That higher level of understanding for C can only be achieved with a solid understanding of pointers and the management of memory.

The key to comprehending pointers is understanding how memory is managed in a C program. After all, pointers contain addresses in memory. If we don’t understand how memory is organized and managed, it is difficult to understand how pointers work.

When a C program is compiled, it works with three types of memory:

Static/Global

Statically declared variables are allocated to this type of memory. Global variables also use this region of memory. They are allocated when the program starts and remain in existence until the program terminates. While all functions have access to global variables, the scope of static variables is restricted to their defining function.

Automatic

These variables are declared within a function and are created when a function is called. Their scope is restricted to the function, and their lifetime is limited to the time the function is executing.

Dynamic

Memory is allocated from the heap and can be released as necessary. A pointer references the allocated memory. The scope is limited to the pointer or pointers that reference the memory. It exists until it is released.

SCOPE AND LIFETIME:
SCOPE                                  LIFETIME

Global: 
The entire file                        While Application Runs

Static: 
The function it is declared within     While Application Runs

Automatic (local): 
The function it is declared within     While Function Executes

Dynamic: 
Determined by the pointers that        Until Memory is Freed
reference this memory 
(reference counted)             

Understanding these types of memory will enable you to better understand how pointers work. Most pointers are used to manipulate data in memory.

Understanding how memory is partitioned and organized will clarify how pointers manipulate memory.

A pointer variable contains the address in memory of another variable, object, or function. An object is considered to be memory allocated using one of the memory allocation functions, such as the malloc function.

A pointer is normally declared to be of a specific type depending on what it points to, such as a pointer to a char. The object may be any C data type such as integer, character, string, or structure. However, nothing inherent in a pointer indicates what type of data the pointer is referencing. A pointer only contains an address.

Faster and more efficient code can be written because pointers are closer to the hardware. That is, the compiler can more easily translate the operation into machine code. There is not as much overhead associated with pointers as might be present with other operators.

Many data structures are more easily implemented using pointers. For example, a linked list could be supported using either arrays or pointers. However, pointers are easier to use and map directly to a next or previous link. An array implementation requires array indexes that are not as intuitive or as flexible as pointers.

Dynamic memory allocation is effected in C through the use of pointers. The malloc and free functions are used to allocate and release dynamic memory, respectively. Dy‐ namic memory allocation enables variable-sized arrays and data structures, such as linked lists and queues. However, in the new C standard, C11, variable size arrays are supported.

Pointers represent a powerful tool to create and enhance applications. On the downside, many problems can occur when using pointers, such as:

• Accessing arrays and other data structures beyond their bounds

• Referencing automatic variables after they have gone out of existence

• Referencing heap allocated memory after it has been released

• Dereferencing a pointer before memory has been allocated to it
The NULL macro is a constant integer zero cast to a pointer to void. In many libraries, it is defined as follows:
#define NULL ((void *)0)

This is what we typically think of as a null pointer.

The actual internal representation of null is implementation-defined. The use of NULL and 0 are language-level symbols that represent a null pointer.

The ASCII NUL is defined as a byte containing all zeros. However, this is not the same as a null pointer.

A C-style string is represented as a sequence of characters terminated by a zero value.

The null string is an empty string and does not contain any characters.

Finally, the null statement consists of a statement with a single semicolon. As we will see, a null pointer is a very useful feature for many data structure implementations, such as a linked list where it is often used to mark the end of the list.

If the intent was to assign the null value to pi, we use the NULL type as follows:

 pi = NULL;

A null pointer and an uninitialized pointer are different. An uninitialized pointer can contain any value, whereas a pointer containing NULL does not reference any location in memory.

Interestingly, we can assign a zero to a pointer, but we cannot assign any other integer value.
A pointer can be used as the sole operand of a logical expression. For example, we can test to see whether the pointer is set to NULL using the following sequence:

if(pi) { // Not NULL, do Work; }

else { // Is NULL, exit;  }

A null pointer should never be dereferenced because it does not contain a valid address. When executed it will result in the program terminating.

NULL should not be used in contexts other than pointers. It might work some of the time, but it is not intended to be used this way.

It can definitely be a problem when used in place of the ASCII NUL character.

This character is not defined in any standard C header file.

It is equivalent to the character literal, ‘\0’, which evaluates to the decimal value zero.

Something to keep in mind (and keep sane):

int num;

int *pi = 0; // Zero refers to the null pointer, NULL

pi = #

*pi = 0; // Zero refers to the integer zero

We are accustomed to overloaded operators, such as the asterisk used to declare a pointer, to dereference a pointer, or to multiply.
The zero is also overloaded.

We may find this discomforting because we are not used to overloading operands.

Pointer to void

A pointer to void is a general-purpose pointer used to hold references to any data type.

An example of a pointer to void is shown below:

void *pv;

It has two interesting properties:

• A pointer to void will have the same representation and memory alignment as a pointer to char.

A pointer to void will never be equal to another pointer.

However, two void pointers assigned a NULL value will always be equal, because there are only one nullpointer which is shared throughout a program.

Any pointer can be assigned to a pointer to void.
It can then be cast back to its original pointer type.
When this happens the value will be equal to the original pointer value.
This is illustrated in the following sequence, where a pointer to int is assigned to a pointer to void and then back to a pointer to int:

int num;

int *pi = #

printf("Value of pi: %p\n", pi);

void* pv = pi;

pi = (int*) pv;

printf("Value of pi: %p\n", pi);

When this sequence is executed as shown below, the pointer address is the same:

Value of pi: 100

Value of pi: 100

Pointers to void are used for data pointers, not function pointers.

That’s it for now.

Until next time, Happy Hacking!
Advertisements

Follow-Up: Reasons to NOT only learn .Net / C#

A modern developer should master at least 3 languages!

A while ago I was all exited about finally “getting it” in sense of the more advanced parts of C#, like Generics, Events, Delegates, and Lambdas. So I wrote a post about 18 reasons you should use C# / .Net / Mono.  it kinda sounded like I’d found a salvation in it or something.

Well, I did not. I was just “on a roll”!

I’m often on these rolls. This is what gets me ahead of the competition and it’s what get’s developers with master degrees in Computer Science and programming  asking ME for help while at work from time to time. That’s wicked cool, but it has its downsides.   logoLispSpillerGlossy

I seldom sleep more than 4 hours per night, because I just HAVE to finish up a stupid project so I can understand a concept in a programming language I probably never going to use, like Cobol or something. But who knows right?

This brings me to the main theme of this blog post:

I’ve been interested in programming for a long time. Long before I started to work as a developer, I snuck in some developer tasks when working as a network and security administrator, and when working as a server and system administrator.
I managed to convince my boss that I really needed this and that book  or course so we could do this and that so much better. It worked all the time.

My job back then was basically sitting in my office with a self-made monitoring system that alerted me if some fiber link was down or a router to a branch office went bananas, something that didn’t happen very frequently. So, my responsibility was to make sure the systems ran 24/7, and that was that.
I make it sound a bit easier than it was from time to time, but the point is that I had a lot of time to study programming!

I started learning the C Language from the ubiquitous K&R book that I still keep in sight for the kicks emacs6-256of it. This was the first standardized version of C, so it had some quirks to put it mildly, but when you understood it, nothing could beat it! At least not in terms of efficiency and performance… Time to market is a nother story.
I was doing a good deal of scripting as part of my job, for automating mass installations, upgrades log-on scripts and those things, but that was in VBScript! Can you believe it? VBScript! I hated it.

So I started to replace many of the scripts with Perl and Python using the Win32 libraries, something that was way cooler.

Then I got interested in cross-platform programming in Java, because I missed a real GUI from the stripped out Tk I managed to get out of Perl and Python, and it had to run on both Windows, Linux and FreeBSD servers. While I probably would get a compile-time error writing “Hello World” in Java today I thought it was fun while it lasted.

Then the real shit hit the fan. I decided to change jobs and work as a full-time developer. My responsibilities where diverse and involved working with Legacy Borland C++ code and some C# 2.0 written in C++ style. So I had to get really serious about learning C++ and C#. The first months I went to work, did what I could, then I wrote down everything I didn’t know how to do.
When I got home I thought it to myself through books, tutorials and Googling so I could fix it the next day.

This went on for almost a year, and I was totally up to my neck in deadlines and trouble.
It wasn’t really my vision of having a job doing what I liked most.
But somehow I managed to get by and new projects came along that demanded the same level of commitment.
That’s the price to pay for adding a bit extra on the resume…the-ruby-mine-logo

Today I feel a lot safer about my skills in the “major languages” C, C++ and C#, but I’ve realized that I’ve only been doing one kind of paradigm type programming and that is the Object Oriented type of programming.

So I’ve now started to learn two new languages (or three actually), namely Common Lisp, Erlang and TCL/Tk.
What I discover each day is that the new things I learn about the more functional approach to programming could have saved my ass plenty of times if I’d known some of the same techniques when working with the projects I barely got through earlier,
I could have done many things so much simpler and more elegantly.

So my advice to all aspiring or maybe even more to all the mounted old dogs that refuses to learn new tricks is to actually do just that. Learn at least one purely functional language, one strictly OOP and one that blends it all together, like C++ or Objective-C if that’s your cup of tea. Plus I’d invest in learning one strictly interpreted language like Python or Ruby, as it makes prototyping and easier tasks, well, so much easier!.

erlang

Put a NoSQL database like MongoDB on top of this and you have an incredible toolbox for handling almost any programming task thrown at you. Word.

PS! Don’t forget those that  work hard for free to bring us some fantastic tools to develop cool things with! 

Get a  Member Sponsorship at the Free Software Foundation Today! 

fsfButton     <– LINK!

These guys are Funding the GNU Project.

Until next time, The MadMan.