An article lets you understand character pointers, array pointers, pointer arrays, array parameter passing and pointer parameter passing, function pointers

insert image description here

review

First of all, let's briefly review the basic knowledge of pointers.
The memory will be divided into individual memory units. Each memory unit has an independent number—number is also called address, and address is also called pointer in C language. The pointer (address) needs to be stored—stored in a variable, this variable is called a pointer variable
For example:

int a = 10;
int* pa = &a;

The size of the pointer is fixed at 4/8 bytes (32-bit/64-bit platform).
The address is generated on the physical wire and
the electrical signal is converted into a digital signal.
32-bit machine—32 address lines—1/0
composed of 32 0/1 The binary sequence, take this binary sequence as the address, 32 bits can store this address,
that is, it needs 4 bytes to store,
so the size of the pointer variable is 4 bytes
. Similarly, on a 64-bit machine, the size of the address It is a binary sequence composed of 64 0/1, which requires 64 bits to store, that is, 8 bytes, so the size of the pointer variable is 8 bytes

1 character pointer

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

int main()
{
    
    
 char ch = 'w';
 //ch = 'a'//这里可以理解成办事的方法有很多种,这只是其中一种
 char *pc = &ch;//pc就是字符指针
 *pc = 'w';
 return 0;
}

now have the following code

int main()
{
    
    
	char arr[] = "abcdef";
	const char* p = "abcdef";//本质上是把字符串首字符的a地址放在p当中,相当于p指向了字符串首元素a的地址//这个字符串是一个常量字符串,常量字符串不能被修改,所以我们需要加上一个const防止被修改
	return 0;
}

This is essentially to put the address of the first character a of the string in p, which is equivalent to p pointing to the address of the first element a of the string //This string is a constant string, and the constant string cannot be modified, so we need Add a const to prevent it from being modified. In addition, pay attention to the usage of const. The const is placed on the left to limit p, and the const is placed on the right to limit p.
Let's print the above code to see the effect

int main()
{
    
    
	char arr[] = "abcdef";
	const char* p = "abcdef";//本质上是把字符串首字符的a地址放在p当中,相当于p指向了字符串首元素a的地址//这个字符串是一个常量字符串,常量字符串不能被修改,所以我们需要加上一个const防止被修改
	printf("%s\n", p);
	printf("%c\n", *p);
	return 0;
}

insert image description here
insert image description here
Let’s think about a question (pay attention to combining the above knowledge of character pointers), see the following code

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

The code const char* pstr = "hello bit." is essentially to put the address of the first character of the string hello bit. into pstr. The above code means to
insert image description here
store the address of the first character h of a constant string into the pointer variable pstr
After mastering the basic knowledge of character pointers, let's look at a pen test question, see the following code

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

insert image description here
insert image description here

2 array of pointers

Integer array—an array of integers. Character
array—an array of characters. Pointer
array—an array of pointers.
Let’s review what the following pointer arrays mean.

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

Let's simulate a two-dimensional array using an array of pointers

int main(int argc, char* argv[], char* envy[])
{
    
    
	int arr1[5] = {
    
     1,2,3,4,5 };
	int arr2[5] = {
    
     2,3,4,5,6 };
	int arr3[5] = {
    
     3,4,5,6,7 };
	int* arr[3] = {
    
     arr1,arr2,arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < 5; j++)
		{
    
    
			printf("%d ", *(*(arr + i) + j));
			Sleep(1000);
		}
		printf("\n");
	}
	system("pause");
	return 0;
}

*(*(arr + i) + j) here means that the address of the first element is stored in the pointer variable arr, that is, the address of the first element of the arr1 array name, and then + traverses the two-dimensional array in turn, I A Sleep(1000) added here means to stay for 1 second to print an array.
This is not a real two-dimensional array. The real two-dimensional array is stored continuously in memory.

3 array pointer

3.1 Definition of array pointer

Array pointer
Analogy:
Integer pointer—a pointer to an integer variable, a pointer variable that stores the address of an integer variable Character
pointer—a pointer to a character variable, a pointer to a character variable that stores the address of a character variable
Array pointer—a pointer to an array, that stores
What is
the pointer variable of the address of the
array
? Array pointer
Which of the following codes is an array pointer?

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

explain

int (*p)[10];
//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指
向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。

3.2 & array name VS array name

Here we explain the understanding of the array name.
The array name is the address of the first element of the array.

