Pointer in C

from Wikipedia, the free encyclopedia

The article Pointers in C describes the use of pointers in the C programming language . Pointers are variables in which memory addresses are stored. They are often used in C and are the only possible implementation for some programming concepts.

definition

The definition of a pointer consists of the data type of the pointer and the desired pointer name. The data type of a pointer in turn consists of the data type of the value to which it is pointed and an asterisk . A data type of a pointer would be e.g. B. double*.

int* zeiger1;           /* kann eine Adresse aufnehmen, die auf einen Wert vom Typ Integer zeigt */
int *zeiger2;           /* das Leerzeichen kann sich vor oder nach dem Stern befinden */
int * zeiger3;          /* ebenfalls möglich */
int *zeiger4, *zeiger5; /* Definition von zwei Zeigern */
int *zeiger6, ganzzahl; /* Definition eines Zeigers und einer Variablen vom Typ Integer */

A defined pointer that has not yet been initialized points to a random address. When this address is accessed, the program may crash or the value saved at this address may be overwritten. Pointers should therefore always be initialized.

Assignments

An address is assigned to a pointer using the address operator, a field, another pointer or the value of NULL.

int variable = 0;
int feld[10];
int *zeiger;
int *zeiger2;
zeiger = &variable;     /* mit Adressoperator */
zeiger = feld;          /* mit Feld */
zeiger = zeiger2;       /* mit weiterem Zeiger */
zeiger = NULL;          /* mit NULL */

Address operator

The programmer cannot determine the address of a variable, but it can be determined using the unary address operator &. The address of a data object cannot be changed over the entire runtime of the program. The address operator can be applied to all data objects with the exception of bit fields and data objects of the storage class register.

int variable = 0;                 /* Definition einer Variable vom Typ int und Initialisierung */
int *zeiger = &variable;          /* Definition einer Zeigervariablen und Initialisierung */
printf("%p", (void*)&variable);   /* gibt Adresse der Variablen in einer implementierungsabhängigen Darstellung aus, z. B. als Hexadezimalzahl */

Content operator

If you have an address available, you can use the content operator *to access the value stored at this address. The asterisk in the definition of a pointer *is not the content operator *, so the same symbol is used for different purposes. When using the content operator on a pointer, one also speaks of dereferencing the pointer.

int variable = 3;
int *zeiger = &variable;        /* hier handelt es sich nicht um den Inhaltsoperator */
printf("%d", *&variable);       /* gibt den Wert „3“ aus */
printf("%d", *zeiger);          /* gibt den Wert „3“ aus */

*zeiger = 5;
printf("%d", *zeiger);          /* gibt den Wert „5“ aus */
*zeiger = *zeiger + 1;
printf("%d", *zeiger);          /* gibt den Wert „6“ aus */

Zero pointer

If a pointer is not supposed to point to an object, the value can be NULLassigned to it. The pointer is therefore invalid and as long as it is not assigned a valid address, it cannot be used sensibly. Dereferencing usually leads to a runtime error and program termination. However, it makes sense to compare (data) object pointers with NULLwhat is also the main application.

int *zeiger;
zeiger = NULL;

*zeiger = 0;  /* Fehler */

zeiger = malloc( sizeof(*zeiger) );
if( zeiger == NULL )
  puts("Fehler bei Speicherreservierung");

NULLis a macro and is defined in several header files (at least in stddef.h). The definition is given by the standard depending on the implementation and implemented appropriately by the compiler manufacturer, e.g. B.

#define NULL 0
#define NULL 0L
#define NULL (void *) 0

Pointer arithmetic

Increase and decrease hands

Pointers can only be changed using the arithmetic operations of adding an integer and subtracting an integer. When adding an integer, the address stored by the pointer is increased accordingly; when subtracting it is decreased.

char zeichen;
char *zeiger = &zeichen;
printf("%p\n", zeiger);   /* gibt z. B. die Adresse „0019FF01“ aus */
zeiger = zeiger + 1;
printf("%p\n", zeiger);   /* gibt dann die Adresse „0019FF02“ aus */

However, the sum of an address stored in a pointer and an integer results in the address increased by the integer in C only with a pointer to a character. Before the addition, the integer is multiplied by the memory size of the data type to which the pointer refers. If an integer requires four bytes, adding an address that points to an integer with the integer one results in the address four integers higher. With the addition and subtraction on pointers, you can easily jump one or more values ​​forwards or backwards.

