Introduce the C pointer in simple language, see the real chapter in the details, refuse all groaning! ! !

Insert picture description here

Article Directory


Preface

I wrote the details of the C language a few days ago, and everyone liked it very much, and it was also ranked first on the hot list. When I wrote at least one article a day before, I think it's all thankful to be in the top ten.

Later, after deep thinking, I went to retreat and published an article for three days in the retreat. The response was very good. My brother also called me personally and said: After working for six or seven years, such a detailed blog is really rare.

Very good, there are some fans who wrote private messages about C++, and some fans said that they are still a bit unsure. In fact, after I finish writing, I will open a topic to discuss and explain the content of the article verbally, usually after I finish writing. That night or the next night, friends who are not sure can come and listen.

The arrangement of C++ is up, but I want to arrange the pointer first.

I wrote a pointer earlier, and the response was good, but I personally feel that it is still lacking in popularity. So I went into retreat for three days and took out this article.


Understanding pointers

Why do you need to be proficient in pointers?

Difficulty index: 1 star / Detail index: 3 stars / Important index: 3 stars

Pointers have multiple uses, Biru said:
1. Support dynamic memory allocation
2. Provide the ability to transfer data structures with pointers without incurring huge overhead
3. Protect data passed to functions as parameters
4. Write fast and efficient Code

If you don't know these advantages, you can easily be dissuaded by the "high difficulty" of the pointer.

I once heard a joke that more than 70% of people support the cancellation of mathematics in the college entrance examination.
why? Because mathematics gets rid of these 70% of people.

I have also heard something called a pointer is very difficult to learn, very dangerous things, novices go and don't touch it.
I don't know if this is also a joke.

Why talk about pointer discoloration?


The pointer must be initialized at the time of declaration?

Difficulty index: 1 star / Detail index: 2 stars / Important index: 3 stars

Nonsense. I don't know why some people say that, is it from a certain book?

The asterisk declares the variable as a pointer. The asterisk is actually an overload symbol because it is also used in multiplication andDereference pointeron.

#include<iostream>
using namespace std;

int main() {
	int* p;	//这里这个星号是声明指针
	int a = 10;
	p = &a;
	cout << *p << endl;	//这里这个星号就是解引指针
}

Will it work? Can you tell me after the actual measurement?

The pointer to the uninitialized memory will directly report an error. I think everyone here has encountered this kind of thing.


Have you ever seen void pointers?

Difficulty index: 3 stars / Detail index: 3 stars / Important index: 3 stars

When making general linked lists, it is more common to use void pointers. In fact, it is not only a universal linked list, but also void pointers in many places.

A void pointer is a universal pointer, which can be used to store references of any data type. Any pointer can be assigned to a void pointer, or it can be converted back to its original type.

Be careful when using void pointers. If you convert an arbitrary pointer to a void pointer, nothing prevents you from converting it to a different pointer type.


Pointer operations and arithmetic operations

Difficulty index: 2 stars / Detail index: 3 stars / Important index: 2 stars

Insert picture description here

When adding or subtracting an integer to a pointer, the pointer actually moves forward and backward, and the moved address bit is: pointer type size * integer.
Look at the length of the data type:

Insert picture description here

Come to a wave of demonstrations to understand:


/*以int指针做实验*/

#include<iostream>
using namespace std;

int main() {
	int* p;
	int a = 10;
	p = &a;
	cout << p << endl;
	cout << p+1 << endl;
	cout << p+2 << endl;
	cout << p+3 << endl;
}
004FFD34
004FFD38
004FFD3C
004FFD40

/*以char指针做实验*/

#include<iostream>
using namespace std;

int main() {
	char* p;
	char a = 10;
	p = &a;

	printf("%p\n", p);
	printf("%p\n", p+1);
	printf("%p\n", p+2);
	printf("%p\n", p+3);
}

00B5FA2B
00B5FA2C
00B5FA2D
00B5FA2E

Data speak

What about void pointers? Some compilers allow arithmetic operations on void pointers, and some do not, so be careful.


Constants and pointers

Difficulty index: 3 stars / Detail index: 4 stars / Important index: 4 stars

Break it down:

Constant\pointerconstantordinary
constant1. Constant pointer to constant2. Ordinary pointer to constant
ordinary3. Constant pointer to non-constant data4. Ordinary pointers that point to a non-constant amount

Ordinary pointer to constant:

int main() {

	const int a = 10;
	int b = 0;

	const int* p = &a;	//这是一个指向整数常量的指针、
	//int* pp = &a;	//无法将一个const int* 对象赋值给int*

	p = &b;	//将指针指向另一个对象
	//*p = 100;	//表达式必须有一个可以修改的左值
	//我们可以用p来解引用,但是不能用p来修改它,即使它是一个普通变量
	//因为它认为自己指向的是一个整数常量,服不服?!

	int* pp = &b;
	*pp = 100;

}

to sum up:

p可以被修改为指向不同的常量
p可以被修改为指向不同的变量
可以解引用以读取数据
不能解引从而修改它指向的数据

Constant pointer to variable:

#include<iostream>
using namespace std;

int main() {
	int a = 10;
	int b = 0;

	int* const p = &a;	//这是一个指向变量的常量指针、

	//p = &b;	//将指针指向另一个对象
	//表达式必须有一个可以修改的左值
	
	*p = 100;	//可以对p进行解引用以修改所指向地址内的内容
}

to sum up:

p被初始化为指向变量的常量指针
p不能指向其它对象
p指向的数据可以被修改

Insert picture description here

C's dynamic memory management

Does the pointer size have to be 4?

Difficulty index: 1 star / Detail index: 4 stars / Important index: 4 stars

For computer systems that commonly use 4-byte addresses, the size of the pointer is 4 bytes, and the size of the pointer in other systems is not necessarily 4 bytes.

Why do you want to say this? Give a simple chestnut:

struct text* a;	//这是一个结构体对象
···

//现在,需要初始化一块空间,将结构体内容写入进行网络传输

//方案一:
char* str_a = new(sizeof(a));		

//方案二:
char* str_a = new(sizeof(struct text));

//站在一个小白的角度,这两个方案你们怎么选?

As a novice, I didn't choose it at all. Don't you feel that there is no difference between the two?
Of course, choose option one, so you can write a few less codes.

Then, there was a thunderstorm, and I could only transmit four characters no matter how I wrote it. At one time I thought it was a problem written by my teammate on the client side.
After investigation, it was my problem.

Fortunately, something went wrong, otherwise I have no memory until now.


Points to note when using malloc functions

Difficulty index: 3 stars / Detail index: 4 stars / Important index: 4 stars

C's dynamic memory allocation functions mainly include:

malloc:从堆上分配内存
calloc:从堆上分配内存并清零
realloc:在之前分配内存的基础上,将内存重新分配为更大或更小的部分
free:将内存块返回堆

Dynamic memory is allocated from the heap. The system does not guarantee the continuity of memory allocation. However, the memory will be aligned according to the data type of the pointer. For example, a four-byte integer will be allocated on an address boundary that is divisible by 4. The address returned by the manager is the address of the lowest byte.

1. The parameter type of malloc is size_t. If the input parameter is a negative number, something will happen.
2. If the input parameter is 0, either NULL or a pointer to zone 0 will be returned.
3. Determine the amount of memory allocated. Recall that point above.

What if you want to allocate 5 doubles? Write it like this:

double *d = (double*)malloc(10*sizeof(malloc));

Other data types can be deduced in the same way. In fact, everyone knows how big the basic data types are. I'm afraid of those non-basic data types, so it's better to write it in this way, and it can be safer in the process of code transplantation.

4. The use process of malloc function:

double *d = (double*)malloc(10*sizeof(malloc));
if(d!=NULL){	//如果分配空间成功
	memset(d,0,10);		//清空所分配的空间
	···
}

I want to talk about calloc, but why is it that calloc is more thorough than malloc, but it doesn't use malloc as much?
That definitely makes sense.

Speed ​​is the last word! ! !


How much do you know about the realloc function?

Difficulty index: 2 stars / Detail index: 4 stars / Important index: 3 stars

Take a look at the function prototype:

void* realloc(void*ptr,size_t size);
The first parameterSecond parameterbehavior
air0
non empty0The original memory is released
non empty>Original memoryUse the current block to allocate a smaller block, and the excess memory is reclaimed
non empty<Original memoryIf possible, allocate it immediately after the current memory; if not, allocate it in another location; if there is not enough space, this returns NULL and an error is reported

Use free to release memory

Difficulty index: 3 stars / Detail index: 5 stars / Important index: 5 stars

First of all, I won't say anything. How many people remember to release the pointer after using it. You can tell me in the comment area. I respect you as a man.

Okay, this is the first detail.

The released pointer can still cause problems. If we try to dereference a pointer that has been released, the consequences are unknowable, so sometimes we explicitly assign NULL to the pointer to indicate that the pointer is invalid. After that, using this pointer will cause abnormal operation.

