Pointer knowledge point notes

What is a pointer?

A pointer is an object in a programming language. Using an address, its value can point to a value stored in another place in the computer memory.

Generally speaking, pointers are addresses. Pointer variables are variables (variables used to store addresses).
Variables have different types, integer and floating point. Pointers also have types.

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

char *The type pointer stores charthe address of the type variable; the
int *type pointer stores intthe address of the type variable.

 
1. Pointer +-integer, dereference:

#include <stdio.h>

int main()
{
	int n = 10;
	char *pc = (char *)&n;
	int *pi = &n;

	printf("%p\n", &n); //n的地址
	printf("%p\n", pc);//pc里面放的n的地址
	printf("%p\n", pc+1);//pc+1,实际是加上自己类型的大小
	printf("%p\n", pi);//pi里面放的n的地址
	printf("%p\n", pi+1);//pi+1,实际是加上自己类型的大小
	return 0;
}

result:
Insert picture description here

Dereference this piece to see this piece of code:

	int n = 0x11223344;
	char *pc = (char *)&n;
	int *pi = &n;
	*pc = 0;
	*pi = 0;

When the initialization statement is executed, the memory is like this: After Insert picture description here
execution *pc=0, the memory has changed:
Insert picture description here
pcthe first address pointing to n has changed.
After execution pi:
Insert picture description here
pithe address pointing to n has been changed (cleared to 0).
Why is this so?
Because the type determines how many bytes can be accessed, the char*type can only access one byte. int*The type can access 4 bytes.

 
 
to sum up:

  1. +1 to the pointer, it looks like +1, which is actually adding the size of the type pointed to by the pointer ;
  2. Dereference the pointer (without forced conversion), representing the variable pointed to by the pointer (target).
  3. Pointer variables are also variables, and pointer variables must have space, content, and address (the pointer itself also has an address).
  4. When a pointer performs dereference access, its own type determines how many bytes can be accessed.

 
 
 
2. Wild pointer: Wild pointer means that the position pointed to by the pointer is unknowable (random, incorrect, and not clearly restricted).

Two reasons for the formation of wild pointers:

  1. Pointer is not initialized
	int *p;//指针变量未初始化,默认为随机值
	*p = 20;
  1. Pointer out of bounds access
	int arr[10] = { 0 };
	int *p = arr;
	int i = 0;
	for (i = 0; i <= 11; i++)
	{
		*(p++) = i;//在这里,指针指向已经越界了,超出了arr的范围,p就是野指针
	}

