[C language beginner level] ❤️ Is a C language primary pointer so hard core? ❤️

Keywords: C

reminder

Hello, I'm Cbiltps. If there are difficult to understand sentences and key points that are difficult to express in words in my blog, I will have pictures. So my blog with pictures is very important!!!

If you are interested in me, please look at mine First blog!

Opening introduction

Since today, I have written a blog about C language pointers. My blog has two columns: Advanced C language and advanced C language.

There are many contents of pointers, so there will be more in-depth explanation in [advanced C language], but it will not be updated immediately (I am going to write the structure and other contents after the initial pointer is written). Please look forward to it!!!

Key points of this chapter

  1. What is the pointer
  2. Pointer and pointer type
  3. Field pointer
  4. Pointer operation
  5. Pointers and arrays
  6. Secondary pointer
  7. Pointer array

Text start

Pre school preparation (understanding memory)

To learn and understand pointers, first pay attention to memory!

Memory is a particularly important memory on the computer. The operation of programs in the computer is carried out in memory.

Therefore, in order to use memory effectively, we divide the memory into small memory units. After careful calculation and trade-off, we find that it is more appropriate to give a byte to a corresponding address.

In order to effectively access each unit of memory, the memory unit is numbered. These numbers are called the address of the memory unit.

An explanation of the address line: for a 32-bit machine, assuming that there are 32 address lines, it is assumed that each address line generates high level (high voltage) and low level (low voltage) during addressing, which is (1 or 0).

When creating variables, they will open up space in memory; And all variables have addresses. The variable addresses are as follows:

#include <stdio.h>
int main()
{
	int num = 10;
	&num;//Fetch the address of num
	//Note: there are 4 bytes of num, each byte has an address, and the address of the first byte (smaller address) is taken out
	printf("%p\n", &num);//Print address,% p is printed as an address
	return 0;
}

1. What is the pointer?

In computer science, a Pointer is an object in a programming language. Using an address, its value directly points to a value stored in another place in computer memory.

Since the required variable unit can be found through the address, it can be said that the address points to the variable unit.

Therefore, the address visualization is called "pointer". It means that the memory unit with its address can be found through it.

We have introduced memory to some extent. Let's take a look at pointers:

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

1.1 understanding of pointer

  • The address points to a certain memory space, so the image of the address is called a pointer
  • A variable is used to store the address (pointer), so a variable is a pointer variable
int a = 10;//Create space when creating variables
int* pa = &a;//Its type is int *, and pa is a pointer variable
//pa is used to store address (pointer)

In the future colloquial description, when we talk about pointer: pointer may be an address, of course, it may also be a pointer variable. We should be able to distinguish these two things!

2. Pointer and pointer type

2.1 pointer variable size

In a 32-bit machine, a memory unit is a space of 32 bits, which is converted to 4 bytes; 64 bit machines are 8 bytes.

Of course, it can also be verified by code:

#include <stdio.h>

int main()
{
	printf("%d\n", sizeof(char*));
	printf("%d\n", sizeof(short*));
	printf("%d\n", sizeof(int*));
	printf("%d\n", sizeof(double*));//It was found that all the prints were 4

	return 0;
}

Conclusion: the pointer size is 4 bytes on 32-bit platform and 8 bytes on 64 bit platform.

2.2 meaning of pointer type

First ask a question:

The pointer size is 4 bytes on the 32-bit platform and 8 bytes on the 64 bit platform. No matter what type, everyone's size is the same. Why distinguish between types?

First take out our two pieces of code for comparison:

//Code 1:
#include <stdio.h>

int main() 
{
	int a = 0x11223344;
	int* pa = &a;
	*pa = 0;
	return 0;
}
//Code 2:
#include <stdio.h>

int main() 
{
	int a = 0x11223344;
	char* pa = &a;
	*pa = 0;
	return 0;
}

Then open the memory window and observe:

After reading the above analysis, can you feel the meaning of type?

The meaning of pointer type: determines how many bytes are accessed at a time (the size of memory accessed) during pointer dereference operation.

Not yet. Let's look at another piece of code:

#include <stdio.h>

int main() 
{
	int a = 10;
	int* pa = &a;
	char* pc = &a;

	printf("%p\n",pa);
	printf("%p\n", pa+1);
	printf("------------\n");
	printf("%p\n", pc);
	printf("%p\n", pc+1);

	return 0;
}

