C语言中的Cons单元数据结构

C语言中的Cons单元数据结构,c,pointers,data-structures,tree,scheme,C,Pointers,Data Structures,Tree,Scheme,我是C语言的新手,正在构建一个小型Scheme解释器的早期阶段。对于项目的这一部分,我试图构建一个简单的cons单元数据结构。它应该有一个如下的列表 (a b c) 并在内部这样表示: [ ][ ] -> [ ][ ] -> [ ][/] | | | A B C 为了测试它是否正常工作,我有一个打印功能来回显输入。以下是不起作用的代码: #include <stdlib.h> #include <

我是C语言的新手,正在构建一个小型Scheme解释器的早期阶段。对于项目的这一部分,我试图构建一个简单的cons单元数据结构。它应该有一个如下的列表

(a b c)

并在内部这样表示:

[ ][ ] -> [ ][ ] -> [ ][/]
 |         |         |
 A         B         C 
为了测试它是否正常工作,我有一个打印功能来回显输入。以下是不起作用的代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "lexer.h"
#include "parse.h"

char token[20]; 


struct conscell {
    char *data;
    struct conscell *first, *rest;
};

void S_Expression ()
{   
    /* function from lexer to receive input a split into tokens no greater than 20 */
    startTokens(20);

    /* gets the next token */
    strcpy(token, getToken());

    /* List is a typedef for the struct conscell */
    List tree = createList ();
    tree = nextNode (tree);
    printList(tree);

}


List createList ()
{
    List node = malloc(sizeof (List));

    if (node == NULL) {
        printf("Out of memory!\n");
        exit(1);
    }
    node->data = NULL;
    node->first = NULL;
    node->rest = NULL;

    return node;
}

/* Recursive function to build cons cell structure */
List nextNode (List node)
{
    node = createList ();

    if (token[0] == '(')
    {         
       strcpy(token, getToken());
       node->first = nextNode(node->first);
       node->rest = nextNode(node->rest);         
     }

    else
    {
       if (token[0] == ')')
       {
          node = NULL;
       }

       else
       {
           List temp = createList();
           temp->data = token;
           temp->first = NULL;
           temp->rest = NULL;

           node->first = temp;

           strcpy(token, getToken());
           node->rest = nextNode(node->rest);            
       }
   }
   return node;
}

/* Prints output. So far, just trying to print symbols */
void printList(List node)
{
    if (node != NULL)
    {
      if (node->data != NULL)
      {        
        printf("%s", node->data);

      }
    }
}
#包括
#包括
#包括
#包括“lexer.h”
#包括“parse.h”
字符标记[20];
结构conscell{
字符*数据;
结构conscell*第一,其余;
};
void S_表达式()
{   
/*从lexer接收分为不大于20个令牌的输入的函数*/
斯塔特肯(20);
/*获取下一个令牌*/
strcpy(token,getToken());
/*列表是结构单元的类型定义*/
列表树=createList();
树=下一个节点(树);
打印列表(树);
}
列表createList()
{
列表节点=malloc(sizeof(List));
if(node==NULL){
printf(“内存不足!\n”);
出口(1);
}
节点->数据=NULL;
节点->第一个=空;
node->rest=NULL;
返回节点;
}
/*递归函数构建cons单元结构*/
列表下一个节点(列表节点)
{
node=createList();
如果(令牌[0]=='(')
{         
strcpy(token,getToken());
节点->第一个=下一个节点(节点->第一个);
节点->休息=下一个节点(节点->休息);
}
其他的
{
如果(令牌[0]==')')
{
node=NULL;
}
其他的
{
List temp=createList();
临时->数据=令牌;
temp->first=NULL;
temp->rest=NULL;
节点->第一个=温度;
strcpy(token,getToken());
节点->休息=下一个节点(节点->休息);
}
}
返回节点;
}
/*打印输出。到目前为止,只是想打印符号*/
作废打印列表(列表节点)
{
如果(节点!=NULL)
{
如果(节点->数据!=NULL)
{        
printf(“%s”,节点->数据);
}
}
}
到目前为止还不能打印出任何内容。我几乎可以肯定这是一个指针问题。如果有人能给我指出正确的方向(没有双关语),我将不胜感激


谢谢

首先,我假设
List
struct conscell*
的类型定义。如果不是,它应该是,否则你的代码在没有大量警告的情况下无法编译

scheme cons单元格应该是简单的单链接列表,而不是双链接列表。所以你的单个细胞应该更像:

typedef conscell 
{
    unsigned char *data;   //<== use unsigned char for a memory buffer
    struct conscell* next; //<== only a "next" pointer needed
} conscell;
void printList(List node)
{
    List current = node;

    while (current != NULL)  //<== guard for the end-of-list
    {
      if (node->data != NULL)
      {        
        printf("%s", node->data);
      }

      current = current->next; //cycle to the next node in the linked list
    }
}
正在递归地添加cons单元格作为“第一个”和“剩余”。。。但链表不是这样的。它应该有一个指向列表节点的指针作为列表的“头”(而不是像您在这里所做的那样的另一个cons单元格),然后列表中的每个节点都指向一些数据和列表中的下一个节点

接下来,使用
createList()
函数分配内存时,内存会到处泄漏,但永远不要删除该内存(即,您有类似
node=NULL
的代码,这实际上是内存泄漏,因为您丢失了对
node
最初指向的已分配内存位置的内存引用)。在将
NULL
分配给节点指针之前,必须在节点指针上调用
free()

最后,
printList()
除了打印传递给它的列表的第一个元素外,什么都不做……没有递归调用或循环循环到链接列表中的下一个节点。因此,使用该函数不会打印太多内容。它应该更像:

typedef conscell 
{
    unsigned char *data;   //<== use unsigned char for a memory buffer
    struct conscell* next; //<== only a "next" pointer needed
} conscell;
void printList(List node)
{
    List current = node;

    while (current != NULL)  //<== guard for the end-of-list
    {
      if (node->data != NULL)
      {        
        printf("%s", node->data);
      }

      current = current->next; //cycle to the next node in the linked list
    }
}
void打印列表(列表节点)
{
列表当前=节点;
while(当前!=NULL)//数据!=NULL)
{        
printf(“%s”,节点->数据);
}
当前=当前->下一步;//循环到链接列表中的下一个节点
}
}

综上所述,1)您的cons数据结构应该表示一个单链接列表,该列表由具有数据元素和指向下一个节点的指针的结构数据类型组成。cons’ed列表通过指向第一个节点的头指针进行访问。2) 解析输入时,应该将节点添加到链表的前面,因为Scheme的
cons
操作以及Scheme中的所有操作都是递归的,“向右折叠”,这意味着它们从基本情况(即两个元素的组合)开始工作,然后在该基本情况下展开。因此,如果您有类似于
(cons'd(cons'c)(cons'b(cons'a)(щщ))
,那么您需要打印列表
(dcba)
。如果您愿意,还可以在递归解析输入时将令牌放入堆栈,然后从堆栈输入放入链接列表(类似于RPN计算器的工作方式)。

还可以将\n添加到printf,以确保将其刷新到标准输出:

printf("%s\n", node->data);

那不是一个囚室;cons单元只有两个成员,
car
cdr
nextNode
中也存在内存泄漏。您还将指针复制到一个缓冲区,该缓冲区随后会被覆盖。-1:您是否尝试过在调试器中单步执行代码?或者添加printf语句来显示代码中变量的值?另外,您还没有提供
List
的定义@larsmans感谢您的反馈,现在更有意义了。@Oli Charlesworth是的,我在整个代码中使用printf语句来显示不同的值,但没有注意到缓冲区每次都被覆盖。当我发布问题时,我把它们拿了出来。忘了提一下,列表是conscellWow的typedef,非常感谢您的深入回复。我应该提到的是,我正在寻找一个递归下降解析器,这会改变什么吗?它与使用单链表有什么不同吗?我喜欢堆叠的主意,谢谢。今晚我们将使用您的建议来解决这个问题。递归解析器和单链表是两个不同的东西。你在储存你的犯罪记录