How does http pointerpointer com

 

C course - when the pointer points into the forest

What are pointer? pointer are variables and they are addresses, they are variables that can hold a memory address, which is why they are 4 bytes in size in 32-bit operating systems, i.e. they correspond to unsigned long integer.

The understanding of Pointers is really important to C. to understand and program correctly. For three reasons:

  • pointer enable functions to change their variables transferred when they are called

  • dynamic management of storage space, memory management, always works over pointer

  • if you want to optimize your program, speed, memory requirements are pointer always very popular

Those were the advantages, you can go with it Pointers but also very easily produce the largest and most inscrutable errors. If your program runs error-free on your computer, but your colleague, customer, acquaintance stiffly claims that it keeps crashing on him, then look for the problem on yours first Pointers. pointer, the concept and the implementation of it are among the most complex things in C programming, so be careful, now during the course anyway and of course later when programming.

 

1. Declaration and use of pointers

Now you know that pointer on the one hand they are important, on the other hand they are a source of constant joy in troubleshooting. Now let's see the syntax for declaring and using Pointers at:

When declaring a pointer type variable, there is a '*' before the variable name. In this case, the asterisk '*' indicates that it is a pointer, it has nothing to do with the multiplication. Pointers of all data types can also be declared,
data type * pointervar;
e.g. here you declare a pointer to an integer number:

// Dear C Compiler, create a variable for me that can hold a pointer to an integer variable:
int * intptr = NULL;
// the variable intptr can hold an address of an integer value.
// It is best to initialize the variable to NULL right away.
...

// Compiler, create an integer variable for me and assign it the value 123:
int a = 123;

Pointer without data type: if you don't want to assign a certain data type to the pointer, you declare it as void.

void * genericPointer;

The size of a generic pointer that is not set to a specific data type corresponds to the size of a memory address of the operating system, 32-bit -> 4 bytes; 64-bit -> 8 bytes.



With the Ampersand and '&' operator assign the address of a variable to the pointer,
pointervar = & variable.
The pointer variable then contains the memory address of the assigned variable, the pointer now references the variable, it points to the variable. Another note, the & operator for the pointer referencing has nothing to do with the logical AND operator, also &:

intptr = & a; // Now assign the address of the integer variable a to the integer pointer intptr.
printf ("% d \ n", a); // a is displayed it should be '123' there

The pointer intptr now contains the address of the variable a, intptr references a or intptr points to a.

With Asterisk '*' operator you get what is in the memory address that the pointer contains, you dereference the pointer:
integervar = * pointer_to_int_var;
you write in another variable what is at the memory address to which the pointer points, or vice versa
* pointer_auf_int_var = 123;
another value is written to the memory address to which the pointer points. So that the whole thing works, the variable and pointer must be of the same data type, e.g. integer;

* intptr = 321; // and now write a new value in the address pointed to by intptr, 321
printf ("% d \ n", a); // a is displayed again, it should now read '321', even though we did not touch a at all

 

And now the whole thing again as a graphic:

 

Addendum: I recently got a new Mac Pro with a 64-bit operating system, the addresses are 8 bytes in size;).

 

2. Pointer arithmetic

Memory addresses are also only numbers and you can calculate with numbers, but since anything other than plus and minus appears nonsensical when calculating with addresses, only these two operations are allowed. Why should someone divide an address by something or multiply it by another number? All arithmetic operations except plus and minus cause error messages with pointers.

So now let's calculate something with pointers:

double * d; // declare pointer

d = 420,000; // assign any address to the pointer
printf ("1st pointer:% d \ n", d); // now print out the content of the pointer variable
d = d + 3; // add 3 to it
printf ("2nd pointer:% d \ n", d); // now print it out again and then look amazed

If you run the little test, you get the following expression on the screen:

1st pointer: 420000
2nd pointer: 420024

