[C language] Pointer -- the basic knowledge of pointer you must master

Posted by coldfused on Sat, 25 Sep 2021 20:54:37 +0200

preface

Pointer is the key and difficult point of C language. Mastering pointer skillfully can better understand the storage mode of calculation, simplify the code and enhance the efficiency of the program.

1, Pointer overview

A pointer is a variable that holds the address (number) of the memory unit.

Pointer creation

When defining a pointer variable, add '*' in front of the variable to represent that the variable is a pointer, and then add a type name in front to represent the type of the pointer, which is called XX pointer.

Pointer initialization:

  • Use & (take address operator) to obtain the address of the variable and assign it to the defined pointer variables. They need to be of the same type. Cast can be used when they are of different types.
  • If you don't know what address to store temporarily, you can first point to NULL ((void*)0). NULL is essentially 0. 0 is not allowed to be stored.
#include <stdio.h>
int main()
{
	int a = 10;//Open up a space in memory
	int *p = &a;//Here we take the address of variable a, and we can use the & operator.
				//Store the address of a in the p variable, p is a pointer variable.
	return 0;
}

Pointer size

Pointers can be of different types, such as char *, int *, float *, double *, long * and other well-known types. How much space does the pointer occupy in memory?

For a 32-bit machine, assuming that there are 32 address lines, it is assumed that each address line generates an electrical signal positive / negative (1 or 0) when addressing
Then the address generated by the 32 address lines will be:

00000000 00000000 00000000 00000000
......
111111111 111111111 111111111 111111111
There are 232 addresses in total. If each address can point to a memory unit (one byte), there are 232 memory units.

We know that the size of a memory unit is one byte and an address line is composed of 32 bits 01. Therefore, 32 bits, i.e. 4 bytes, are required to store the pointer (address). Therefore, on the 32-bit platform, no matter what type of pointer is, it is 4 bytes.

Similarly, there are 64 address lines on the 64 bit platform, and each address is 64 bits, so 8 bytes are required.

How to use pointers

Use the '*' operator to dereference the pointer to obtain the value of the pointer pointing to the space
Let's run the code below.

#include <stdio.h>
int main()
{
	int n = 0x11223344;
	char* pc = (char*)&n;//Cast the address (pointer) of n to char * type
	int* pi = &n;
	*pc = 0;//Change the value it points to space
	*pi = 0;
	return 0;
}

We start debugging the code and check the memory of n. the address is on the far left, the data stored in the memory is displayed in hexadecimal on the right, and n is also stored in hexadecimal. Two hexadecimals represent a byte, as shown in the following figure:

When the statement * pc=0 is executed;

Because pc refers to char * type, only one byte can be accessed, so only one byte can be modified.
Re execute * pi = 0;

At this time, all the memory data of n becomes 0, indicating that the pointer of int * type can access 4 bytes.

Summary:
The type of pointer determines how much permission you have to dereference the pointer (can operate several sections). For example, the dereference of char * pointer can only access one byte, while the dereference of int * pointer can access four bytes.

Secondary pointer

Pointer variable is also a variable. If it is a variable, it has an address. Where is the address of pointer variable stored? This is the secondary pointer.
That is, the pointer that stores the address of the pointer variable. The value of the space pointed to by the secondary pointer is a primary pointer.

int main()
{
	int a = 20;
	int* p = &a;

	int** pp = &p;

	printf("%d\n", *p);//Dereference can get the pointer pointing to the value in the space

	printf("%d\n", *p); //For the secondary pointer, you need to dereference twice to get the initial value
	return 0;
}


2, Field pointer

The wild pointer is that the position pointed to by the pointer is unknown (random, incorrect and unrestricted).

Reasons for the formation of field pointer

  1. Pointer not initialized
#include <stdio.h>
int main()
{
	int *p;//Local variable pointer is uninitialized and defaults to random value
	*p = 20;//It is not allowed to put data into a random address (not belonging to the space of this program)
	return 0;
}
  1. Pointer out of bounds access
    The pointer wants to access the space that does not belong to the program, resulting in cross-border access and program error. It is most likely to occur when using the array.