Operation results:

Meaning of pointer type 2: determines the step size of pointer + - integer (skip a few bytes when pointer + - integer).

2.3 practical application of pointer meaning

Pointer dereference is used here, and the following two codes are directly:

#include <stdio.h>

int main()
{
	int arr[10] = { 0 };
	int* p = arr;//&Arr [0] - type is int*
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 1;//Replace 0x 00 01 with 1
	}

	return 0;
}
#include <stdio.h>

int main()
{
	int arr[10] = { 0 };
	char* pa = arr;
	int i = 0;

	for (i = 0; i < 40; i++)
	{
		*(pa + i) = 1;
	}

	return 0;
}

The operation analysis is as follows:

Summary:
The type of pointer determines how much permission (several bytes can be manipulated) there is when dereferencing the pointer.

For example, the dereference of char * pointer can only access one byte, while the dereference of int * pointer can access four bytes.

3. Field pointer

Concept: a wild pointer means that the position pointed to by the pointer is unknown (random, incorrect, and not clearly limited).

3.1 cause of formation

1. Pointer not initialized

//This code is wrong
#include <stdio.h>

int main()
{
	int* p;//There is no initialization. There are random values in it

	*p = 20;//Use the random value stored in p as the address to find a space that does not belong to our current program
	        //It causes illegal access, p is the wild pointer
	        
	return 0;
}

2. Pointer cross-border access

#include <stdio.h>

int main()
{
	int arr[10] = {0};
	int i = 0;
	int* p = arr;
	
	for (i = 0; i < 11; i++)
	{
		*p = i;//When the range pointed to by the pointer exceeds the range of array arr, p is a wild pointer
		p++;
	}
	
	retuen 0;
}


3. The space pointed to by the pointer is released

int* test()
{
	int a = 10;//Local variables. When the space for storing it has been released and its address is remembered, this pointer is called a wild pointer
	return &a;//When the life cycle of a comes, the memory space is returned to the system, but the address is passed to p
}

int main()
{
	int* p = test();
	printf("%d\n", *p);//The p in this place is the wild pointer. The printed value is 10, but it doesn't mean it's right
	return 0;
}

Picture analysis:

Here we will explain it when developing dynamic memory, so let's give a brief hint.

Let's talk about other things (mainly expanding our thinking):
Why print 10 here?
The reason is that the memory space is returned to the system, but the content has not changed or been overwritten, but the last value is retained.

For example:

//Let's change the code a little
#include <stdio.h>

int* test()
{
	int a = 10;//Local variables,
	return &a;//When the life cycle of a comes, the memory space is returned to the system, but the address is passed to p
}

int main()
{
	int* p = test();
	printf("hehe\n");//Here is the so-called coverage
	printf("%d\n", *p);//p in this place is the wild pointer
	
	return 0;
}

Drawing explanation:

3.2 how to avoid wild pointer

1. Pointer initialization

int a = 10;//Explicitly initialize and determine the direction
int* p = &a;
	
int* q = NULL;//If you don't know where a pointer should be pointing, it can be initialized to NULL (NULL pointer)
//Of course, you can also int* q = 0, However, it is not easy to recognize as a null pointer
//So the essence of NULL is 0

2. Be careful that the pointer is out of range
When using the pointer, try to judge whether the pointer crosses the boundary (whether it crosses the boundary when accessing the boundary).

3. The pointer points to the space, even if it is set to NULL

4. Try to avoid returning the address of local variables
Is not a local variable that cannot be returned.

5. Check the validity of the pointer before use

#include <stdio.h>

int main()
{
	int* p = NULL;
	*p = 100;//error
	//The null pointer is referenced here
	//The null pointer is 0. 0 is also an address. The address space pointed to by 0 is not allowed
	//Null pointers cannot be dereferenced directly

	//So how
	if (p != NULL)//Proceed to the next step when the pointer is not a null pointer
	{
		//...
	}
}

be careful:
When doing projects, many bug s are caused by wild pointers, so avoid wild pointers!
There are two things that must be done: the pointer should be initialized + effective judgment

4. Pointer operation

  • Pointer + - integer
  • Pointer pointer
  • Relational operation of pointer

