Elementary C language - pointer

Hello, we meet again, time flies so fast, I have written so many blogs in a blink of an eye, in the next year, the editor will also study and type code seriously, we will make progress together, then today Let's start talking about our pointers. The chapter of pointers is a difficult chapter in the learning of C language. Let's not talk nonsense, let's start our study.

1. What is a pointer?
What are pointers?
Two key points for pointer understanding:

  1. A pointer is the number of the smallest unit in memory, that is, the address
  2. The pointer in the spoken language usually refers to the pointer variable, which is a variable used to store the memory address.
    Summary: The pointer is the address, and the pointer in the spoken language usually refers to the pointer variable

insert image description here
We store an address in the memory, each memory unit corresponds to a corresponding number, the unit is one byte, and our pointer is used to store the address

pointer variable

We can use & (address operator) to take out the actual address of the variable's memory, and store the address in a variable, which is a pointer variable

#include <stdio.h>
int main()
{
    
    
 int a = 10;//在内存中开辟一块空间
 int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
    //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量
中,p就是一个之指针变量。
 return 0;
}

Summary:
Pointer variables, variables used to store addresses. (The value stored in the pointer is treated as an address).
The question here is:
how big is a small unit? (1 byte)
How is it addressed?
After careful calculation and weighing, we found that it is more appropriate to assign a byte to a corresponding address.
For a 32-bit machine, assuming that there are 32 address lines, then assuming that each address line generates a high level (high voltage) and a low level (low voltage) when addressing
is (1 or 0);
then 32 What is the address generated by the address line?

We can understand it this way, if there are 32 address lines, each of our address lines can be represented by 0 and 1, then we
can write it as
00000000000000000000000000000000000000000000000000000000000000000000000000000
0000010
1000000000000000000000000000000
10000000000000000000000000000001
11111111111111111111111111111111111


Going on like this is equivalent to the 32 storage methods of 2, how much is the 32 times of 2
(2^32Byte == 2^32/1024KB == 2 32/1024/1024MB==2 32/1024/1024/1024GB == 4GB) 4G free for addressing.

Here we understand:
on a 32-bit machine, the address is a binary sequence composed of 32 0s or 1s, and the address must be stored in 4 bytes, so the size of a
pointer variable should be 4 bytes .
Then if on a 64-bit machine, if there are 64 address lines, the size of a pointer variable is 8 bytes to store an address.
2. Pointers and pointer types

We all know that variables have different types, integer, floating point, etc. Does the pointer have a type?

the answer is yes

int num = 10;
p = &num;

When we see the above code, take out the address of num and store it in p, then everyone think about what our p pointer type should be.

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

The pointer of char* type is used to store the address of char type variable.
The short* type pointer is used to store the address of the short type variable.
The pointer of type int* is used to store the address of variable of type int.

Seeing here, do we have any doubts, that is, we define the type of pointer variable, although its size is the same, but have we ever thought about why we define it this way?

The answer is that the pointer type determines how much to add 1 to. It is like a person with long legs and a person with short legs. Everyone is one step, but the step length is different. This is the function of our pointer variable type. We use code to make everyone better understand

2.1 pointer ± integer

#include <stdio.h>
//演示实例
int main()
{
    
    
 int n = 10;
 char *pc = (char*)&n;
 int *pi = &n;
 
 printf("%p\n", &n);
 printf("%p\n", pc);
 printf("%p\n", pc+1);
 printf("%p\n", pi);
 printf("%p\n", pi+1);
 return  0;
}

insert image description here

The first &n takes out the size of the entire integer, although its address is the same as others, but it is the entire variable of variable n, occupying four bytes, so it adds 1 to skip four addresses

The second pc is the address stored in the first byte of the four bytes of the integer variable, so it adds 1 to skip an address
pi is also the address of the entire n variable, and we use an integer pointer to receive , then what it skips by adding 1 is also four bytes in size, and one byte is an address

Summary:
The type of pointer determines how much authority (how many bytes can be manipulated) when dereferencing the pointer.
For example: dereferencing a char* pointer can only access one byte, while dereferencing an int* pointer can access four bytes.

3. Wild Pointer

Concept: A wild pointer means that the location pointed to by the pointer is unknown (random, incorrect, and without clear restrictions)

3.1 Causes of wild pointers

  1. pointer is not initialized
#include <stdio.h>
int main()
{
    
     
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}

We did not define the type of the *p pointer variable

  • 2 pointer out of bounds access
