Fundamental C - Starting Pointers
Written by Harry Fairhead   
Monday, 15 June 2020
Article Index
Fundamental C - Starting Pointers
Address Operator
Arrays As Pointers

Pointers and Arrays

Being able to take the address of a variable and use a pointer to it instead of using it directly is a good illustration of how pointers work, but it isn’t often useful. To be of any great use, pointers need some way of allocating memory that they can point to and that isn’t just the reuse of memory already allocated to a variable.

In many cases pointers are the default way of accessing C’s few data structures. In fact we have already encountered pointers in connection with arrays – a simple data structure that deserves to be encountered before the intricacies of pointers, but one that is essentially about pointers.

When you declare an array the compiler allocates a block of memory large enough to store the entire array and creates a pointer to store the address of the first element, i.e. the start of the allocated block.

That is:

int myArray[20];

reserves enough storage for 20 ints, i.e. sizeof(int) *20 bytes and myArray refers to the address of the first element.

In most cases, myArray behaves as if it was a pointer to int, but there are some subtle differences. The first is that myArray is more like a label rather than a full pointer. When you use myArray[0], for example, the compiler treats myArray as a constant pointer, i.e. an address, which it inserts into the machine code. A true pointer is a memory location that stores the address.

What this means in practice is that while you can use myArray as if it was a pointer, you cannot assign a new address to it and it is not a lvalue, unless you convert it into a true pointer.

For example, if you try:

int myVar=42;
int myArray[20];
myArray=&myVar;

you will see an error that is something like:

error: assignment to expression with array type

An array name is an expression of array type and not a pointer.

However, you can create a pointer to do the same job as an array variable:

int *myPointer;
int myArray[20]; 
myPointer=myArray;
printf("%d \n",myPointer[0]);

In this case we have assigned the address of the start of the array to a pointer and then used it as if it was an array – how is this last part possible?

Pointer Arithmetic

Suppose you have a pointer to a block of memory that contains repeated elements of the same type. For example, an int array is just a block of memory that is regarded as being one int followed by another. In this case the first int pointed to by the array name or an equivalent pointer.

That is, after:

int *myPointer;
int myArray[20]; 
myPointer=myArray;

myPointer references the first int in the array and

printf("%d \n",*myPointer);

prints the contents of the first element, i.e. myArray[0].


Where is the second element?

The answer is, displaced in memory from the start of the array by whatever the size of an int is.


That is, the address of the second element i.e. myArray[1] is given by

myPointer+sizeof(int);

By the same argument the third element, i.e. myArray[2] is given by:

myPointer+sizeof(int)*2;

In general, the address of the Ith element is:

myPointer+sizeof(int)*I;

This is the reason that C arrays start from zero index. If you wanted an array to start from index one you would need to subtract one from I in the above expression – not difficult but starting at zero is natural given the way elements are stored offset from the start of the array.

This calculation is so standard for pointers that C makes it the default and:

myPointer+I;

is taken to mean not +I but +sizeof(int)*I.

This is pointer arithmetic, and addition and subtraction are all you can do with pointers. Adding one adds sizeof(type) to the pointer and subtracting one reduces it by sizeof(type). You can also use ++ and - - but that’s all – no multiply or divide.

If you have a pointer to the start of an array, and it is a pointer to the type that the array stores, then the Ith element is addressed by:

myPointer+I;

and this is equivalent to the address of:

myArray[I];

In fact the [] array indexing operator is exactly equivalent to pointer arithmetic. That is:

myArray[I];

is the same as:

*(myArray+I);

and:

*(myPointer+I);

Notice that there is still the subtle difference in using a pointer or an array variable in that myArray+I is evaluated as a constant address plus I whereas myPointer+I is the contents of a variable, i.e. a memory location, plus I.

Although these examples have used int as the element type, the same things work for any element type with sizeof returning the size of the element. Notice that an array variable is slightly faster as it produces simpler machine code, but the difference is small.

