C language self-study course - first encounter with the great devil pointer (part 2)

Get into the habit of writing together! This is the 10th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .

At present, "C language self-study course" is constantly being updated. In the
future, "Data Structure Algorithm", "C++ Language", "Linux System Programming", "Linux Network Programming", "MySQL Database" and so on.
Friends who are looking forward to systematically learning programming can follow me, don't miss it!

1. Wild pointer

Concept: A wild pointer is where the pointer points to is unknowable (random, incorrect, unspecified)

1.1 Causes of wild pointers

  1. pointer is not initialized
#include <stdio.h>
int main()
{
   int *p;//局部变量指针未初始化,默认为随机值
   *p = 20;
   return 0;
}
复制代码
  1. 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;
}
复制代码
  1. The space pointed to by the pointer is freed

It will be explained in detail when the dynamic memory is opened. Here is a brief reminder. Please add image descriptionAfter calling the test function, a is destroyed, and the right to use the space of 0x0012ff40 is reclaimed. At this time, p is a wild pointer, but the subsequent code still accesses this space. But the content of that space is not changed, so it happens to print 100.

1.2 How to avoid wild pointers

1. Pointer initialization
2. Be careful of pointer out-of-bounds
3. Place NULL in time when the pointer points to the space released
4. Avoid returning the address of a local variable
5. Check the validity of the pointer before use

#include <stdio.h>
int main()
{
	int *p = NULL;//指针指向空间释放及时放置NULL
	//....
	int a = 10;
	p = &a;
	if(p != NULL)//指针使用之前检查有效性
	{
		*p = 20;
	}
	return 0;
}
复制代码

2. Pointer arithmetic

2.1 Pointer + - Integer

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;
	}
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}

	return 0;
}
复制代码

2.2 Pointer-Pointer

int main()
{
	int a[10] = { 0 };
	printf("%d\n", &a[9] - &a[0]);//9
	printf("%d\n", &a[0] - &a[9]);//-9
	return 0;
}
复制代码

2.3 Relational operations on pointers

//从后往前初始化
float values[5];
float *vp;
for(vp = &values[5]; vp > &values[0];)
{
	*--vp = 0;
}
复制代码

insert image description here

Code simplification, which modifies the code as follows:

for(vp = &values[4]; vp >= &values[0];vp--)
{
	*vp = 0;
}
复制代码

Please add image description

Simplified code actually works fine on most compilers, but we should avoid writing it because the standard doesn't guarantee that it will work.

The standard states: 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 a comparison with a pointer to a memory location before the first element is not allowed.

3. Pointers and arrays

Let's look at an example:

#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;
}
复制代码

Running result: It can be insert image description hereseen that the array name and the address of the first element of the array are the same. Conclusion: The array name represents the address of the first element of the array. (Except for 2 cases, which are explained in the Array chapter) Then it is feasible to write the code like this:

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
复制代码

Since the array name can be stored in a pointer as an address, it is possible for us to use the pointer to access an array. E.g:

#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]);
	for(i=0; i<sz; i++)
	{
		printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i);
	}
	return 0;
}
复制代码

Running result: insert image description here So p+i actually calculates the address of the subscript i of the array arr. Then we can access the array directly through the pointer. as follows:

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("%d ", *(p + i));
	}
	return 0;
}
复制代码

4. Secondary pointer

A pointer variable is also a variable, and a variable has an address. Where is the address of the pointer variable stored?
This is it 二级指针 . insert image description hereThe operations for the second-level pointer are: *ppa dereferences the address in ppa to find pa, and *ppa actually accesses pa.

int b = 20;
*ppa = &b;//等价于 pa = &b;
复制代码

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

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;
复制代码

Man, this is a nesting doll.

7. Array of pointers

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

int arr1[5];
char arr2[6];
复制代码

insert image description here

What about an array of pointers?

int* arr3[5];//是什么?
复制代码

arr3 is an array with five elements, each element is an integer pointer.Please add image description

This is the end of this chapter, but the content of the pointer is not finished yet, so let’s give a preview of the next issue. In the next issue, we will talk about the pointer in detail, and the content is even more important and difficult. I believe we can beat it through hard work. The big devil pointer! Interested friends can follow me not to get lost!

Guess you like

Origin juejin.im/post/7085157385076998175