c language pointer

Posted by jadeddog on Tue, 01 Feb 2022 21:54:30 +0100

summary

When defining a variable, the corresponding memory size is reserved, and the variable name therefore corresponds to the address of the variable. The number of memory locations reserved depends on the data type. (& name / function) can be used to determine the memory address,% p represents the output address type data

#include <stdio.h> 
struct 
{
    int x, y, z;
} var3;
union  {char a;short b;int c;} var4;
enum {ROT,GRUEN,BLAU} var5;
int func(void) {return 1;}            
int main() { 
    int var1; 
    var1=7;
    printf("Var1=%d Adresse=0x%x %p\n", var1, (int)&var1, &var1);
    int var2;
    printf("var2=%d   &var1=%p &var2=%p\n",var2,&var1,&var2);
    printf("&var3=%p  &var3.x=%p  &var3.y=%p  &var3.z=%p\n",&var3, &var3.x, &var3.y, &var3.z);
    printf("&var4=%p  &var4.a=%p  &var4.b=%p  &var4.c=%p\n",&var4, &var4.a, &var4.b, &var4.c);
    printf("&var5=%p\n", &var5);
    printf("func=%p\n", func);
    printf("&func=%p\n", &func);
}

Output results

Var1=7 Adresse=0x61fe1c 000000000061FE1C
var2=16 &var1=000000000061FE1C &var2=000000000061FE18
&var3=0000000000407978 &var3.x=0000000000407978 &var3.y=000000000040797C &var3.z=0000000000407980
&var4=0000000000407974 &var4.a=0000000000407974 &var4.b=0000000000407974 &var4.c=0000000000407974
&var5=0000000000407970
func=0000000000401550
&func=0000000000401550

Note:

  • The memory size required for pointer variables is independent of the underlying variable data type, but depends on the calculation width of the system, which is 4-byte / 8-byte.
  • The address displayed is the first address location of the data type

Pointer variable

Syntax: data type * pointer variable name
The pointer variable receives an address. It is equivalent to a pointer variable, but its variable content represents an address (the starting address of other variables).

#include <stdio.h>
#include <string.h>
int main()
{
    int var1, var2;
    int *ptr1;
    ptr1 = &var1;                                    //Zuweisung eines Pointers mit einer Adresse
    int *ptr2 = &var2;                               //Zuweisung eines Pointers
    int var2a, *ptr2a = &var2a; //OK
    // int *ptr2b = &var2b, var2b;                      //KO
    int *ptr3a = (int *)100;                         //No error but incorrect
    // int *ptr3b = 100;                                //KO
    // int *ptr4 = &7;                                  //KO
    ptr1 = ptr2;
    char str[] = "Hallo";
    char *start1 = str;     
    char *start2 = &str[0]; 
    char *ende = &str[strlen(str)-1];
}

*Reference pointer variable

*You can manipulate the address pointed to by the pointer variable

#include <stdio.h>
#include <string.h>
int main()
{
    int var1, *ptr1 = &var1;
    var1 = 7; //Direktes schreiben des Wertes 7 in
    *ptr1 = 7; //Indirektes schreiben des Wertes 7
    printf("%x %x %d %d", ptr1, &var1, *ptr1, var1);
    //Bei Strukturen
    struct xyz
    {
        int x, y, z;
    } var2;
    struct xyz *ptr2;
    ptr2 = &var2; //Startadresse der Struktur zuweisen
    var2.x = 1;
    var2.y = 1;
    var2.z = 7; //Direktes schreiben
    //*ptr2          ‐‐> Zugriff auf die vollständige Struktur (12‐Byte)
    (*ptr2).x = 2;
    (*ptr2).y = 2; //Indirektes Schreiben über deferenzierung
    ptr2 -> x = 3;
    ptr2 -> y = 3;                         //Indirektes Schreiben über deferenzierung
    int *ptr3 = &var2.y; //Adresse eines Strukturelementes
    int *ptr4 = &ptr2 -> y;                //Adresse eines Strukturelementes
    // *ptr2.x = 7;                          // report errors
}

Arithmetic operation of pointer

The compiler usually assigns successive addresses to variables defined one after another in the source code.

#include <stdio.h>
#include <string.h>
int main()
{
    int arr[3] = {123, 456, 789}; //Alle 3 Arrayelemente liegen im Speicher direkt hintereinander
    printf("%x %x %x\n", &arr[0], &arr[1], &arr[2]);
    int var1 = 1, var2 = 2, var3 = 3; //Alle 3 Variablen liegen im Speicher direkt
    int *ptr2 = &var2;                //hintereinander. (Ausnahme bei lokalen Variablen,
                                      //hier optimiert der Compiler ggf. die erste lokale Variable)
    printf("%x %x %x\n", &var1, &var2, &var3);
    printf("%x %x %x\n", ptr2 - 1, ptr2, ptr2 + 1);
    printf("%d %d %d\n", var1, var2, var3);
    printf("%d %d %d\n", *(ptr2 - 1), *(ptr2), *(ptr2 + 1));
}