int main()
{
    
    
	int arr[10] = {
    
     0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}

But the array name indicates the address of the first element, there are two exceptions
1. sizeof (array name), the array name here does not indicate the address of the first element of the array, the array name indicates the entire array, sizeof (array name) calculates the entire array Size, the unit is byte
2. &Array name, where the array name represents the entire array, &array name takes out the address of the entire array
In addition, the array name in all other places is the address of the first element of the array
There is a phenomenon here, please see the following code

int main()
{
    
    
	int arr[10] = {
    
     0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr);
	return 0;
}

The addresses printed here are all the same, but are they really the same in essence?
Let's debug the code and take a look.
insert image description here
Although the addresses we see are the same, their types are different.
Here, the type of the address arr should be int (*) [10]
just because their types are different.
Now we come to Look at the code below

int main()
{
    
    
	int arr[10] = {
    
     0 };
	printf("%p\n", arr);
	printf("%p\n", arr + 1);
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr[0] + 1);
	printf("%p\n", &arr);
	printf("%p\n", &arr + 1);
	return 0;
}

You copy this string of codes to compile and run, and you will find that the effects of adding 1 to each have different effects.
insert image description here
The reason is that different pointer types bring different effects.
For the array name
, & the array name gets the address of the array.

3.3 Use of array pointers

int main()
{
    
    
	int arr[10] = {
    
     0 };
	//数组的地址存放到数组指针变量
	//int[10]*p=&arr;//error
	int(*p)[10] = &arr;
	//int*p1=&arr;
	return 0;
}