int zahl;
int *zeiger = &zahl;
printf("%p\n", zeiger); /* gibt z. B. die Adresse „0019FF01“ aus */
zeiger = zeiger + 2;
printf("%p\n", zeiger); /* gibt dann „0019FF09“ aus, also 0019FF01 plus 4 mal 2 */

As is common in C, addition and subtraction can also be written in abbreviated form here.

zeiger += 5;
zeiger++;

Comparisons of pointers

The comparison operations and can be used to compare pointers .

Difference of pointers

The stddef.hprimitive data type defined in the header file is ptrdiff_tavailable to record how many bytes two pointers are apart . It is used to store the result of subtracting two pointers, the result of which is equivalent to removing the two pointers.

char *zeichenkette = "hallo";
char *zeiger = &zeichenkette;
char *zeiger2 = zeiger + 2;
ptrdiff_t differenz;
differenz = zeiger2 - zeiger;
printf("%d\n", differenz);     /* gibt die Differenz in Bytes aus, hier „2“ */

Pointers and fields

Pointers and fields can be used with the exact same syntax by the programmer in many cases, but not all.

int *zeiger;
int feld[] = { 1, 2, 3 };
zeiger = feld;
/* Zugriff auf die in einem Zeiger bzw. einem Feld gespeicherte Adresse */
printf("%p\n", zeiger);        /* gibt beispielsweise „0019FEEC“ aus */
printf("%p\n", feld);          /* gibt dann ebenfalls „0019FEEC“ aus */
/* Zugriff auf die Adresse eines Elements eines Feldes */
printf("%p\n", &zeiger[1]);    /* gibt dann ebenfalls „0019FEF0“ aus */
printf("%p\n", &feld[1]);      /* gibt dann ebenfalls „0019FEF0“ aus */
printf("%p\n", zeiger + 1);    /* gibt dann ebenfalls „0019FEF0“ aus */
printf("%p\n", feld + 1);      /* gibt dann ebenfalls „0019FEF0“ aus */
/* Zugriff auf den Wert eines Elements eines Feldes */
printf("%d\n", zeiger[1]);     /* gibt „2“ aus */
printf("%d\n", feld[1]);       /* gibt „2“ aus */
printf("%d\n", *(zeiger + 1)); /* gibt „2“ aus */
printf("%d\n", *(feld + 1));   /* gibt „2“ aus */

Working with pointers differs from working with fields in that the address of a field is constant and therefore cannot be changed.

int *zeiger;
int feld[3];
zeiger = feld;                       /* „feld = zeiger;“ ergäbe hingegen einen Fehler */
zeiger++;                            /* „feld++;“ ergäbe hingegen einen Fehler */
/* auch hat der Zeiger selbst eine andere Adresse als das Feld */
printf("%p: %p\n", &zeiger, zeiger); /* ergibt beispielsweise „0019FEF8: 0019FEE4“ */
printf("%p: %p\n", &feld, feld);     /* ergibt dann           „0019FEE4: 0019FEE4“ */

If a field is passed to a function, it is always converted into a pointer to its first element, regardless of the function declaration.

void funktion(int feld[]);
void funktion(int *feld);  /* gleichbedeutend wie obige Deklaration */

Pointer to pointer

A pointer can point to objects of any data type, including pointers themselves. This can be continued indefinitely, with pointers that point to pointers, point to pointers, etc. In practice, pointers to pointers do happen, and very rarely still pointers to pointers that point to pointers.

int zahl = 3;
int *zeiger = &zahl;    /* Zeiger auf Objekt vom Typ Integer */
int **zeiger2 = &zeiger; /* Zeiger auf Zeiger auf Objekt vom Typ Integer */

Pointer to strings

A character string is always a field whose field elements are characters. A pointer can be used to point to the beginning of a character string. Pointers to character strings are often used, for example when passing character strings to functions.

char feld[] = "Hallo";
char *zeiger = "Welt!"; /* „zeiger“ zeigt auf ein anonymes Array */
feld[3] = 'Z';          /* das Ergebnis von „zeiger[3] = 'Z';“ ist im Standard hingegen nicht definiert*/
zeiger = feld;          /* „feld = zeiger;“ ist hingegen nicht möglich */
printf("%s - %zu\n", feld, sizeof(feld));     /* gibt z. B. „HalZo - 6“ aus */
printf("%s - %zu\n", zeiger, sizeof(zeiger)); /* gibt z. B. „HalZo - 4“ aus */

application areas

Automatic storage management

In contrast to automatic or static memory, dynamic memory is used in C in situations in which the required size is only known at runtime or the desired size exceeds the limits of the automatic / static memory in the process. In order to request dynamic memory for the program during runtime, the function malloc(or functions similar to it calloc, realloc) must be used in C. mallocreserves the required memory and returns a pointer to it. This memory must also be released manually in C with the function after use free.