Operation results:

61fe0c 61fe10 61fe14
61fe08 61fe04 61fe00
61fe00 61fe04 61fe08
1 2 3
3 2 1

Int var[2]={7,8},*ptr=&var;

In the above code, ptr+1 is equivalent to ptr+(1*sizeof(int))

  • The addition and subtraction of a pointer and an integer means that the first address of the pointer plus the product of the integer and sizeof (the type the pointer points to)
  • Addition, multiplication, division and logical operation of two pointers are not allowed, and the compiler will report an error
  • It is possible to subtract two pointers

Pointer operation should pay attention to:
Pointer operations can lead to invalid memory addresses - programmers should know what they are doing when using pointer operations. Know what they are doing when using pointer operations. Storing an invalid address in a pointer variable is not a problem, but there are problems when referencing:

  • The program crashes because a memory location not allocated to the program is accessed - > segmentation failure is accessed - > segmentation failure (in these cases, the contents of the buffer are contained in the standard output buffer and are not output. Therefore, it is helpful to print out the output of the following files: send important information with fprintf(stderr,...) or fflush(stdout).
  • Address refers to a valid memory address, which has different "meanings", for example, assigned to another variable. For example, it belongs to another variable. Dereferencing this address will change the contents of another variable, which will only be noticed when using that variable. Use this variable later. In this case, the performance of the program is mostly "strange". This kind of error is difficult to find, because the time when the error is found and its
    The occurrence of errors is far apart in time

Increment and decrement related to address characters

Var=*ptr++ //Entspricht var=*ptr; ptr=ptr+1;
Var=*ptr‐‐ //Entspricht var=ptr; ptr=ptr‐1;
Var=++ptr //Entspricht ptr=ptr+1; var=ptr;
Var=‐‐ptr //Entspricht ptr=ptr‐1; var=*ptr;

#include <stdio.h>
#include <string.h>
int var1=1, var2=2, var3=3; //Bitte als globale Variablen anlegen
int main()
{
    int *ptr = &var2;
    var1 = var2++;
    var1 = ++var2;          //Inkrementieren einer Variablen
    printf("%d ", *ptr++);   //4
    printf("%d ", (*ptr)++); //3
    printf("%d ", *--ptr); //4
    char str[] = "hallo\0";
    char *ptr2 = &str[0];
    for (; *ptr2++;);                                            
    printf("%d", ptr2 - str); //6
    char *ptr3 = &str[0];
    for (; *++ptr3;);                                            
    printf("%d", ptr3 - str); //5
}

Pointer difference

The difference between two pointers indicates the distance between the two pointers, that is, the multiple of the basic data type.
The result data type of subtraction is ptrdiff_t (depending on the system, it may be signed int/ unsigned long/ unsigned long long)

#include <stdio.h>
#include <string.h>
int main()
{
    struct xyz
    {
        int x, y, z;
    } xyz[] = {{1, 2, 3}, {4, 5, 6}, {0, 0, 0}};
    struct xyz *ptr;
    for (ptr = xyz; ptr -> x; ptr++);
    printf("%d", (int)(ptr - xyz)); //2
}

Pointer comparison

#include <stdio.h>
#include <string.h>
int var1, var2; //Bitte als globale Variablen anlegen
int main()
{
    int *ptr1 = &var1, *ptr2 = &var2;
    printf("%d", (ptr1 == ptr2));
    printf("%d", (ptr1 < ptr2));
    printf("%d", (ptr1 <= ptr2));
    printf("%d", (ptr1 >= ptr2));
    printf("%d", (ptr1 == NULL));
    printf("%d", (ptr1 > NULL));
}

Operation results:

011001

Initialization pointer

A pointer (Reference) must be given a valid storage address before it is used for the first time

char *ptr;
*ptr = 47;

The above code is wrong because the first line does not initialize a storage space for the variable after defining it.

- The uninitialized global pointer is initialized to 0, that is, the reference will cause the contents of memory address 0 to be returned. stay Windows/Linux In, this is not assigned to the process, thus causing the program to crash.
- Uninitialized local pointers are assigned a random value, that is, an interpretation is likely to read the memory of an unallocated memory address, or cause a memory address or cause the program to crash.

Therefore, initializing a pointer has the following options
- Initialize with the address of the global variable
 global variable/Static local variable/Functions are valid throughout the program, and pointers to these addresses are therefore always valid when the program is running.
- Initialize with the address of the local variable
 Local variables and parameters are only valid within the scope of the function body or block. Operations on pointers are allowed only during the operation of a function or block scope

```c
//OK
Void func(int par)
{
    int lok;
    int *ptr1 = &par;
    int *ptr2 = &loc;
    *ptr1++;
    *ptr2++;
}
//KO
int *func(void){
	int lok = 7;
	return(&lok);
	// Memory is released at the end of the function body
}
Void main()
{
   int *ptr = func();
   *ptr=7;
}
//OK
void func1(int *ptr){
	*ptr = 7;//OK
}
Void func2(void)
{
    int lok = 7;
	func1(&lok);
}
//KO
Int *ptr;
void func(void)
{
    int lok=7;
    ptr=&lok;
	*ptr=8;
}
Void main(void)
{
    *ptr=7;
    func();
    *ptr=7;
}

Initialize pointer with heap space:
Memory pool, from which all functions can request memory of any size. The requested memory is then reserved until it is explicitly released again. In other words, the C language runtime environment can now allocate this memory to other callers. Allocate this memory to other callers. Therefore, access to memory is no longer allowed after release.

int main(int argc, char const *argv[])
{
    char *ptr = malloc(100);
    strcpy(ptr, "hello world");
    printf("%s\n", ptr);
    free(ptr);
    ptr = null;
    printf("%s", ptr);
    return 0;
}

After free (ptr), it is best to point the pointer to null

When the pointer is not initialized or the address pointed to by the pointer fails, the pointer is called a wild pointer

cast operator

In c language, there is no implicit type conversion for pointer assignment and comparison, so the two pointers must be of the same type. Otherwise, the compiler will report an error.
One pointer can be converted to another by explicit type conversion (cast operator). There is no data type conversion, but the interpretation of the content of changing the memory address.
No matter what type of pointer variable it is, the stored value is the address (value of type int). So what is the role of declaring different types? The answer is to specify the number of bytes per pointer movement in memory. For example, when "int * PA = & a" is defined, the int type takes up 4 bytes, and the pointer moves from the first address to read 4 bytes. Similarly, when the short type occupies 2 bytes, the pointer moves 2 bytes. Get the value of the variable by declaring the pointer type and telling the pointer how many bytes to move each time.

 	short c[2];          //It is equivalent to applying for two consecutive memory spaces, each of which is 2 bytes
    c[0] = 1;            //Assign 1 to the first short space
    c[1] = 1;            //Assign a value of 1 to the second short space
    short *p1 = c;       //p1 points to c [] first address
    int *p2 = (int *)p1; //p2 points to the first address of c [] and casts the type to int
    printf("p1 Point to:%p\np2 Point to:%p\n", p1, p2);
    printf("p1 Take out:%d\np2 Take out:%d\n", *p1, *p2);
    return 0;

Operation results:

p1 points to: 000000000061FE0C
p2 points to: 000000000061FE0C
p1 take out: 1
p2 take out: 65537

void pointer

In programming language C, the only exception to pointer allocation / comparison is void pointer (general pointer, anonymous pointer, unformed pointer). This is compatible with any other data pointer, so you can compare and assign values without explicit conversion.
Due to the void data type, you cannot use a void pointer alone to reference content.
In GNU-C, pointer operation with null pointer is allowed. Here, it is assumed that the referenced memory size is 1.
Application:

  1. The return value type of malloc function is void pointer, so malloc function can assign value to each pointer
    Int ptr1=malloc(10sizeof(int));
    Struct {int x,y,z;} *ptr2=malloc(12);
  2. If a structure is to be "hidden" by the caller, the structure definition will not be written in the header file, but in the C file. The caller then stores the address in a void pointer.

NULL pointer

Global uninitialized variables are initialized to 0 at program startup.
Since these criteria are considered uninitialized, a valid memory address 0 is considered an invalid memory address. Since it is impossible to compare a pointer with an integer constant 0 (see the CAST operator), a macro (see preprocessor) NULL is defined, which converts the constant 0 to an invalid pointer with address 0.
#define NULL ((void *)0)
This macro is contained in the header file stddef H medium.

Application:

  1. Used to judge whether malloc allocates memory successfully
int *ptr=malloc(100);
If(ptr==NULL)
  1. Array pointer. The end of the string array is marked with NULL
char *strarray[]={"hallo","Du",NULL};
int lauf;
for(lauf=0;strarray[lauf];lauf++)
printf(strarray[lauf]);

be careful:
In Windows/Linux systems, the memory address 0 is not assigned to the process, so the reference will lead to runtime errors, while in embedded systems, the memory address 0 is well assigned to the "process". This is usually the location of the interrupt vector table, so writing to this address may have serious consequences.

Pointer when calling a function

An important application field of pointers is to participate in the use of return value pointers during function calls. The main goal here is, on the one hand, to avoid time-consuming data replication, on the other hand, to enable the callee to directly change the caller's value.
Value transfer:

void func(int lok) {lok=hallo*2;}
func(7); 
func(var);

Here, the constant 7 and the variable var will be copied into the formal parameter lok, and the change of the formal parameter lok will not change the source variable

Address transfer:
If the content of the variable is not passed, but the address of the variable, the callee may now change the content of the original variable through the address.

void func(int *ptr) {*ptr=10;  ptr=ptr+7;}
int main(int argc, char const *argv[])
{
    int var = 1;
    printf("%x ", &var);
    func(&var);
    printf("%d ", var);
    printf("%x ", &var);
}

Output result:

61fe1c 10 61fe1c

Address transfer application:

  • Can replace the function with return value, when
    • More than one value needs to be returned
    • Function returns value as status
  • It can make the program run faster by exchanging addresses instead of copying content
Void swap(int *a, int *b) {int temp=*a; *a=*b; *b=temp;}

Return value:
In addition to passing parameters using pointers, you can also return pointers.

char *strstr( const char *haystack, const char *needle);
char *strtok(char *str, const char *delim). 

Here, we also avoid more time-consuming copying, but only return the address where the actual content is located.
Special attention is paid to "looking for an address". The returned address must still be valid after the end of the function, so a pointer to a local variable cannot be returned. Only pointers to global variables, static local variables, or pointers to heap areas make sense.
The state of a function is often returned by a return value. In the case of pointers, errors in function execution are represented by a pointer to a NULL address. In the case of an integer as the return value, - 1 is returned according to the POSIX standard.

const modifier pointer

Const modifies the character on the left. When const is on the far left, it modifies the character on the right next to it

const int *var1;
int const *var2;

const here modifies int to indicate that the reference (the value pointed to) of the address variable is immutable and the address is changeable

int *const var

const modifier * here indicates that the address is immutable and the reference of the address (the value pointed to) is variable

int const *const var

Both the address and the reference to the address are immutable

Application:

  • When the function body is using a pointer to pass parameters, const should be used to ensure that the pointer reference content remains unchanged
char *strcpy(char *dst, char const *src);

string constant

The string will be stored in the constant area, and the string pointer returns the address of the first character

char *p1="Hallo"; //Hier müsste eigentlich compiler Warning ausgeben
const char *p2="du";    //Korrekte Schreibweise

Therefore, the string defined by pointer cannot be changed. The following code will cause the program to terminate

p1[1]='x';
*((char *)p2)='y';

String constants are also generated when initializing local variables, such as char arr [] = "hello"; The following code is executed inside the compiler

Const char *anonymous3="hallo";
Char arr[5+1];
memcpy(arr,anonymous3);

Function pointer

If a function is defined in the program, the system will allocate a storage space for the function code at compile time. The first address of this storage space is called the address of this function. And the function name represents this address. Since it is an address, we can define a pointer variable to store it. This pointer variable is called function pointer variable, which is called function pointer for short.

Definition method: function return value type (* pointer variable name) (function parameter list);
Note:

  • *The parentheses at both ends of "(pointer variable name)" cannot be omitted. The parentheses change the priority of the operator. If you omit the parentheses, you will not define a function pointer, but a function declaration, that is, a function whose return value type is pointer type.
  • Pointer variables pointing to functions do not have + + and -.
# include <stdio.h>
int Max(int, int);  //Function declaration
int main(void)
{
    int(*p)(int, int);  //Define a function pointer
    int a, b, c;
    p = Max;  //Assign the function Max to the pointer variable p so that P points to the Max function
    printf("please enter a and b:");
    scanf("%d%d", &a, &b);
    c = (*p)(a, b);  //Call Max function through function pointer
    printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
    return 0;
}
int Max(int x, int y)  //Define Max function
{
    int z;
    if (x > y)
    {
        z = x;
    }
    else
    {
        z = y;
    }
    return z;
}

Output result:

please enter a and b:3 4
a = 3
b = 4
max = 4

typedef function pointer:

// Define a prototype as int fun (int a); Function pointer to
typedef int (*PTRFUN) ( int aPara );
PTRFUN pFun; // pFun is the function pointer variable name

Topics: C