How to avoid wild pointers:

  1. Pointer initialization (when the pointer is defined, if you don't know who it points to, you can directly point to NULL)
  2. Note that the pointer is out of range
  3. The pointer points to the space when released and set to NULL
  4. Check the validity of the pointer before use

 
 
 
3. Pointer operations

  1. Pointer +-Integer (here is consistent with the second section above)
  2. Pointer-pointer
int my_strlen(char *arr)
{
	char *p = arr;
	while (*p != NULL)
	{
		p++;
	}
	return p - arr;
}

The number of elements in the string can be calculated by pointer-pointer. If you want to find the number of elements experienced by an array or string, you can use the pointer-pointer method.
to sum up:

1. Pointer-Pointer represents: the number of "elements" experienced between two pointers. (Not necessarily a number of 1 byte)
2. Subtracting two pointers must be done. The pointer types are consistent.
3. Subtract two pointers. It is generally recommended that two pointers point to the same block of memory.

  1. Pointer relational operations
①:
#define N 5
	float values[5];
	float *p = NULL;
	for (p = &values[N]; p > &values[0];)
	{
		*--p = 0;
	}
②:
#define N 5
	float values[5];
	float *p = NULL;
	for (p = &values[N-1]; p >= &values[0];p--)
	{
		*p = 0;
	}

In the VS environment, both schemes can run, but the second scheme should be avoided as much as possible. Because the standard does not guarantee that the second is feasible.

standard regulation:

Allowing a pointer pointing to the array element with the array of points the last memory location behind that element comparison of a pointer, but does not allow the points to that memory location before the first element is compared to the pointer.

 
 
 
4. Pointers and arrays : There is no relationship between the two.

  1. Pointers and arrays do not matter in type, they are two different types.
  2. When accessing array elements, there is a certain similarity.

In most cases, the array name represents the address of the first element of the array.

Second-level pointer: the address where the first-level pointer is stored. (The pointer itself also contains the address)

Pointer array: It is an array, an array used to store pointers. Such as:int *arr[5];

Array pointer: is a pointer, a pointer to an array. Such as:int (*arr)[5];

In secondary pointers, we often use keywords constto modify variables so that the pointer's point and content cannot be changed. Exercise:

	int a = 20;
	int *p = &a;//p指向a,对p解引用,就是a值
	int **q = &p;//q指向p,一次解引用,为p=&a,二次解引用,为a的值


	const int *p = &a;//p的内容可以更改,p的指向不能更改。不能通过解引用的方式对a值进行更改,即*p = 5,是错误的
	int const *p = &a;//同上
	const int *const p = &a;//p的内容和p的指向都不能更改。


	const int **q = &p;//q的内容和指向可以更改,*q的指向(**q)不能更改
	int const **q = &p;//同上
	int *const *q = &p;//q的内容可以更改,q的指向不能更改(*q的内容不能更改)。*q的指向(**q)可以更改
	int **const q = &p;//q的内容不能更改,q的指向(*q)可以更改,*q的指向(**q)可以更改
	int *const *const q = &p;//q的内容和指向(*q)都不能更改,*q的指向(**q)可以更改
	int const *const *q = &p;//q的内容可以更改,q的指向(*q)不能更改,*q的指向(**q)不可以更改
	int const * const *const q = &p;//q的内容和指向(*q)都不能更改,*q的指向(**q)不可以更改

 
 
 
 
 
Character pointer:char *

Two usages:

  1. Directly point to the character
  2. Point to a string (C has no string type, but a string)

const char *s
char arr[]

char *s="hello world!"It puts “hello world!”the first address of the string in the character pointer s. Generally add in front to constindicate that the string is not allowed to be modified.

	char str1[] = "hello world!";
	char str2[] = "hello world!";
	char *str3 = "hello world!";
	char *str4 = "hello world!";
	if (str1 == str2)
	{
		printf("1 and 2 are same");
	}
	else
	{
		printf("1 and 2 are not same");
	}
	if (str3 == str4)
	{
		printf("3 and 4 are same");
	}
	else
	{
		printf("3 and 4 are not same");
	}

In this example, str1and str2are different variables, opening up different address spaces.
str3And str4the address is the same. Because "hello world!"there is a character in constant area, it will only save a copy, it can be a read-only, so *str3and *str4as long as it points to the line.

 
 
& Array name and array name:
When the pair is output, their values ​​are the same, but their meanings and types are different.
Array name: the address of the first element of the array.
&Array name: Take the address of the entire array, but when outputting, the address of the first element is output.

Understanding of array types: not just look at the previous type, but also look at the number of calibration elements in [].

	int arr[10];
	int arr1[10];
	int arr2[9];

The first two types are the same, and the third and the first two types are different.

 
 
The use of array pointers : int (*p)[5]
When passing parameters of a two-dimensional array, it is convenient to reduce the dimensionality and reduce the dimensionality to a one-dimensional array pointer.

void print_arr(int (*arr)[5], int row, int col)
{
	int i = 0;
	for (; i < row; i++)
	{
		int j = 0;
		for (; j < col; j++)
		{
			//printf("%d  ", arr[i][j]);//1
			printf("%d   ", *(*(arr + i) + j));//2
		}
	}
}
int main()
{
	int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10,15 };
	print_arr(arr, 3, 5);
	return 0;
}

The second method means: arr+1point to the next one-dimensional array and dereference it, which means that the current one-dimensional array +jis the element in the current array 第j个.

 
 
Array parameter transfer should pay attention to whether the type can transfer parameters, and at the same time, the number of arrays cannot be omitted in a one-dimensional array. In a two-dimensional array, the number of the second dimension cannot be omitted.

Pointer transfer parameters:

  1. One-dimensional pointer transfer
void print(int *p, int size)
{
	int i = 0;
	for (; i < size; i++)
	{
		printf("%d  ", p[i]);
	}
}
int main()
{
	int arr[11] = { 1,2,3,4,5,6,7,8,9,10,11 };
	int *p = arr;
	print(p, 11);
	return 0;
}

Pointers are also variables. When passing parameters, formal parameter instantiations must also be performed, and pointers must also form temporary variables. However, the biggest feature of pointers is that the contents of the temporary variables formed are the same as those of the passed pointer. It is decided that in the above code, the targets pointed to by the two pointers are the same. The above two Ps are not the same, but point to the same goal.

What parameters can be accepted when the parameter of a function is a first-level pointer?

