Original article Chen Hao
Link: http://coolshell.cn/articles/8990.html
Thanks to full_of_bull for posting this article(Note: This article was originally published here. I modified a lot in the second half of the original article and added illustrations)
Linus big brother answered some questions from programmers on Slashdot. One of them asked him what kind of code he liked. After talking about some of his ideas, he gave an example of a pointer, explains what isCore low-level coding.
The following is the original teaching text and translation of Linus --
"at the opposite end of the spectrum, I actually wish more people understood the really core low-level kind of coding. not big, complex stuff like the lockless Name Lookup, but simply good use of Pointers-to-Pointers etc. for example, I 've seen too records people who delete a singly-Linked List entry by keeping track of the "Prev" entry, and then to delete the entry, doing something like. (At the end of this section, I actually want more people to understand what is the real core underlying code. This is not as huge and complex as querying lockless file names (Note: it may be the design in git source code), but just as simple as using a second-level pointer. For example, I have seen many people maintain a "Prev" Table item pointer when deleting a single linked list and then delete the current table item, just like this) "
1234 |
If (Prev)
Prev-> next = entry-> next; Else
List_head = entry-> next; |
And whenever I see code like that, I just go "this person doesn't understand Pointers ". and it's sadly quite common. (when I see this code, I will think "this person doesn't know the pointer ". Sadly, this is too common .)
People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. and then as they traverse the list, they can remove the entry without using any conditionals, by just doing a "* PP = entry-> next ". (the person who understands the pointer will use the address of the linked list header to initialize a "pointer to the node pointer ". When a, and in the as in, as in the as in, and)
So there's lots of pride in doing the small details right. it may not be big and important code, but I do like seeing code where people really thought about the details, and clearly also were thinking about the compiler being able to generate efficient code (rather than hoping that the compiler is so smart that it can make efficient code * Despite * The State of the original source code ). (It is proud to correct the details. Events. Maybe this code is not huge and important,But I like to read the code written by people who focus on code details, that is, to clearly understand how to compile valid code.(Rather than relying on a smart compiler to generate valid code, even those original assembly code )).
Linus gave an example of a one-way linked list, but the Code provided is too short. Generally, it is difficult for people to understand the meaning behind the two codes. A programmer has read this section and provided a complete code. I will not translate his words. The following code is provided.
If we need to write a remove_if (link *, rm_cond_func *) function, that is, to pass in a one-way linked list and a custom delete function, and then return the processed link.
This code is not difficult. Basically, all textbooks will provide the following sample code, which is also a face-to-face question for large companies.StandardTemplate:
123456789101112131415161718192021222324252627282930 |
typedef struct node { struct node * next; .... } node; typedef bool (* remove_fn)(node const * v); // Remove all nodes from the supplied list for which the // supplied remove function returns true. // Returns the new head of the list. node * remove_if(node * head, remove_fn rm) { for (node * prev = NULL, * curr = head; curr != NULL; ) { node * const next = curr->next; if (rm(curr)) { if (prev) prev->next = next; else head = next; free (curr); } else prev = curr; curr = next; } return head; } |
Remove_fn is a function pointer provided by the call query to determine whether to delete the current object node. It will determine whether the deletion condition is true. This Code maintains two node pointers: Prev and curr,Standard textbook writing-When deleting the current knot, a previous pointer is required, and a boundary condition judgment is required here-whether curr is the linked list Header. Therefore, to delete a node (not the header), you only need to direct the next node of the previous node to the next object of the current node, that is, the next node (I .e: prev-> next = curr-> next), and then release the current node.
But in Linus's view, this is the practice of a person who does not know the pointer. So what is core low-level coding? That isThe second-level pointer is effectively used as the primary option for managing and operating the linked list.The Code is as follows:
1234567891011121314 |
void remove_if(node ** head, remove_fn rm) { for (node** curr = head; *curr; ) { node * entry = *curr; if (rm(entry)) { *curr = entry->next; free (entry); } else curr = &entry->next; } } |
How can I improve the same piece of code? We can see:You do not need a prev pointer or determine whether it is the head of the linked list. However, curr becomes a pointer to the pointer.. This is exactly the subtlety of this program. (Note: the three lines of code in my highlight)
Let us come and run this code, --
- Deleting a node is the headerIn the case of, input the second-level pointer of the head in the parameter, initialize the curr in the for loop, and then the entry is * head (* curr). We will immediately delete it, then, the 8th rows are equivalent to * head = (* head)-> next, which is the implementation of deleting the header.
- Deleting a node is not a headerFor the above code, we can see --
1)(12th rows)If you do not delete the current node -- curr stores the address of the next pointer of the current node.
2) (row 5th) the entry saves * curr--This means that in the next loop, the entry is the memory pointed to by the prev-> next pointer.
3) (Row 3) Delete the node: * curr = entry-> next; -- so: Prev-> next points to entry-> next;
Is it clever? We can use only one second-level pointer to operate the linked list, which is the same for all nodes.
If you have difficulty understanding the above Code and description, you can look at the following:
(Full text)
[Switch] Linus: using a second-level pointer to delete a one-way linked list