#include <stdio.h>
int main()
{
	int arr[10] = {0};
	int *p = arr;
	int i = 0;
    for(i=0; i<=11; i++)
	{
  		//When the range pointed to by the pointer exceeds the range of array arr, p is a wild pointer
    	*(p++) = i;
	}
	return 0;
}
  1. The space pointed to by the pointer is released
    When the dynamically opened memory is released, the pointer at this time belongs to the wild pointer, and the position it points to cannot be accessed normally. Dynamic memory allocation will be discussed in detail later.
int main()
{
	//Open up a shaping space
	int* p = (int*)malloc(sizeof(int));

	//Free the space
	free(p);
	//At this time, p is the wild pointer, because the space it points to has been inaccessible, and it generally needs to be set to null
	//Point it to a null pointer to prevent errors in subsequent calls
	p = NULL;
	return 0;
}

How to avoid wild pointer

  • Pointer initialization
  • Be careful that the pointer is out of range
  • Pointer to space release even if set to NULL
  • Check the validity of the pointer before use

3, Basic operation of pointer

There are generally two operations on pointer, pointer + pointer. The semantics is legal, but it has no meaning.

  • Pointer ± integer
  • Pointer pointer

Pointer ± integer

Perform + 1 operation on pointers of type int and char respectively,%p print in hexadecimal

int main()
{
	int n = 10;
	char* pc = (char*)&n;//Cast the address (pointer) of n to char * type
	int* pi = &n;
	printf("&n:     %p\n", &n);
	printf("pc:     %p\n", pc);
	printf("pc + 1: %p\n", pc + 1);
	printf("pi:     %p\n", pi);
	printf("pi + 1: %p\n", pi + 1);
	return 0;
}


Summary:
The type of pointer determines how far the pointer moves forward or backward.

Pointer pointer

int main()
{
	int arr[10] = { 0 };
	//Fetch the addresses of the first and last elements of the array
	int* start = arr;
	int* end = &arr[9];
	printf("%d\n", end - start);
	return 0;
}


Summary:
Pointers - pointers are equal to the number of types of data that differ between them. That is, the difference between the 10th element and the first element in this example is 9.

4, Pointers and arrays

Let's see what the array name is

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}


It can be seen that the array name and the address of the first element of the array are the same.

Conclusion: the array name represents the address of the first element of the array. It's also a pointer

Then we can replace the array name with a pointer, as shown in the following code:

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);//Calculate the number of array elements

	//Assign a value to an array
	for (i = 0; i < sz; i++)
	{
		*(p + i) = i;
	}
	//Print array data
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}


be careful:
The array name is not the address of the first element in the following two cases

  1. Sizeof (array name) - the array name here is not the address of the first element, but represents the whole array. What is calculated here is the size, unit or byte of the whole array
  2. &Array name - the array name here is not the address of the first element, but represents the entire array. What you get is the address of the entire array
int main()
{
	int arr[10] = { 0 };

	int sz = sizeof(arr);
	printf("sizeof(arr)The size of the entire array is calculated:%d\n", sz);

	printf("Array first address:      %p\n", arr);
	printf("Address of the first element of the array:  %p\n", &arr[0]);
	printf("Address of array:      %p\n", &arr);

	printf("Array header address+1:     %p\n", arr + 1);
	printf("Address of the first element of the array+1: %p\n", &arr[0] + 1);
	printf("Address of array+1:     %p\n", &arr + 1);

	//The array name is indeed the address of the first element
	//There are two exceptions:
	//1. Sizeof (array name) - the array name here is not the address of the first element, but represents the entire array. What is calculated here is the size, unit or byte of the entire array
	//2. & array name - the array name here is not the address of the first element, but represents the entire array. What you get is the address of the entire array
	//
	return 0;
}

5, Pointer array

An array of pointers.

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int* arr[10] = { &a,&b,&c };
	for (int i = 0; i < 3 ; i++)
	{
		printf("%d ", *(arr[i]));
	}
	return 0;
}

summary

Pointer is a very important part of C language. It has many contents and is not easy to understand. This paper only introduces some basic knowledge, and we will have an in-depth understanding of pointer in the future.

I hope it can help you learn the pointer!

Topics: C C++ C# pointer