เมื่อเร็ว ๆ นี้เมื่อเขียนโปรแกรม linux ใน c ดูเหมือนว่ามีสถานที่จำนวนมากต้องการรายการเชื่อมโยงทั่วไปที่สามารถรองรับค่าประเภทต่าง ๆ ดังนั้นฉันจึงพยายามใช้รายการหนึ่ง แต่ก็ยังมีคำถามอยู่บ้าง
แนวทาง:
- กำหนดโครงสร้างด้วยพอยน์เตอร์ จากนั้นปิดท้ายด้วยฟิลด์ค่าประเภท char[] ใช้เป็นโครงสร้างทั่วไป
- วิธีกำหนด & นัยในรายการที่ลิงก์โดยใช้โครงสร้างทั่วไป
- กำหนดประเภทโครงสร้างใหม่ที่มีฟิลด์ค่าประเภทที่แตกต่างกัน
- เมื่อเรียกใช้ฟังก์ชัน เพียงแค่โยนสิ่งต่าง ๆ ให้เป็นประเภททั่วไป
รหัส: (เวอร์ชันร่าง)
linked_list.h
#ifndef _LINKED_LIST
#define _LINKED_LIST
// common list for any type,
struct llist_item {
struct llist_item *next;
char value[1];
};
// int list
struct llist_int {
struct llist_int *next;
int value;
};
/**
* append item to end of list,
*
* @param headp
* pointer to head pointer,
* @param valuep
* pointer set value of deleted item into,
* @param value_size
* size of value,
* @param struct_size
* size of actual struct,
*
* @return
* pointer to head,
*/
extern struct llist_item *llist_append(struct llist_item **headp, void *valuep, ssize_t value_size, ssize_t struct_size);
/**
* delete head,
*
* @param headp
* pointer to head pointer,
* @param valuep
* pointer set value of deleted item into,
*
* @return
* pointer to new head,
*/
extern struct llist_item *llist_del_head(struct llist_item **headp, char *valuep);
#endif
linked_list.c
// linked_list utility
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include "linked_list.h"
/*
printf("error while linked_list: %s\n", strerror(errno));
printf("linked_list succeed\n");
*/
struct llist_item *llist_append(struct llist_item **headp, void *valuep, ssize_t value_size, ssize_t struct_size) {
struct llist_item *head = *headp;
// create new item
struct llist_item *new_item = (struct llist_item*) malloc(struct_size);
new_item->next = NULL;
memcpy(&(new_item->value), valuep, value_size);
// append new item
if(head == NULL) { // empty queue,
head = new_item;
*headp = head;
} else {
// find last item
struct llist_item *tail = head;
while(tail->next != NULL) {
tail = tail->next;
}
tail->next = new_item;
}
return head;
}
struct llist_item *llist_del_head(struct llist_item **headp, char *valuep) {
struct llist_item *head = *headp;
if(head == NULL) {
return NULL;
} else {
memcpy(valuep, &(head->value), sizeof(*valuep));
*headp = head->next;
free(head);
return *headp;
}
}
llist_test.c
// linked_list test
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include "linked_list.h"
int linked_list_test() {
struct llist_int *int_list = NULL; // it's important to initialize this pointer as NULL explicitly,
int i;
for(i=1; i<=5; i++) {
llist_append((struct llist_item **) &int_list, (void *) &i, sizeof(int), sizeof(struct llist_int));
}
struct llist_int *int_item;
int value;
if(int_list != NULL) {
do {
(struct llist_int *)llist_del_head((struct llist_item **) &int_list, (char *) &value);
printf("%d\n", value);
} while (int_list!= NULL);
}
return 0;
}
int main(int argc, char * argv[]) {
return linked_list_test();
}
คอมไพล์และรัน
รายการรหัส:
- linked_list.h ส่วนหัว
- linked_list.c การใช้งาน
- llist_test.c ทำการทดสอบ
คอมไพล์ - สำหรับการทดสอบ:
gcc - ผนัง linked_list.c llist_test.c -o a.out
ดำเนินการ:
./a.ออก
คำถาม:
- การหล่อมีความซับซ้อน มีแนวทางใดที่ทำให้ง่ายขึ้นหรือไม่?
ในวิธีทดสอบ
linked_list_test()
:หากมีการเปลี่ยนแปลง:
do { int_item = (struct llist_int *)llist_del_head((struct llist_item **) &int_list, (char *) &value); printf("%d\n", value); } while (int_item != NULL);
to
do { (struct llist_int *)llist_del_head((struct llist_item **) &int_list, (char *) &value); printf("%d\n", value); } while (int_list!= NULL);
ผลลัพธ์ที่ได้คือการใช้ แทนที่จะเป็นเอาต์พุต:
1 2 3 4 5
มันเอาท์พุท:
32513 32514 32515 32516 32517
ความแตกต่างคือการร่ายพอยน์เตอร์ เหตุใดจึงทำให้ผลลัพธ์แตกต่างออกไป
@อัปเดต - เกี่ยวกับคำถามที่ 2
ตามที่ @BLUEPIXY อธิบายไว้ในความคิดเห็น แน่นอนว่า sizeof(*valuep)
ทำให้เกิดปัญหา ตอนนี้ฉันแก้ไข llist_del_head()
และระบุขนาดในรายการพารามิเตอร์อย่างชัดเจน และแก้ไขปัญหาแล้ว
ฟังก์ชั่นตอนนี้มีลักษณะดังนี้:
extern struct llist_item *llist_del_head(struct llist_item **headp, char *valuep, ssize_t value_size);
sizeof(*valuep)
คือ1
- person BLUEPIXY   schedule 23.01.2016&something
) เมื่อคุณใช้ที่อยู่ของวัตถุด้วยตัวดำเนินการ urnary&
ผลลัพธ์ก็คือ ที่อยู่ ที่อยู่ไม่มีประเภท -- มันเป็นเพียงตำแหน่งหน่วยความจำ ดังนั้น เพื่อที่จะใช้ที่อยู่ของออบเจ็กต์อย่างเหมาะสม คุณต้อง ส่งที่อยู่ ของออบเจ็กต์ให้เป็น ประเภท ที่เหมาะสม - person David C. Rankin   schedule 23.01.2016sizeof(*valuep)
ที่ทำให้เกิดปัญหา ตอนนี้ฉันได้แก้ไขllist_del_head()
เพื่อให้มีขนาดในรายการพารามิเตอร์อย่างชัดเจน และแก้ไขปัญหาแล้ว ขอบคุณ - person user218867   schedule 23.01.2016&
) กับวัตถุที่ถูกต้อง ผลลัพธ์จะเป็นค่าที่พิมพ์เสมอ หากนำไปใช้กับint
ประเภทจะเป็นint *
หากใช้กับchar [5]
ผลลัพธ์จะเป็นchar (*)[5]
ทุกนิพจน์ในภาษา C มีประเภท ไม่ว่าจะเป็นตัวชี้หรืออย่างอื่น - person Tom Karzes   schedule 23.01.2016const
ตัวระบุในสถานการณ์ที่คอมไพเลอร์ไม่ชอบ - person Tom Karzes   schedule 23.01.2016