C language - pointer advanced

insert image description here
Key points of this chapter

  1. character pointer
  2. array pointer
  3. array of pointers
  4. Array parameter passing and pointer parameter passing
  5. function pointer
  6. array of function pointers
  7. pointer to array of function pointers
  8. Callback
  9. Analysis of pointer and array interview questions

1. Character pointer

In the pointer type, we know that there is a pointer type that is a character pointer char*

int main()
{
    
    
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}

Another way is

int main()
{
    
    
const char* pstr = "hello bit.";//这里是把一个字符串放到pstr指针变量里了吗?
printf("%s\n", pstr);
return 0;
}

This will print the entire string completely.
But instead of putting the entire string into pstr, we put the address of the first element of the string.

The above code means to store the address of the first character h of a constant character string into the pointer variable pstr.

Take a look at a written test below.

#include <stdio.h>
int main()
{
    
    
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char *str3 = "hello bit.";
const char *str4 = "hello bit.";
if(str1 ==str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 ==str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}

What is the result of our running, let us look at the results given by the compiler.
insert image description here
The reason here is that our first one is an array, the creation of the array will open up space, and two different spaces will be opened up, so their addresses must be different, and why the second one is the same, first of all, ours is a constant hello bit.character String, only space is opened up for constant strings, so str3 and str4 point to the same space, so the address is the same, our question is actually to compare whether their addresses are the same. We can also debug to see the result we want.
insert image description here
In this way, it is obvious that we reallocate space when we give the array.

Here str3 and str4 point to the same constant string. C/C++ will store constant strings in a separate memory area, as
several pointers. When pointing to the same string, they will actually point to the same block of memory. But when using the same constant string to initialize
different arrays, different memory blocks will be opened up. So str1 is different from str2 and str3 is different from str4.

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

insert image description here
In fact, it has the same effect as the above code, so everyone may understand it easily.
2. Array of pointers

When we are learning this, people often get confused, first character array, second word pointer array, and array pointer. In fact, we can solve many problems as long as we grasp what it is, such as array pointer, which points to the array. Pointers, on the contrary, an array of pointers is an array of pointers.

In the chapter "Pointers", we also learned about pointer arrays, which are an array of pointers.
Here we review again, what does the following pointer array mean?

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

3. Array pointer
Integer pointer: int * pint; can point to an integer data pointer.
Floating-point pointer: float * pf; A pointer that can point to floating-point data.
The array pointer should be: a pointer that can point to an array.

int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?

First of all, p1 is first connected with the brackets, and then connected with the and, which means the pointer array, and the number of elements is 10.
p2 is the first
contact, and then contact with [], that is, it represents the pointer to the array.

//Note here: the priority of [] is higher than that of number, so () must be added to ensure that p is combined first

3.2 & array name VS array name
We have actually talked about this content several times before, the array name is the address of the first element, except for two special cases, one is & and the other is sizeof, these two represent the entire array.

#include <stdio.h>
int main()
{
    
    
int arr[10] = {
    
    0};
printf("%p\n", arr);
printf("%p\n", &arr);
return 0;
}

Look at the example above.
insert image description here
We can see that although their content is the same, the effect is different. Let's take a look at their +1 results.
insert image description here
Obviously different, this is because taking out the address + 1 is to skip the entire array.

In fact: &arr represents the address of the array, not the address of the first element of the array. (Experience in detail)
The type of &arr in this example is: int(*)[10], which is an array pointer type
array address + 1, skipping the size of the entire array, so the difference between &arr+1 and &arr The value is (28 in hexadecimal) 40, just the entire array.

3.3 The use of array pointer
How is the array pointer used?
Since the array pointer points to an array, the address of the array should be stored in the array pointer.

#include <stdio.h>
int main()
{
    
    
int arr[10] = {
    
    1,2,3,4,5,6,7,8,9,0};
int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
//但是我们一般很少这样写代码
return 0;
}

We use the array pointer to print the array.

#include<stdio.h>
void print_arr(int(*arr)[5], int row, int col)
{
    
    
	int i = 0;
	for (i = 0; i < row; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < col; j++)
		{
    
    
			printf("%d ", arr[i][j]);
			
		}
		printf("\n");
	}
}
int main()
{
    
    
	int arr[3][5] = {
    
     {
    
    1,2,3,4,5},{
    
    2,3,4,5,6},{
    
    3,4,5,6,7} };
	print_arr(arr, 3, 5);
	return 0;
}

insert image description here
After learning pointer array and array pointer, let's review and see the meaning of the following code:

int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

The first is to store an array of int type.
The second is to store an array of ints, an array of pointers.
The third is our array pointer.
The fourth parr3 is first combined with [10], and then
combined with the sum, so parr3 means the array pointer pointing to the array

Draw a picture for better understanding

insert image description here
4. Array parameters, pointer parameters

When writing code, it is inevitable to pass [array] or [pointer] to the function. How should the parameters of the function be designed?

