Baru-baru ini, ketika menulis beberapa program linux di c, sepertinya banyak tempat yang memerlukan daftar tertaut umum yang dapat mendukung berbagai jenis nilai, jadi saya mencoba menerapkannya, tetapi masih ada beberapa pertanyaan.
Pendekatan:
- tentukan sebuah struct dengan pointer, lalu akhiri dengan bidang nilai bertipe char[], gunakan itu sebagai struct umum,
- tentukan & impl metode pada daftar tertaut, menggunakan struct umum,
- tentukan tipe struct baru yang memiliki bidang nilai tipe berbeda,
- saat memanggil fungsinya, masukkan saja sesuatu sebagai tipe umum,
Kode: (versi draf)
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();
}
Kompilasi & Jalankan
daftar kode:
- linked_list.h, tajuk,
- linked_list.c, implementasi,
- llist_test.c, lakukan tes,
kompilasi - untuk pengujian:
gcc -Dinding tertaut_list.c llist_test.c -o a.out
eksekusi:
./a.keluar
Pertanyaan:
- Pengecorannya rumit, apakah ada pendekatan untuk menyederhanakannya?
Dalam metode pengujian
linked_list_test()
:jika berubah:
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);
Maka hasilnya adalah penggunaan, bukan keluaran:
1 2 3 4 5
itu keluaran:
32513 32514 32515 32516 32517
Yang membedakan adalah cast pointernya, kenapa hasilnya berbeda?
@Pembaruan - Tentang pertanyaan kedua
Seperti yang dijelaskan @BLUEPIXY dalam komentar, memang sizeof(*valuep)
yang menyebabkan masalah, sekarang saya memodifikasi llist_del_head()
, dan memberikan ukuran dalam daftar param secara eksplisit, dan masalah diperbaiki.
Fungsinya sekarang terlihat seperti ini:
extern struct llist_item *llist_del_head(struct llist_item **headp, char *valuep, ssize_t value_size);
sizeof(*valuep)
adalah1
- person BLUEPIXY   schedule 23.01.2016&something
). Saat Anda mengambil alamat suatu objek dengan operator&
urnary, hasilnya hanyalah sebuah alamat. Sebuah alamat tidak memiliki tipe -- ini hanya sebuah lokasi memori. Oleh karena itu, untuk memanfaatkan alamat objek dengan benar, Anda harus mentransmisikan alamat objek ke ketik yang tepat. - person David C. Rankin   schedule 23.01.2016sizeof(*valuep)
yang menyebabkan masalah, sekarang saya memodifikasillist_del_head()
untuk memberikan ukuran dalam daftar param secara eksplisit, dan masalah telah diperbaiki, terima kasih. - person user218867   schedule 23.01.2016&
) diterapkan ke objek apa pun yang valid, hasilnya selalu berupa nilai yang diketik. Jika diterapkan padaint
, tipenya adalahint *
. Jika diterapkan padachar [5]
, hasilnya adalahchar (*)[5]
. Setiap ekspresi dalam C memiliki tipe, baik pointer atau lainnya. - person Tom Karzes   schedule 23.01.2016const
dalam situasi yang tidak disukai kompiler. - person Tom Karzes   schedule 23.01.2016