Fundamental C - Starting Pointers |
Written by Harry Fairhead | |||||||
Monday, 15 June 2020 | |||||||
Page 3 of 3
Pointers and ArraysBeing 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 ArithmeticSuppose 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].
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:
Summary
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 ArticlesRemote C/C++ Development With NetBeans Getting Started With C/C++ On The Micro:bit Fundamental C: Getting Closer To The MachineNow available as a paperback and ebook from Amazon.
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.
Comments
or email your comment to: comments@i-programmer.info |
|||||||
Last Updated ( Monday, 15 June 2020 ) |