4.1 One-dimensional array parameter passing
insert image description here
Then let’s see that the results of the above parameter passing are correct.
From top to bottom, the first array parameter is received in the form of an array. It is definitely right. In fact, its essence is int* arr.
Next A parameter in [] is actually meaningless, and can even be scribbled, so it is also true,
the third is the essence of what we say i.
Then let's take a look at the following pointer array parameter passing.
The fourth is also right, we receive it in the form of an array.
The fifth one is also correct. We think that the latter * means that it is a pointer, and the content pointed to is an int . It can also be considered that arr belongs to int *
4.2 Two-dimensional array parameter passing

void test(int arr[3][5])//ok?
{
    
    }
void test(int arr[][])//ok?
{
    
    }
void test(int arr[][5])//ok?
{
    
    }
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//ok?
{
    
    }
void test(int* arr[5])//ok?
{
    
    }
void test(int (*arr)[5])//ok?
{
    
    }
void test(int **arr)//ok?
{
    
    }
int main()
{
    
    
int arr[3][5] = {
    
    0};
test(arr);
}

Then let's take a look at this two-dimensional array parameter passing.
I wrote the code directly, so that it looks like one-to-one correspondence

void test(int arr[3][5])//ok?二维数组传参用二维数组接收,肯定没问题
{
    
    }
void test(int arr[][])//ok?这个不行,因为我们后面的列必须有参数
{
    
    }
void test(int arr[][5])//ok?可以
{
    
    }
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//ok?不行
{
    
    }
void test(int* arr[5])//ok?不行
{
    
    }
void test(int (*arr)[5])//ok?可以
{
    
    }
void test(int **arr)//ok?不行
{
    
    }
int main()
{
    
    
int arr[3][5] = {
    
    0};
test(arr);
}

We talked about the parameter passing of two-dimensional arrays above, so it is faster to judge

4.3
In fact, for this problem, we only need to master a trick. The first-level pointer is passed by the first-level pointer to receive, and the second-level pointer is passed by the second-level pointer to receive, but the address of the first-level pointer must be used. Secondary pointer to receive.

#include <stdio.h>
void print(int *p, int sz)
{
    
    
int i = 0;
for(i=0; i<sz; i++)
{
    
    
printf("%d\n", *(p+i));
}
}
int main()
{
    
    
int arr[10] = {
    
    1,2,3,4,5,6,7,8,9};
int *p = arr;
int sz = sizeof(arr)/sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}

Think about when the parameter part of a function is a first-level pointer, what parameters can the function receive?

void test1(int *p)
{
    
    }
//test1函数能接收什么参数?
void test2(char* p)
{
    
    }
//test2函数能接收什么参数?
void test1(int *p)
{
    
    }
//test1函数能接收什么参数?
可以是一维数组的数组名,可以是一个常量的地址,可以是一级指针
void test2(char* p)
{
    
    }
//test2函数能接收什么参数?
字符指针,字符数组的数组名,一个字符的地址

4.4 Second-level pointer parameter passing

#include <stdio.h>
void test(int** ptr)
{
    
    
printf("num = %d\n", **ptr);
}
int main()
{
    
    
int n = 10;
int*p = &n;
int **pp = &p;
test(pp);
test(&p);
return 0;
}

When the parameter of the function is a secondary pointer, what parameters can it receive?

void test(char **p)
{
    
     }
int main()
{
    
    
char c = 'b';
char*pc = &c;
char**ppc = &pc;
char* arr[10];
test(&pc);
test(ppc);
test(arr);//Ok?
return 0;
}

5. Function pointers

Let's take a look at the code below

#include <stdio.h>
void test()
{
    
    
printf("hehe\n");
}
int main()
{
    
    
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}

Let's see what the address outputs.
insert image description here
In fact, the address is the same. Our function adding and fetching the address is actually the same as not adding it. They are both correct. The
output is two addresses, and these two addresses are the addresses of the test function.
So how do we save the address of our function if we want to save it?
Let's look at the code below

void test()
{
    
    
printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();

pfun1 can be stored. pfun1 is first combined with *, indicating that pfun1 is a pointer, and the pointer points to a function, the pointed function has no parameters
, and the return value type is void.

In fact, function pointers are very similar to our array pointers. Let’s look at two particularly interesting codes, which are a bit difficult but interesting.
insert image description here

//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);

Then let's look at the first code first, and give the conclusion first. A function pointer is given at the address of 0. There is no return type and no parameters.
We have curly braces before 0. This is obviously a forced type conversion. Put a at the address of 0 The type of function pointer, and then call this function

The next one is the signal pointer.
Let's split signal(int, void( )(int)), first look at this, it is a function, the first parameter of the function is int and the second parameter is a function pointer, the type is void( )(int ), Then there is a * outside the signal, which means it is a pointer, the return is void and the parameter is int, which is actually a function pointer.

typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);

It can also be written like this.
That's all for today's sharing, see you next time! ! ! !

Guess you like

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