To the original value of the pointer variable, 3 is not added, as it actually stands, but 3 times the memory requirement of the pointer type. Again, first line, double * d; our pointer, * d points to the data type double, double is 8 bytes in size. If I add 3 to any address, e.g. 420000, which is in my pointer variable d, the result is 420024, i.e. 420000 plus 3 * 8, the original address plus 3 times the size of the data type. The same works with the ++ or - operator, as well as + = and - =.

With character pointers, i.e. pointers that point to a character, the data type is only one byte in size, the arithmetic is correct here anyway.

 

3. Pointers and arrays

There is a very close relationship between pointers and arrays, it is due to the fact that array variables are actually pointers. An array is a pointer to the first element of the array. You can assign array variables directly to a pointer or transfer them to functions as pointers. Here is a small example program:

#include

// 'PrintArray', a function that uses a pointer to an integer value as input variable,
// 'int * inputArray', as well as a simple integer variable required
void PrintArray (int * inputArray, int arraysize)
{
int i;
for (i = 0; i   {
printf ("% d \ n", inputArray [i]); // the integer pointer inputArray is simply treated as an array
  }
}


int main (int argc, const char * argv [])
{
int array [5] = {10, 20, 30, 40, 50}; // Declaration of an array with 5 elements
int * arrayStart = NULL;

arrayStart = array;
printf ("% ul \ n", arrayStart); // to which address does 'arrayStart' point?
printf ("% d \ n", * arrayStart); // and what does this address say?
printf ("% ul \ n", array); // what is actually in 'array'
printf ("% ul \ n", & array [0]); // and what is the address of the first element of the array?

PrintArray (array, 5);// the function PrintArray expects a pointer to integer as the first parameter,
                        // since an array variable is actually a pointer,
                        // you can just pass it here.


return 0;
}

 

4. Change of variables transferred to the function, call at reference

Up until now we had only ever passed simple variables to functions, e.g. like this:

void my favorite function (int inputvar)
{
inputvar = inputvar * 10;
printf ("inputvar:% d \ n", inputvar);
}


int main (void)
{
int x = 42;
MyFavorite Function (x);
printf ("x:% d \ n", x);
}

The following expression on the screen:

inputvar: 420
x: 42

The input variable 'inputvar' is changed within 'My Favorite Function', but only locally in the function. The variable 'x' in the higher-level, calling function then still has the same value as before the function call. How does this work? Now the C compiler creates a copy of the input variables. The function now works with this copy and can do whatever it wants with it, the variable in the calling function remains unaffected. This approach is called in good German Call by Value, the value of the variable is passed to a function, not the variable itself.

Usually this is also the desired behavior, nevertheless you want or have to be able to change the variable passed to the function, but how? Well, you simply pass a pointer to the function, it points to the real memory address of your variable and then you can change it:

void functionWithPointer (int * inputvar)
{
* inputvar = * inputvar * 10; // the memory area to which the pointer points is changed
printf ("* inputvar:% d \ n", * inputvar);
}


int main (void)
{
int x = 42;
FunctionWithPointer (& x); // the address of x is passed to the 'FunktionMitPointer'
printf ("x:% d \ n", x);
}

The following expression appears on the screen:

* inputvar: 420
x: 420

As you can see, the variable 'x' has been changed in the calling function, the address of the variable x is entered with the merchant and in the function
FunctionWithPointer (& x); entered and dereferenced and changed there with the * operator. Because one does not pass the variable but the reference, the address of the variable, the whole is called Call By Reference.

5. Pointer to pointer

To complicate matters, you can also declare pointers that point to another pointer, which is often used, for example, when writing an application with its own memory management. Briefly explained by the way, you use a pointer that points to the data, if the data is moved in the memory, this pointer is updated. Then you declare a master pointer that points to this data pointer. The master pointer does not change, it always only points to the other pointer, it can be transferred to all functions at any time. To get to the data, you only have to dereference it twice.

You declare a pointer to a pointer with two asterisks'**', here is an example:

int x = 42;
int * myptr, ** masterptr;

myptr = & x; // myptr points to x
masterptr = & myptr; // masterptr points to myptr
printf ("** masterptr:% d \ n", ** masterptr); // masterptr is dereferenced twice

You can of course take this further and have pointers point to pointers, which in turn point to pointers to pointers:

int x = 42, * ptr1, ** ptr2, *** ptr3, **** ptr4; // etc.

ptr1 =?
ptr2 =?
ptr3 =?
ptr4 =?

printf ("**** ptr4:% d \ n", **** ptr4); // results in: **** ptr4: 42

is correct C code, but until now I hadn't had a meaningful application for something like that.

 

 

6. When the pointer points into the forest

As mentioned at the beginning, pointers can produce the most inscrutable errors. I'll show you how to do it now:

int * myptr;

* myptr = 1234;

OK, you declare myptr, at this moment either a random address is in myptr, the pointer points to the forest, or the compiler initializes it with NULL, in which case it points to the start area of ​​the memory, where the operating system of your computer is begins. In the next line, you write a value, '1234', to this memory address.

If the pointer points to NULL, as in the second case, you immediately get a 'NULL-POINTER-EXCEPTION' error message, i.e. the operating system complains, that's still easy. In the first case, the pointer simply points somewhere, three things can happen:

  • the pointer points to an address outside the address range of the program, possibly even to an address that is not physically present in the memory, not everyone has 4 gigabytes of memory stuck in their computer. You receive a 'SEGMENT-FAULT' error message, the system reports that you are trying to access a memory address outside of the memory area assigned to your program without permission.

  • the storage space to which the pointer points is simply free, you don't notice anything at first.

  • the memory space to which the pointer points is occupied by a variable, array or something else, you should now notice a malfunction of the program.

Here you can now also explain this sometimes it works - sometimes it doesn't explain the behavior of a program. The addresses are assigned during the runtime of the program, if the computer has a lot of memory chips available or the memory is only little used, i.e. only a few programs are running, the chance increases that the pointer points to free memory space and the program initially runs without problems. If someone else uses it on a computer with little free memory, it may be that the uninitialized pointer then points to something important and the program behaves nonsensically or crashes.

The following construction is now better:

int * myptr = NULL; // first set the pointer variable to NULL
int x = 42;

myptr = & x; // then initialize the pointer

...

if (myptr) // check beforehand whether the pointer is assigned
* myptr = 1234;

Most modern C compilers initially set pointer variables to NULL, but now take a look at the following code fragment:

int * myptr = NULL; // first set the pointer variable to NULL
int x [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // create an array of 10 integers

myptr = & x [5]; // then let the pointer point to the 6th element of the array

...

myptr + = 100; // let the pointer point to 100 * 4 memory locations above

I am sure you understood. The integer array has only 10 elements and the pointer is set to an address that is 400 bytes larger, based on the address of the 5th element of the array. 400 bytes, because integer is 4 bytes, sometimes 100. The pointer points again into the forest, this time the chance that it points into the same segment is actually quite large. There is probably no SEGMENT FAULT, what is in the memory location to which the pointer now points is left to chance as before.

 

Another nice mistake is to have the pointer point to free space:

void main (void)
{
int x;
int * ptr = NULL;

SomeFunction (ptr);
  
  ...

x = * ptr;
* ptr + = 100;
}


void SomeFunction (int * inputPtr)
{
int localx = 42;

inputPtr = & localx;
}

The following happens here, you create a pointer: int * ptr = NULL;
passes this to a function: SomeFunction (ptr);
In this function the pointer is set to the address of a local variable of this function: inputPtr = & localx;
and after leaving the function the pointer is still used: x = * ptr;

The only problem is that the local Variable localx no longer exists after exiting the function SomeFunction, the memory space of the local variables of the function is released again after the function has ended. This mistake is called one 'dangling pointer' or 'hanging pointer' . Whether the storage space has already been used again or not is now again left to chance, i.e. the program has an error, but can sometimes work.

So always remember "double check your damn pointers".

 












Everything about pointers: