几年前,Linus Torvalds做了一个TED演讲,他展示了一个链表实现,通过使用指针到指针来删除多余的if测试,他认为这是"好品味"。 下面是一个简单的例子:
#include <stdio.h>
#include <stdlib.h>
struct list_entry {
int val;
struct list_entry *next;
};
void list_insert(struct list_entry **head, int val)
{
while (*head)
head = &(*head)->next;
*head = calloc(1, sizeof(**head));
(*head)->val = val;
}
int main(int argc, char *argv[])
{
struct list_entry *head = NULL;
list_insert(&head, 0);
list_insert(&head, 1);
printf("Entry 1: %dn", head->val);
printf("Entry 2: %dn", head->next->val);
}
通过使用递归list_insert
和 fortran 的引用调用语义,我能够在 fortran 中制作类似这项工作的东西:
module list_type
implicit none
type :: list
integer :: val
type(list), pointer :: next => null()
end type list
contains
recursive subroutine list_insert(lst, val)
type(list), pointer, intent(inout) :: lst
integer :: val
!-
if (associated(lst)) then
call list_insert(lst%next, val)
return
else
allocate(lst)
lst%val = val
end if
end subroutine list_insert
end module list_type
program list_test
use list_type
implicit none
type(list), pointer :: head => null()
call list_insert(head, 0)
call list_insert(head, 1)
call list_insert(head, 2)
print *, head%val
print *, head%next%val
print *, head%next%next%val
end program list_test
有没有办法在不诉诸递归的情况下完成这项工作? 到目前为止,我所有的尝试都以失败告终。
编辑:这是我的迭代方法不起作用的示例
module list_type
...
type :: list_ptr
type(list), pointer :: p
end type list_ptr
contains
...
subroutine list_insert_iter(lst, val)
type(list), pointer, intent(inout) :: lst
integer :: val
!-
type(list_ptr) :: walker
walker%p => lst
do while (associated(walker%p))
walker%p => lst%next
end do
allocate(walker%p)
walker%p%val = val
end subroutine list_insert_iter
end module list_type
program list_test
use list_type
implicit none
type(list), pointer :: head => null()
call list_insert_iter(head, 0)
if (.not.associated(head)) stop "FAIL"
end program list_test
在 Fortran 中处理指针时,通常需要使用中间包装器类型。 此包装器的语义更接近 C 指针的语义,而不是裸 Fortran 指针。
举个例子:
module list_type
implicit none
type :: list_ref
type(list), pointer :: ref => null()
end type list_ref
type :: list
integer :: val
type(list_ref) :: next
end type list
contains
subroutine list_insert(lst_arg, val)
type(list_ref), intent(inout), target :: lst_arg
integer, intent(in) :: val
type(list_ref), pointer :: lst
lst => lst_arg
do while (associated(lst%ref))
lst => lst%ref%next
end do
allocate(lst%ref)
lst%ref%val = val
end subroutine list_insert
end module list_type
program list_test
use list_type
implicit none
type(list_ref) :: head
call list_insert(head, 0)
call list_insert(head, 1)
call list_insert(head, 2)
print *, head%ref%val
print *, head%ref%next%ref%val
print *, head%ref%next%ref%next%ref%val
end program list_test