In order to work with dynamic memory in C, it is therefore essential to work with pointers as well.

int *zeiger = malloc(sizeof(int));  /* Zeiger auf den Beginn eines zur Laufzeit reservierten Speicherbereiches, hier Speicher für genau einen int-Wert */

... Verwendung von zeiger ...
zeiger[0] = 1;
printf("%d", zeiger[0]);
*zeiger = 2;
printf("%d", *zeiger);

free(zeiger);    /* Freigeben des Speichers */

... nach free() bedeutet die Verwendung von zeiger undefiniertes Verhalten (UB) ...

When releasing dynamic memory with free(), it must be ensured that the pointer value (i.e. the stored address) is exactly the same as at the time of mallocand that freethis address is only called once exactly:

int *zeiger = malloc( 10 * sizeof(int));

... Verwendung von zeiger ...
for( int i=0; i<10; i++ )  zeiger[i] = i;
for( int i=0; i<10; i++ )  printf("%d", zeiger[i]);

free(zeiger);    /* Freigeben des Speichers */
free(zeiger);    /* Fehler! */
int *zeiger = malloc( 10 * sizeof(int));

zeiger++;

free(zeiger);    /* Fehler! */

Pointer as function parameter

For function parameters that are not transferred as pointers ( call by value ), a copy is created within the function. If a copy is not necessary or undesirable, it is also possible to pass pointers to data objects to functions ( call by reference ). Another important reason for passing pointers to functions is the restricted scope of variables. It is only possible to change variables of calling program blocks within functions if they are either global (which is usually undesirable) or if pointers to these variables are transferred to the function.

void funktion(int *zeiger) {
    *zeiger = 1;              /* der Wert an der übergebenen Adresse wird „1“ mit überschrieben */
}
main() {
    int ganzzahl = 0;
    funktion(&ganzzahl);      /* als Argument wird eine Adresse übergeben */
    printf("%d\n", ganzzahl); /* gibt „1“ aus */
}

Passing parameters using pointers is also the only way to be able to pass functions as arguments to other functions.

Pointer as return value of a function

Many functions of the standard library return a pointer as a return value. The pointer returned is always a pointer to the start address of the return type. This method is mainly used in C to transfer character strings and structures.

int *funktion(void) {
    static int zahl = 3;
    int *zeiger = &zahl;
    return zeiger;           /* hier wird ein Zeiger zurückgegeben */
}
main() {
    int *zeiger;
    zeiger = funktion();
    printf("%d\n", *zeiger); /* gibt „3“ aus */
}

Data structures

See the article Verbund (data type) .

Recursive data structures

Recursive data structures such as lists or trees can hardly be implemented without pointers.

Processing of data objects of any type

With the help of the typeless voidpointer, data objects of any type can be processed.

Memory size of pointers

The amount of memory a pointer requires depends on the implementation and is usually between two and eight bytes. The size is determined with the function sizeof. Since a pointer only ever stores one address, it does not matter whether the pointer points to an integer or a double variable, for example.

int *zeiger;
double *zeiger2;
printf("%zu\n", sizeof(zeiger));  /* gibt zum Beispiel „4“ aus */
printf("%zu\n", sizeof(zeiger2)); /* ergibt denselben Wert noch einmal, hier also wieder „4“ */

Type assurance

The data type pointer is strictly typed in C. For example, the assignment of an address of a double variable to a pointer of the data type is int *permitted, but usually does not produce meaningful results. Therefore, pointer variables in C are not type-safe and are only assignment-compatible in terms of the memory address , but not with regard to the referenced data types . This can easily lead to type violations during programming , which in turn can cause unstable or faulty programs.

literature

  • Brian Kernighan, Dennis Ritchie: The C Programming Language. 2nd edition, Prentice Hall, Englewood Cliffs (NJ) 1988, ISBN 0-13-110362-8 , pp. 93-126. (German translation: Brian Kernighan, Dennis Ritchie: Programming in C. With the C-Reference Manual in German. 2nd edition, Hanser, Munich / Vienna 1990, ISBN 3-446-15497-3 ).

Individual evidence

  1. ^ Brian Kernighan, Dennis Ritchie: The C Programming Language . 2nd edition, Prentice Hall, Englewood Cliffs (NJ) 1988, ISBN 0-13-110362-8 , p. 94.
  2. CSE 341: Unsafe languages ​​(C) , Computer Science washington.edu, accessed on December 2, 2016.