Although there are differences between array variables and pointers, you can simplify things by always thinking of a pointer as if it was an array of elements. If the pointer is to a single variable then think of it as a single-element array.

 

In chapter but not included in this extract:

  • Functions and Pointers
  • Allocating Memory
  • Casting Pointers
  • Type Punning
  • Type Punning and Undefined Behavior
  • Is int* a Type?
  • Pointers to Functions
  • Pointers to Pointers
  • Immutability

Summary

  • Declarations are always of the form
    type variable1, variable2, variable3...
  • You can use the dereferencing operation in a declaration
    type variable1,*variable2 ...and variable1 and *variable2 are type which means that variable2 must be a pointer to type.
  • Pointers and arrays are nearly, but not quite, the same thing. A simple array is a pointer constant allocated no storage, and a pointer is a variable pointer allocated storage.
  • You can allocate and free memory using malloc and its associated functions.
  • In C data is best regarded as a bit pattern. How that pattern is interpreted depends on its assigned type.
  • You can also cast pointers and this changes how what they point at is interpreted.
  • Type punning can be used to interpret the same bit pattern in different ways.
  • In standard C type punning is undefined behavior and you should use unions as an alternative. Not every C programmer agrees with this point of view.
  • You can use malloc and pointers to return arrays and other data structures from functions.
  • Pointers to functions are also allowed and are useful in advanced contexts.
  • You can also create pointers to pointers and so on. If a pointer is the same thing as a one-dimensional array, a pointer to a pointer can be thought of as a two-dimensional array and so on.
  • You can use const to create immutable data – but this can be more complex than you might first think.

Harry Fairhead is the also the author of Applying C For The IoT With Linux, Raspberry Pi IoT in C and  Micro:bit IoT in C .

 

Related Articles

Remote C/C++ Development With NetBeans

Raspberry Pi And The IoT In C

Getting Started With C/C++ On The Micro:bit

Fundamental C: Getting Closer To The Machine

Now available as a paperback and ebook from Amazon.

  1. About C
      Extract Dependent v Independent
                  & Undefined Behavio
  2. Getting Started With C Using NetBeans
  3. Control Structures and Data
  4. Variables
      Extract Variables 
  5. Arithmetic  and Representation
      Extract Arithmetic and Representation 
  6. Operators and Expression
      Extract Side Effects, Sequence Points And Lazy Evaluation
      First Draft of Chapter: Low Down Data
  7. Functions Scope and Lifetime
  8. Arrays
      Extract  Simple Arrays 
      Extract  Ennumerations 
  9. Strings
      Extract  Simple Strings 
  10. Pointers
      Extract  Starting Pointers
      Extract  Pointers, Cast & Type Punning
  11. Structs
      Extract Basic Structs 
      Extract Typedef ***NEW
  12. Bit Manipulation
      Extract Shifts And Rotates 
  13. Files
     Extract Files 
  14. Compiling C – Preprocessor, Compiler, Linker
     Extract Compilation & Preprocessor

Also see the companion volume: Applying C

<ASIN:1871962609>

<ASIN:1871962463>

<ASIN:1871962617>

<ASIN:1871962455>

 

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on, Twitter, Facebook or Linkedin.

Banner


Fully Homomorphic Encryption Comes To Linux
31/07/2020

IBM has extended support for its Fully Homomorphic Encryption (FHE) toolkit to include Linux distributions for IBM Z and x86 architectures. The move follows the launch a few weeks ago for MacOS and iO [ ... ]



Mozilla Layoffs Include MDN Team
13/08/2020

Further to yesterday's report of layoffs at Mozilla we now know that Mozilla's MDN team are among those losing their jobs, which will come as a blow to the many developers who rely on MDN as a so [ ... ]


More News

graphics

 



 

Comments




or email your comment to: comments@i-programmer.info



Last Updated ( Monday, 15 June 2020 )