One-dimensional array: int arr[] test(arr)
first-level pointer int *p=xxx test§
specific variables int a=10 test(&a)

  1. Second-level pointer transfer

When the function parameter is a secondary pointer, what parameters can be accepted?

Secondary pointer: int **q test(q)
Primary pointer: int *q test(&q)
pointer array: int *q[10] test[q]

 
 
Function pointer : A function is essentially a code block, and the code essentially contains multiple sets of codes, which determines that it will contain an address sequence.
Function name (only), the code is the starting address of the code block.

void print(int *p, int size)
{
	int i = 0;
	for (; i < size; i++)
	{
		printf("%d  ", p[i]);
	}
}

printf("%p\n", print);
printf("%p\n", &print);

The output address of the function is the same as the address of the & function.
How to save the address of a function?

Use function pointer: void (*p)();

 
 
Function pointer array :int (*p[5])();

Store the address of the function in an array, then this array is called an array of function pointers.

One use of the function pointer array is the transfer table : for example, in the realization of the calculator function

void menu()
{
	printf("############################################\n");
	printf("######       1.add           2.sub    ######\n");
	printf("######       3.mul           4.div    ######\n");
	printf("######       0.exit                   ######\n");
}
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mul(int x, int y)
{
	return x * y;
}
int div(int x, int y)
{
	if (0 == y)
	{
		return 0;
	}
	return x / y;
}

int main()
{
	int choice = 1;
	menu();
	printf("请做出你的选择:>");
	scanf("%d", &choice);
	int(*p[5])(int x, int y) = {0, add,sub,mul,div };//函数指针数组,可以很方便的实现许多相同参数的函数的调用,转移表
	while (choice)
	{
		int x = 0;
		int y = 0;
		printf("请输入两个数:>");
		scanf("%d %d", &x, &y);
		int ret = (*p[choice])(x, y);
		printf("%d\n", ret);
		menu();
		printf("请做出你的选择:>");
		scanf("%d", &choice);
	}
	return 0;
}

 
 
Pointer to an array of function pointers

Function pointer: int (*p)();
Function pointer array: int ( p[5])();
Pointer to function pointer array: int (
(*p)[5])();

 
 
Callback function: A function called through a function pointer. If the address of this function is passed as a parameter of another function, when the pointer is used to call the function pointed to, this is a callback function. The callback function is not called directly by the implementer of the function, but is called by another party when a specific event or condition occurs, and is used to respond to the event or condition.

You go to a store to buy something, and the thing you want is out of stock, so you leave your phone number at the clerk, and after a few days the store is in stock, the clerk calls you, and then you receive the call Then I went to the store to pick up the goods. In this example, your phone number is called the callback function, and if you leave the call to the clerk, it’s called the registration callback function. Later, when the store becomes available, it is called a callback-related event. The clerk calls you called the callback function. You go to the store to pick up the goods is called responding to a callback event. --By Chang Xiling

The callback function simulates the realization of qsort (bubble sort method):

The qsort function is in the C function library, which can compare any of the same types (char int double float) and sort them

int int_cmp(void *s, void *p)//回调函数
{
	int *s1 = (int *)s;
	int *p1 = (int *)p;
	return *s1-*p1;
}
void swap(void *s, void *p, int size)
{
	int i = 0;
	char *s1 = (char *)s;
	char *p1 = (char *)p;
	for (; i < size; i++)
	{
		s1[i] ^= p1[i];
		p1[i] ^= s1[i];
		s1[i] ^= p1[i];
	}
}
void my_qsort(void *base, int num, int size, int (*cmp)(void *, void *))//实现调用回调函数的函数
{
	int i = 0;
	int j = 0;
	for (; i < num - 1 ; i++)
	{
		int flag = 1;
		for (j = 0; j < num - i - 1; j++)
		{
			if (cmp((char *)base + j * size, (char *)base + (j + 1) * size) > 0)
			{
				flag = 0;
				swap((char *)base + j * size, (char *)base + size * (j + 1),size);
			}
		}
		if (1 == flag)
		{
			break;
		}
	}
}
int main()
{
	int arr[] = { 5,7,8,1,5,4,1,6,3,2 };
	int num = sizeof(arr) / sizeof(arr[0]);
	my_qsort(arr, num, sizeof(int), int_cmp);
	for (int i = 0; i < num; i++)
	{
		printf("%d  ", arr[i]);
	}
	printf("\n");
	return 0;
}

 
 
 
 
 
Some pointers and array exercises:

	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a+0));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a+1));
	printf("%d\n", sizeof(a[1]));
	printf("%d\n", sizeof(&a));
	printf("%d\n", sizeof(*&a));
	printf("%d\n", sizeof(&a+1));
	printf("%d\n", sizeof(&a[0]));
	printf("%d\n", sizeof(&a[0]+1));