After calling free, remember to add NULL to the pointer,
In addition, except in the case of initialization, NULL can not be assigned to a pointer.

Repeated release problem:
Repeated release refers to the release of the same memory twice.
Repeated release is also a problem. Two pointers referencing the same address are called aliases (think linked lists).

Because of these problems with the free function, we can create our own free function. Let me make a sample:

void My_Free(void **p){
	//这是一个我们自己的free函数
	//1、防止指针被回收但是指向的内存没有释放
	//2、防止重复释放指针
	if(p != NULL && *p != NULL){	
		free(*p);
		*p = NULL;
	}
}

Do you want to release the memory before the program terminates?

Difficulty index: 3 stars / Detail index: 3 stars / Important index: 3 stars

This is not so easy to say, it depends on the specific application.

Although, remember to release the memory after using it, but the program is closed. Make sure to release all the memory before the program terminates. It may not be worth the loss:

可能很耗时,释放复杂结构也比较麻烦
可能增加应用程序的大小
增加更多编程错误的概率

decide as things go.


Insert picture description here

Pointers and functions

When using a function, there are two situations where pointers are useful. The first is to pass the pointer to the function. At this time, the function can modify the data referenced by the pointer, and it can also transfer large blocks of information more efficiently.

Another situation is to declare function pointers. In fact, function notation is pointer notation (the teacher has told us before).

Local data pointer

Difficulty index: 3 stars / Detail index: 5 stars / Important index: 5 stars

What is a local data pointer? This is a more dangerous pit. Sometimes the code just falls into it as it is written.

Don't talk about others, just talk about me. I wrote such a function before:

char* forget(){
	//函数名字忘了,参数啥的也都忘了,核心是记住了
	char* res = new char[100];
	sprintf(···);
	return res;
}

Then start receiving this return value outside.
But I am wondering, sometimes it can be received, sometimes it is not. The feedback is: sometimes there is data on the client side, and sometimes there is no data.

So my poor team member came out again and said, "Is there something wrong with the place you received? Isn't it? What about unzipping the package? Is the package unpacking wrong?"

Well, it was confirmed that it was not all his problem.

"Is our agreement wrong? I posted it to the group after changing the agreement the day before yesterday. Is our agreement unified?" The
agreement began again.

Well, it may be my fault.
So began to investigate.
Well, it turned out to be all my problem. . .

So, what is a "local function pointer"?

As the name implies, it is a pointer that declares and allocates memory in a function.
This pointer and the memory it allocates,ScopeBelongs to this function, once the function ends, it is theoretically gone. However, the recovery takes time, so it will cause: sometimes the data is received, sometimes the data is not received.

Knock on the blackboard: circle the three words "scope" to be tested! ! !


Function pointer

Difficulty index: 4 stars / Detail index: 5 stars / Important index: 4 stars

The process of the function pointer to complete the task is like this:

Get the address of the function
Declare a function pointer
Use the function pointer to call the function
Get the function address

It is relatively simple to get the address of a function. If void Hanshu(); is a function, then its address is Hanshu.
If the function Hanshubaba(); wants to call this function, it is like this: Hanshubaba(Hanshu);
remember not to write:Hanshubaba(Hanshu());


Suppose there is such a function int test3(void *arg); //这个arg参数,回调函数里面用,要解释有点长。
now : Now we need to change it into a function pointer form:int (*test3)(void *arg);

First, replace test3 with (*test3), so (*test3) is also a function, so test3 is a function pointer.
To declare the priority, you need to enclose *test3 in parentheses.


If you insist on telling me the meaning of the existence of function pointers, then I’m really not good at telling you why it is. Then I will give you a few useful places:

自定义排序/搜索

不同的模式(如策略,观察者)

回调

There should have been a "strings and pointers" part here, but in response to the needs of friends, the next article is dedicated to sorting strings, so this part will be moved to the next one.


Insert picture description here

Structure and pointer

Linked list operations that circumvent people! !

Difficulty index: 4 stars / Detail index: 5 stars / Important index: 5 stars

The status of the linked list in the data structure of the C language is not low. Many subsequent data structures, especially trees, are developed based on linked lists.
Therefore, if you learn the linked list well, it is necessary to look at the following structure.

Let's take a look at the node data structure of the linked list first:

//节点描述结构体
typedef struct point
{
	void *pData;				//指向数据域
	struct point *next;			//指向下一个节点	
} POINT_T;

Pay attention to the distinction, the linked list will have two "structures", one is the data node, and the other is the linked list node carrying the data node.
Imagine that the train, the carriage and the people are separated.
Don’t ignore this simple concept. It’s the most important thing to understand the list after a period of time.! ! !