The int*p1=&arr here may report a warning because the pointer type does not match. Above we introduced to you that the pointer type of &arr is int(*p1)[10] so how to use the array pointer
? It is generally convenient to put it on a two-dimensional array

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
    
    
 int i = 0;
 for(i=0; i<row; i++)
 {
    
    
 for(j=0; j<col; j++)
 {
    
    
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
void print_arr2(int (*arr)[5], int row, int col)
{
    
    
 int i = 0;
 for(i=0; i<row; i++)
 {
    
    
 for(j=0; j<col; j++)
 {
    
    
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
int main()
{
    
    
 int arr[3][5] = {
    
    1,2,3,4,5,6,7,8,9,10};
 print_arr1(arr, 3, 5);
 //数组名arr,表示首元素的地址
 //但是二维数组的首元素是二维数组的第一行
 //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
 //可以数组指针来接收
 print_arr2(arr, 3, 5);
 return 0;
}

Look at the code below

//二维数组传参,形参是指针的形式
void Print(int (*p)[5], int r, int c)
{
    
    
	int i = 0;
	for (i = 0; i < r; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < c; j++)
		{
    
    
			printf("%d ", *(*(p + 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 };
	//arr 是数组名,数组名表示数组首元素的地址
	Print(arr, 3, 5);
	return 0;
}

Here I will explain to you *(*p+i)+j), adding i is equivalent to getting the address of a certain row, and then adding j to traverse
each row of the two-dimensional array can be understood as an element of the two-dimensional array, each A row is also a one-dimensional array, so a two-dimensional array is actually an array of one-dimensional arrays. The array
name of a two-dimensional array is also the array name, and the array name is the address of the first element. The address of one-dimensional array—the address of the array
insert image description here
One-dimensional array is passed as a parameter, and the part of the formal parameter can be an array or a pointer
Let’s look at the following code

//void test1(int arr[5], int sz)
//{}
//void test2(int* p, int sz)
//{}
//
//int main()
//{
    
    
//	int arr[5] = { 0 };
//	test1(arr, 5);
//	test2(arr, 5);
//	return 0;
//}

The formal parameter part can be written as an array, but it is essentially a pointer, so it is recommended to use a pointer to receive
two-dimensional array parameters. The formal parameter part can be an array or a pointer

//void test3(char arr[3][5], int r, int c)
//{}
//
//void test4(char (*p)[5], int r, int c)
//{}
//int main()
//{
    
    
//	char arr[3][5] = {0};
//	test3(arr, 3, 5);
//	test4(arr, 3, 5);
//
//	return 0;
//}
//

Array pointer—is a pointer—is a pointer to an array. Pointer
array—is an array—is an array that stores pointers.
You can use the example of a good child to understand

4Array parameter passing pointer parameter passing

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

#include <stdio.h>
void test(int arr[])//ok?
{
    
    }
void test(int arr[10])//ok?
{
    
    }
void test(int *arr)//ok?
{
    
    }
void test2(int *arr[20])//ok?
{
    
    }
void test2(int **arr)//ok?
{
    
    }
int main()
{
    
    
 int arr[10] = {
    
    0};
 int *arr2[20] = {
    
    0};
 test(arr);
 test2(arr2);
}

The first one is OK, there is nothing wrong with receiving an array to pass parameters.
The second one is OK, but the number of elements is written out.
The third one is OK, and a pointer is used to receive
the fourth one. An array has 20 elements, each element It’s int*, it’s okay to use int*arr[20] to receive it
. The fifth type is OK. The address of the first-level pointer is received by a second-level pointer, so there’s nothing wrong with it.

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

In the first type of OK
parameter part, the row can be omitted, but the column cannot be omitted.
Summary: When passing parameters in a two-dimensional array, the design of the function parameter can only omit the first [] number,
because for a two-dimensional array, you don’t need to know the number How many lines, but you must know how many elements are in a line ,
so that it is convenient to calculate.
So the second type is not OK, the third type is OK
, and the fourth type, the array name is the address of the first element—the two-dimensional array is the address of a line, definitely not the address of a certain one , so the error
The fifth method does not work, because I passed the name of the array, and the formal parameter here is just an array of pointers, it must not work, either written as an array pointer or a two-dimensional array The sixth method is OK, it is an array pointer, which can point
to One line
The seventh error, the array name indicates the address of the first element, how can the address of the first line be received by the secondary pointer, it must be wrong!

4.3 First-level pointer parameter passing

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

Let's understand it by ourselves, it's relatively simple.
Let's think about a question here
. When the parameter part of a function is a first-level pointer, what parameters can the function receive?
for example

void test1(int *p)
{
    
    }
//test1函数能接收什么参数?
void test2(char* p)
{
    
    }
//test2函数能接收什么参数?

insert image description here

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

Thinking:
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;
}

insert image description here

5 function pointer

Function pointer - pointer to a function
Array pointer - pointer to an array
For an example, see the code

//int Add(int x, int y)
//{
    
    
//	return x + y;
//}
//
//int main()
//{
    
    
//	int arr[10] = {0};
//	int (*pa)[10] = &arr;
//	//printf("%p\n", &Add);
//	//printf("%p\n", Add);

The result is exactly the same, you can try it on your own compiler
The function name is the address of the function
& the function name is also the address of the function

//int Add(int x, int y)
//{
    
    
//	return x + y;
//}
//	int (*pf)(int, int) = &Add;//pf是函数指针变量
//	//int (*)(int, int) 是函数指针类型
//	return 0;
//}

Let's look at a piece of code

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

The output result
insert image description here
is shown in the following code

//int Add(int x, int y)
//{
    
    
//	return x + y;
//}
//
//int main()
//{
    
    
//	//int (*pf)(int, int) = &Add;
//	int (*pf)(int, int) = Add;
//
//	int r = Add(3, 5);
//	printf("%d\n", r);
//
//	int m = (*pf)(4, 5);
//
//	printf("%d\n", m);
//
//	return 0;
//}

Note that * must first be combined with pf to be called a pointer, and then combined with the parameter type to be called a function pointer. Let’s take a
look at the following two interesting codes.
Let’s look at the first one first.

//代码1
(* (void (*)())0 )();

Many people looked at it at first glance and I was directly confused. What is this 0? The related knowledge of a function pointer is so complicated. In fact, this line of code has its specific meaning. Let me explain to you that 0 can be defaulted
to It is an integer.
I can think of 0 as an int type, which is no different from x0012ff40. You
can also 0x0012ff40—it is an integer expressed in hexadecimal.
You can also think of this thing as an address—an address is a number—it can be an integer address— Int

for example
//void(*p)()—p is a function pointer

//void(*)() is a function pointer type.
I added a parenthesis in front of 0.
Here is the forced type conversion of 0 into the following

void(*)() is a pointer type
, so this line of code means to call the function at address 0, and convert 0 to

function pointer of void(*)() type
, and then call the function at address 0.
This uses the knowledge of function pointers. Try to understand that this line of code comes from C traps and defects. Let’s look at the
second code

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

signal is a function declaration.
The signal function has two parameters. The type of the first parameter is Int, and the type of the second parameter is void(*)(int) function pointer type. The function pointed to by
the function pointer has a parameter of type Int. The return type is void

The return type of the signal function is also a void(*)(int) function pointer type. The function pointed to by the function pointer has a parameter of type int, and the return type is void. This code is a bit complicated. We need to understand the typedef function for a little
modification
. — type renaming

//	typedef void(*pf_t)(int);
//	pf_t signal(int, pf_t);
//	void (* signal(int, void(*)(int) ) )(int);
//

Guess you like

Origin blog.csdn.net/fjj2397194209/article/details/131581908