sizeof(a), which is the byte size of the entire array, so it is 16
sizeof(a+0), a is the address of the first element, plus 0, still the address of the 0th element, the size of the address (pointer) is 4
sizeof( a), a is the address of the first element, dereference a, it is 1, the byte size is 4
sizeof(a + 1);//a is the address of the first element, plus 1, it is the next element (2 ), the address (pointer) size is 4
sizeof(a[1]);//a[1]=2, and the byte size is 4
sizeof(&a);//&a, take the address of the entire array, namely The address of the array, the size of the address (pointer) is 4
sizeof(
&a);//Dereference the &a, dereference the address of the array, must be an array, the size is 16
sizeof(&a+1), &a is to take the entire array The address, after adding +1, points to the next position of the last element. Is 4
sizeof(&a[0]);//a[0]=1, takes the address for it, and the size is 4
sizeof(&a[0] + 1);//a[0]=1, takes the address for it , Plus 1 to take the address of the next element (2), the size of the address (pointer) is 4

result:
Insert picture description here

	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));//数组的大小为6
	printf("%d\n", sizeof(arr+0));//第0个元素(a)的地址,4
	printf("%d\n", sizeof(*arr));//第0个元素(a)解引用,大小为1
	printf("%d\n", sizeof(arr[1]));//第1个元素(b)解引用,大小为1
	printf("%d\n", sizeof(&arr));//对整个数组取地址,数组的地址,地址(指针)大小为4
	printf("%d\n", sizeof(&arr+1));//对整个数组取地址,数组的地址,再加1,指向数组最后一个元素的下一位置,地址(指针)大小为4
	printf("%d\n", sizeof(&arr[0]+1));//对第0个元素取地址,再加1,为b元素的地址,地址(指针)大小为4

result:
Insert picture description here

	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));//数组里面无‘\0’,随机值
	printf("%d\n", strlen(arr+0));//随机值
	//printf("%d\n", strlen(*arr));//传参错误,类型不匹配
	//printf("%d\n", strlen(arr[1]));//传参错误,类型不匹配
	printf("%d\n", strlen(&arr));//随机值,&arr是数组的地址,数组的地址char (*p)[6],告警,类型不匹配
	printf("%d\n", strlen(&arr+1));//随机值,数组的地址char (*p)[6],告警,类型不匹配
	printf("%d\n", strlen(&arr[0]+1));//随机值

Here, why does a parameter transfer error occur?

strlen定义为:size_t strlen(const char *str);

The incoming must be an address, so the above 34 types do not match, resulting in an error.
5: &arr is the address of the array, the address of the array should use the array pointer char (*p)[6], but it is the same as the starting address of the array &arr[0], the value is the same, the meaning is different, so it is passed to strlen When, an implicit type conversion occurs, and it is converted to a character pointer, so you can finally get a random value
6: &arr+1, which is equivalent to &arr[6], the type does not match, char (*p)[6], also happens Implicit type conversion.
result:
Insert picture description here

	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//字符串,有'\0',大小为7
	printf("%d\n", sizeof(arr+0));//arr+0,为首元素的地址,地址(指针)大小为4
	printf("%d\n", sizeof(*arr));//首元素的字节大小1
	printf("%d\n", sizeof(arr[1]));//第一个元素的字节大小1
	printf("%d\n", sizeof(&arr));//数组的地址,地址(指针)大小为4
	printf("%d\n", sizeof(&arr+1));//数组的地址+1,数组末下一个地址,地址(指针)大小为4
	printf("%d\n", sizeof(&arr[0]+1));//第1个元素的地址(b),地址(指针)大小为4

result:
Insert picture description here

	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//字符串长度6
	printf("%d\n", strlen(arr+0));//传入首元素的地址,字符串长度6
	//printf("%d\n", strlen(*arr));//传参错误
	//printf("%d\n", strlen(arr[1]));//传参错误
	printf("%d\n", strlen(&arr));//结果为6,但会有告警,类型不匹配,char(*p)[7]
	printf("%d\n", strlen(&arr+1));//随机值,有告警,类型不匹配,char(*p)[7]
	printf("%d\n", strlen(&arr[0]+1));//5