#include <stdio.h>
int main()
{
    
    
    int arr[10] = {
    
    0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
    
    
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}

Our array only has ten elements, but the scope of our access is beyond the scope of the array,
and the content of the address behind the dereference here is the content of the address behind the address of our array, which may be a random number

Here I use a metaphor to describe the wild pointer. The wild pointer is actually a vicious dog. If it is not used rationally, it will cause irreversible results. But we only need to tie him with a rope so that he will be fine, and we Here, NULL (null pointer) is usually used as a string.

  • How to avoid wild pointers
  1. pointer initialization
  2. Careful pointer out of bounds
  3. The pointer points to the space to release even if it is set to NULL
  4. Avoid returning the address of a local variable
  5. Check the validity of the pointer before using it
#include<stdio.h>
int* test()
{
    
    
	int a = 10;
	return &a;
}
int main()
{
    
    
	int* p = test();
	printf("%p", p);

	return 0;
}
#include<stdio.h>
int* test()
{
    
    
	int a = 10;
	return &a;
}
int main()
{
    
    
	int* p = test();
	*p = 100;

	return 0;
}

We also want to avoid the above code, because local variables are automatically destroyed when they go out of scope, but our address will not be destroyed at the end. Here, when we talk about function stack frames later, I will give you a careful analysis

  1. Check the validity of the pointer before using it
#include <stdio.h>
int main()
{
    
    
    int *p = NULL;
    //....
    int a = 10;
    p = &a;
    if(p != NULL)
   {
    
    
        *p = 20;
   }
    return 0;
}

4.1 Pointer ± Integer

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
    
    
     *vp++ = 0;
}

Change the contents of the floating-point vp address to 0, and change five addresses.
Because vp is a pointer of float type, the ±. movement of the pointer of float type is float units

4.2 Pointer-Pointer
We have used the strlen function to find the length of a string before, and now we can also use a pointer to find the length of a string

#include<stdio.h>
#include<string.h>
int main()
{
    
    
	char str[] = "abcdef";
	int len = strlen(str);
	printf("%d ", len);
	return 0;
}

This is the length of the string we use the strlen function to find, now we use the pointer to find, define a function my_strlen to find the length of the string

#include<stdio.h>
int my_strlen(char* str)
{
    
    
	int count = 0;
	while (*str != '\0')
	{
    
    
		count++;
		str++;
	}
	return count;
}
int main()
{
    
    

	char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d", len);
	return 0;
}

Of course, we have also used the idea of ​​function recursion to write code before, and here we will bring you back to recall

#include<stdio.h>
int my_strlen(char* str)
{
    
    
	if (*str != '\0')
	{
    
    
		return 1 + my_strlen(str+1);
	}
}
int main()
{
    
    

	char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d", len);
	return 0;
}

We now have at least three ways to find the length of a string

4.3 Relational operations on pointers

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

In fact, the task can be successfully completed on most compilers, but we should still avoid writing this way, because the standard does not guarantee that it will work.

Standard: A pointer to an array element is allowed to compare with a pointer to a memory location after the last element of the array, but not with a pointer to a memory location before the first element.

5. Pointers and arrays

Let's take a look at the following string of code

#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;
}

insert image description here

It can be seen that their address content is the same, and we have always emphasized in the previous study that the array name is the address of the first element, except for two special exceptions (sizeof) (&), in any other case the array name is the address of the first element

Since the array name can be stored as an address in a pointer, it becomes possible for us to use a pointer to access one.

#include<stdio.h>
int main()
{
    
    
	int arr[] = {
    
     1,2,3,4,5,6,7,8,9,0 };
	int* p = arr;//存放首元素地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
    
    
		printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p + i);
	}
	return 0;
}

insert image description here
So you can use a pointer to access the array address

So p+i actually calculates the address of the subscript i of the array arr.
6. Secondary pointer

A pointer variable is also a variable, and a variable has an address. Where is the address of the pointer variable stored?

insert image description here
*ppa finds pa by dereferencing the address in ppa, and *ppa actually accesses pa.
int b = 20;
*ppa = &b;//equivalent to pa = &b;

**ppa first finds pa through *ppa, and then dereferences pa: *pa, then finds a

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

7. Array of pointers

Is an array of pointers a pointer or an array?
Answer: an array. is an array of pointers.
Arrays We already know integer arrays, character arrays.

insert image description here

The above should be int arr[4]

insert image description here
So what is our pointer array like?
insert image description here
The pointer is also finished, and I will learn more about pointers later, because pointers are really important. If you know C language, you must know pointers. This is the end of our sharing today, thank you Everyone has to support, your support is my motivation, bye

Guess you like

Origin blog.csdn.net/2301_76895050/article/details/131648435