The above is the "carriage", and the "pData" in it can be regarded as a "person".

Take a "human" chestnut:

//节点数据结构体
typedef struct test
{	
	char name[12];		//名字
	char pwd[8];		//密码
	int number;			//编号
	int flag;			//区分管理员和用户	// 	0 超级管理员 1 管理员  2 普通用户 3 屏蔽用户
	int money;			//仅用户有存款,初始500
} TEST_T;

Since it is void*, it means that it can be any data structure or a basic data structure, such as int.

When each section of "body" is not operated and changed, its address is fixed, and the addresses of its front and rear sections of "carriage" are also fixed.

Let's look at a few basic operations and pay attention to the distinction:

(伪代码)
PData* head;	//链表的头
PData* tempA = head;	//临时节点,但是它现在也是链表的头了
PData* tempB = head;	//临时节点,但是它现在也是链表的头了

Now, head, tempA, tempB,Not the same pointer, but pointing to the same address.
These three pointers have the same one-vote decision for everything on the current address. It will be a bit detour.

Now let's take a look at a few more operations:

tempA = tempA->next;	
//将tempA指针指向下一个节点,失去了对原地址的决定权,但是保留了对原地址的下一个地址的绝对权力。另外两个指针并不受影响
tempB->next = NULL;		
//好家伙,tempB指针将当前地址的下一个指针域置空了,由于tempA已经走了,所以不受影响,但是head指针指向的部分同时被清空了

See it, this is one of the most confusing operations in the linked list.

Let's go back to the front, just as if this wave of operations has not happened, let's look at another wave of operations:

head->next = tempA;	
//将tempA接到了head的下面,原本A后面的内容就没有掉了
//但是,tempA也受到了影响,这句话等同于:
head->next = head;
//陷入了死循环

Okay, back to the origin, let's look at another wave of operations:

head->val = 0;	
//将head指针指向的值域的值置0,则tempA、tempB所指向值域的值读出来也是0了。

In fact, the linked list is nothing more than these points, but these points are enough to circumvent fools.

The best way to unlink the list of questions is the most earthy way, first draw the entire operation process on paper before you start! ! !


Common linked list operations

Difficulty index: 3 stars / Detail index: 5 stars / Important index: 4 stars

//创建结点
POINT_T * creat(void *data )	//创建一个属于结构体point的函数,
//传入结构体test的指针便可以用以操作test变量,
{								//并返回一个point的指针用以操作point函数
	POINT_T *p=NULL;
	
	p=(POINT_T *)malloc(sizeof(POINT_T));
	if(p==NULL)
	{
		printf("申请内存失败");
		exit(-1);
	}
	memset(p,0,sizeof(POINT_T));
	
	p->pData=data;
	p->next=NULL;	//处理干净身后事
	return p;
}

//新增节点
void add(POINT_T * the_head,void *data )				//这里的data不会和上面那个冲突吗?
{
	POINT_T * pNode=the_head;							//把头留下
	POINT_T *ls=creat(data);
	//后面再接上一个
	while (pNode->next != NULL)							//遍历链表,找到最后一个节点
	{
		pNode=pNode->next;
	}
	pNode->next=ls;			//ls 临时
}

//删除节点
void del(POINT_T * the_head, int index)
{
	POINT_T *pFree=NULL;					//用来删除
	
	POINT_T *pNode=the_head;
	int flag=0;
	while (pNode->next!=NULL)
	{
		if(flag==index-1)
		{
			pFree=pNode->next;				//再指向数据域就爆了
			pNode->next=pNode->next->next;	//这里要无缝衔接
			free(pFree->pData);				//先释放数据
			free(pFree);					//释放指针
			break;
		}
		pNode=pNode->next;
		flag++;	
	}	
}

//计算节点数
int Count(POINT_T * the_head)
{
	int count=0;
	POINT_T *pNode1=the_head;
	while (pNode1->next!=NULL)
	{
		pNode1=pNode1->next;
		count++;		
	}	
	return count;
}

//查找固定节点数据
POINT_T * find(POINT_T *the_head,int index)
{
	int f=0;
	POINT_T *pNode=NULL;
	int count=0;
	pNode=the_head;
	
	count=Count(the_head);
	
	if(count<index)	
		printf("find nothing");
	
	while(pNode->next!=NULL)
	{
		if(index==f)
			return pNode;
		pNode=pNode->next;
		f++;		
	}
}
Insert picture description here

The plan to create a boutique column! ! !