result:
Insert picture description here

	char *p = "abcdef";
	printf("%d\n", sizeof(p));//p存放的地址,大小为4
	printf("%d\n", sizeof(p+1));//p+1为b的地址,大小为4
	printf("%d\n", sizeof(*p));//char *解引用,为char,大小为1
	printf("%d\n", sizeof(p[0]));//p[0]='a',大小为1
	printf("%d\n", sizeof(&p));//&p,p本身的地址,大小为4
	printf("%d\n", sizeof(&p+1));//&p+1,为地址,大小为4
	printf("%d\n", sizeof(&p[0]+1)); //&p[0] + 1,‘b’的地址,大小为4

result:
Insert picture description here

	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//4*3*4=48,字节大小为48
	printf("%d\n", sizeof(a[0][0]));//第0个数组,第0个元素,int型,大小为4个字节
	printf("%d\n", sizeof(a[0]));//第0个数组,里面有4个元素,大小为16
	printf("%d\n", sizeof(a[0]+1));//第0个数组,第一个元素,大小为4
	printf("%d\n", sizeof(*(a[0]+1)));//第0个数组,第一个元素解引用,大小为4
	printf("%d\n", sizeof(a+1));//第一个数组的地址,大小为4
	printf("%d\n", sizeof(*(a+1)));//第一个数组的地址,解引用,为第一个数组,大小为16
	printf("%d\n", sizeof(&a[0]+1));//第0个数组的地址+1,为第1个数组的地址,大小为4
	printf("%d\n", sizeof(*(&a[0]+1)));//第0个数组的地址+1,为第1个数组的地址,解引用大小为16
	printf("%d\n", sizeof(*a));//首元素的地址,解引用,为16
	printf("%d\n", sizeof(a[3]));//16,不会报错,含义一致,但不能写入

result:
Insert picture description here

 
 
 
Comprehensive questions:

int main()
{
	int a[5] = { 1,2,3,4,5 };
	int *ptr = (int *)(&a + 1);
	printf("%d %d\n", *(a + 1), *(ptr - 1));
	return 0;
}

&a, is the address of the entire array, +1, points to the next address of the last element of the array.
*(a+1), a is the address of the first element, plus 1, it is the address of the first element, dereference is 2
*(ptr-1), is the address of the last element of the array, dereference is 5
Insert picture description here
2.

struct Test
{
	int num;
	char *name;
	short sdate;
	char cha[2];
	short sba[4];
}*p;
int main()
{
	p = 0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p+0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

The size of this structure is 20 bytes.
p + 0x1, actually adding the size of its own type, 20 bytes, it is 0x100014
(unsigned long)p+0x1, p is forcibly converted to an unsigned long integer, which is an integer, adding 1 is directly adding 1 to 0x100001
(unsigned int*)p + 0x1, p is forcibly converted to unsigned int*, the size is 4 bytes, plus 1 is the size of the plus type, which is 0x100004
Insert picture description here
3.

int main()
{
	int a[4] = { 1,2,3,4 };
	int *ptr = (int *)(&a + 1);
	int *ptr2 = (int *)((int)a + 1);
	printf("%x %x\n", ptr[-1], *ptr2);
	return 0;

}

Insert picture description here
Result:
Insert picture description here
4.

int main()
{
	int a[3][2] = { (0,1),(2,3),(4,5) };
	int *p;
	p = a[0];
	printf("%d\n", p[0]);
	return 0;
}

Insert picture description here
So the result is: 1
Insert picture description here

int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}

Insert picture description here
%p is an unsigned integer, so it is interpreted as a particularly large number.
Pointer-pointer, which is the number of elements experienced by the two pointers.
Result:
Insert picture description here
6.

int main()
{
	int a[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)(*(a + 1));
	printf("%d %d\n", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}

ptr1 points to the next address at the end of the array.
ptr2 points to a two-dimensional array,
the results of the second array are: 10, 5
Insert picture description here

int main()
{
	char *a[] = { "work","at","school" };
	char **pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

a is an array of pointers.
The secondary pointer pa points to the starting address of a. For pa++, it points to the next array in the pointer array. The
result of "at" is:
Insert picture description here

int main()
{
	char *c[] = { "enter","new","point","first" };
	char **cp[] = { c + 3,c + 2,c + 1,c };
	char ***cpp = cp;
	printf("%s\n", **++cpp);
	printf("%s\n", *--*++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);
	return 0;
}

Insert picture description here
Insert picture description here
The result is: point, er, st, ew
Insert picture description here

Guess you like

Origin blog.csdn.net/w903414/article/details/106837545
Recommended