4.1 pointer + - integer

Pointer + integer: directly reflected in the code as follows

#include <stdio.h>
#define N_VALUES 5

int main()
{
	float values[N_VALUES];
	float* vp = NULL;
	
	for (vp = &values[0]; vp < &values[N_VALUES];)
	{
		*vp++ = 0;//The + + here means to skip a float type
	}

	return 0;
}

Drawing analysis:

Pointer integer: look at the code

#include <stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int* p = &arr[10];

	printf("%p\n", p);
	printf("%p\n", p-1);

	return 0;
}

See the address minus 4 bytes from the running result:

We won't introduce pointer + - integer too much here. Please look at the meaning of pointer type above to understand it deeply!

4.2 pointer - pointer

We can see that the title of this section is pointer pointer. Can we use pointer + pointer?
The answer is no, it's meaningless!

Then we might as well write the code directly:

#include <stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int* p = &arr[10];

	printf("%d\n", &arr[9] - &arr[0]);//Print out 9
	printf("%d\n", &arr[0] - &arr[9]);//Print out - 9

	return 0;
}

Pointer - the absolute value of the number obtained by the pointer is the number of elements between the pointer and the pointer
Note: pointer - pointer has a premise that two pointers point to the same area

Let's actually use it:

Use the above knowledge to write a function to find the string length

#include <stdio.h>

int my_strlen(char* s)
{
	char* start = s;//Represents the address of the first element
	while (*s != '\0')
	{
		s++;
	}

	return s-start;// The address of slash 0 minus the address of the first element is the length of the string
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);

	return 0;
}

4.3 pointer relation operation

The relational operation of pointers is to compare the size of pointers

Let's look at a piece of code:

for (vp = &values[N_VALUES]; vp > &values[0];)
{
	*--vp = 0;
}

Code simplification, which modifies the code as follows:

for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--)
{
	*vp = 0;
}

Which of the above two coding methods is good?

In fact, most compilers can successfully complete the task. However, we should avoid simplifying the writing method, because the C language standard does not guarantee its feasibility.

Standard provisions:

A pointer to an array element is allowed to be compared with a pointer to the memory location after the last element of the array, but it is not allowed to be compared with a pointer to the memory location before the first element.

Draw a picture to understand:

5. Relationship between pointer and array

  • An array is a continuous space with elements of the same type;
    The size of the array is related to the element type and the number of elements.

  • A pointer (variable) is a variable that places an address;
    The size of the pointer is 4 / 8 bytes.

Here I tell you: the array name is the address of the first element
So we can access the array with a pointer:

#include <stdio.h>

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

	for (i = 0; i < sz; i++)
	{
		*(p + i) = i;
		printf("%d ", *(p + i));
	}

	return 0;
}

6. Secondary pointer

First of all, let's think about the problem: the pointer variable is also a variable. If it is a variable, it has an address. Where is the address of the pointer variable stored?

Let's read a piece of code and draw a picture to explain:

#include <stdio.h>

int main()
{
	int a = 10;//The occupied space is 4 bytes
	int* p = &a;//p is the first level pointer
	int** pp = &p;//pp is the secondary pointer
	//Theoretically, you can have unlimited sets of dolls?
	return 0;
}


This is the secondary pointer.

How do we access the secondary pointer?

Write code directly and draw pictures to explain:

#include <stdio.h>

int main()
{
	int a = 10;//The occupied space is 4 bytes
	int* p = &a;//p is the first level pointer
	int** pp = &p;//pp is a two-level pointer, which can be set infinitely in theory?
   
    **pp = 20;
	printf("%d\n", a);//a here prints out 20
	
	return 0;
}


As for the secondary pointer, we can stop here. I will explain the later knowledge in the pointer blog of [advanced C language]! Please look forward to it!!!

7. Pointer array

Is a pointer array a pointer or an array?
Answer: it's an array. It's an array that holds pointers.

int* parr[5];//Array of integer pointers
char* pc[6];//Array of character pointers

Pointer array is essentially an array. Many knowledge points are the same as ordinary arrays!

So there is no too much explanation, everyone understands!

Many knowledge points about arrays are not explained here, Please look at my blog about arrays!

End of the full text

Posted by kevinbarker on Tue, 14 Sep 2021 13:22:48 -0700