contributed by < EJ7289
>
$ gcc --version
gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 39 bits physical, 48 bits virtual
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 142
Model name: Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz
Stepping: 9
CPU(s) scaling MHz: 14%
CPU max MHz: 3500.0000
CPU min MHz: 400.0000
BogoMIPS: 5799.77
Virtualization: VT-x
L1d cache: 64 KiB (2 instances)
L1i cache: 64 KiB (2 instances)
L2 cache: 512 KiB (2 instances)
L3 cache: 4 MiB (1 instance)
NUMA node0 CPU(s): 0-3
在 C 語言中, malloc
用來分配指定大小的記憶體空間,並且回傳指標,配置的空間尚未初始化。
C99 [7.20.3.3] The malloc function
#include <stdlib.h>
void * malloc(size_t size);
Description
The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate.
Return
The malloc function returns either a null pointer or a pointer to the allocated space.
若記憶體配置失敗,須回傳空指標,但是 C 語言中的空指標用 NULL 表示。
補充:C++11 中的空指標用 nullptr 表示。
struct list_head *q_new(){
struct list_head *h = (struct list_head *)malloc(sizeof(struct list_head));
if (!h) {
return NULL;
}
h->next = h;
h->prev = h;
return h;
}
注意事項:
以下程式會陷入無窮迴圈:
void q_free(struct list_head *head)
{
while(head) {
struct list_head *next = head->next;
free(head);
head = next;
}
}
放 github 的程式
free
函數的引數為指標。
C99 [7.20.3.2] The free function
#include <stdlib.h>
void free(void *ptr);
bool q_insert_head(struct list_head *head, char *s)
{
element_t *newq = malloc(sizeof(element_t));
if (!newq) { return false; }
newq->value = s;
newq->list.next = head;
newq->list.prev = head->prev;
return true;
}
以上程式的問題有:
修改方法:
strdup()
複製字串。 strdup()
會用 malloc 獲得新的字串,並且可用 free 釋放字串。bool q_insert_tail(struct list_head *head, char *s)
{
// Create a new queue
element_t *newq = malloc(sizeof(element_t));
if (!newq) {
return false;
}
// Duplicate s in global memory and storage in new queue
newq->value = strdup(s);
if (!newq->value) {
free(newq);
return false;
}
// Insert s at the tail of queue
newq->list.next = head;
newq->list.prev = head->prev;
head->prev->next = &newq->list;
head->prev = &newq->list;
return true;
}
放 github 的程式
在 queue.h 說明:
q_remove_head(struct list_head *head, char *sp, size_t bufsize)
原本程式碼:
element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || list_empty(head)) {
return NULL;
}
// find the element of node
element_t *h = list_entry(head, element_t, list);
sp = h->value;
list_del_init(head);
return h;
}
以上程式的問題有:
list_entry(head->next, element_t, list)
list_del_init(head->next)
sp = h->value
無法回傳字串 - h 為區域變數
*sp = *h->value
只能回傳一個字元,無法回傳字串strncpy
複製 sp 如果不複製為怎樣?char
只能作為字元,例如 char a = 'a'
char的字元宣告必須用單引號char
不能作為字串的宣告,例如 char a = "good"
char *
則作為字串的指標宣告
char *a = "a"
char的指標宣告必須用雙引號char *b = "good"
char *a = "a";
char *b = "banana";
printf("%c\n", a); // error
printf("%c\n", *a); // correct, a
printf("%c\n", b); // error
printf("%c\n", *b); // correct, b
printf("%s\n", b); // correct, banana
printf("%s\n", *b); // error
element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || list_empty(head)) {
return NULL;
}
// find the element of node
element_t *h = list_entry(head, element_t, list);
if (sp) {
sp = strncpy()
}
sp = h->value;
list_del_init(head);
return h;
}
解題思維:
insert github's commit
解題思維:
list_del()
)elem
和 elem->value
)insert github's commit
目的:將相鄰且相同的數值刪除
解法:
bool q_delete_dup(struct list_head *head)
{
// https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
if (!head || list_empty(head))
return false;
struct list_head *curr = head->next;
struct list_head *next = curr->next;
bool del = false;
while(curr!=head) {
element_t *elem = list_entry(curr, element_t, list);
element_t *safe = list_entry(next, element_t, list);
if (elem->value == safe->value) {
del = true;
list_for_each_entry_safe(elem, safe, head, list);
free(elem->value);
free(elem);
} else if ((elem->value != safe->value) && (del == true)) {
del = false;
list_for_each_entry_safe(elem, safe, head, list);
free(elem->value);
free(elem);
}
curr = next;
next = next->next;
}
return true;
}
程式 1 存在的問題:
elem->value 指向的是 value 的地址,因此要用 strcmp()
list_for_each_entry_safe()
的使用方式不正確
在 list.h
中說明list_for_each_entry_safe()
可用來代替一個 for 迴圈。
#define list_for_each_entry_safe(entry, safe, head, member) \
for (entry = list_entry((head)->next, typeof(*entry), member), \
safe = list_entry(entry->member.next, typeof(*entry), member); \
&entry->member != (head); entry = safe, \
safe = list_entry(safe->member.next, typeof(*entry), member))
最基本的定義方式#define MACRO value
=> #define MAX 1000
須使用 list_del()
將指定數值從鏈結串列中移除
需要初始化 entry=NULL
和 safe=NULL
github code
利用 XOR 操作 swap 的行為,不適用在 struct
和 char*
,因此該題不適用。
XORswap(int *a, int *b) {
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
因此,需要另外存取的空間 tmp 。
解題方法:不改 node ,指改變 *value
。(如下方程式所示)
for (; curr != head && curr->next != head;
curr = curr->next->next, next = curr->next) {
char *tmp = list_entry(curr, element_t, list)->value;
list_entry(curr, element_t, list)->value = list_entry(next, element_t, list)->value;
list_entry(next, element_t, list)->value = tmp;
}
github code
解題方法:
curr->next = prev
的概念*value
解題方法:
github code
在 C99 [6.8.5.3] 中,解釋到 for 迴圈的使用如下,
for ( init-clause ; condition ; iteration-expression ) statement
其中:
範例:
for (int a=0, b=0; a<3, b<3; a++, b++, printf("a = %d\n", a)) {
printf("b = %d\n\n", b);
}
輸出:
b = 0
a = 1
b = 1
a = 2
b = 2
a = 3
struct list_head *qsort_split(struct list_head *head, bool descend)
{
if (!head || list_empty(head) || list_is_singular(head))
return head;
struct list_head *base = head->next;
struct list_head *curr = head->next->next;
struct list_head *left;
struct list_head *right;
INIT_LIST_HEAD(left);
INIT_LIST_HEAD(right);
for (; curr != head; curr = curr->next) {
if (strcmp(list_entry(base, element_t, list)->value,
list_entry(curr, element_t, list)->value) >= 0) {
list_add_tail(curr, left);
} else {
list_add_tail(curr, right);
}
}
if (descend == true) {
struct list_head *tmp = left;
left = right;
right = tmp;
}
list_add_tail(base, left);
list_splice(qsort_split(left, descend), qsort_split(right, descend));
return left;
}
想建立一個新的 dummy 為什麼不能這樣寫?
struct list_head *dummy;
INIT_LIST_HEAD(dummy);
struct list_head *dummy = NULL;
INIT_LIST_HEAD(dummy);
為什麼必須這樣寫?
struct list_head dummy;
INIT_LIST_HEAD(&dummy);
github code
queue_context_t
取出各個 queuehead
作為 head ?