Chinaunix
标题:
如何理解memory-mapped
[打印本页]
作者:
蓝色键盘
时间:
2003-05-07 19:13
标题:
如何理解memory-mapped
如下这段代码编译成功后,使用如下命令:
add lastname
del lastname
find lastname
list
quit
/*
* This program implements a simple address book. It is implemented as a
* binary tree inside a memory-mapped file so that it can survive
* between executions of the program.
*/
#include <stdio.h>;
#include <string.h>;
#include <stdlib.h>;
#include <errno.h>;
/* Header record placed at the start of the storage area. It describes the
free parts and contains the root of the BST. */
struct header
{
int nunused; /* Number of unused blocks. */
int firstun; /* Offset of the first unused block. */
int firstfree; /* First block of the freelist. */
int root; /* Root of the tree. */
};
/* Note that nodes on the free list, when the exist, are linked into a single
linked list using the left pointer of each node, and ignoring the right
pointer. */
/* Form of the tree nodes. */
struct node
{
char lname[20]; /* First name. */
char fname[20]; /* Last name. */
char addr[40]; /* Address. */
char phone[14]; /* Phone number. */
int left, right; /* Tree links. */
};
/* Note that left and right are integers. They represent the byte offset
of the left and right nodes relative to the start of the header. */
/* Macros to convert between offsets relative to the base of the area, and
pointers to node structures. */
#define OFFSET_TO_PTR(base, offset) \
((struct node *)((char *)(base) + (offset)))
#define PTR_TO_OFFSET(base, ptr) \
((char *)(ptr) - (char *)(base))
/* Location record returned by the tree search function. */
struct lrec {
int *plink; /* Where the node found is specified. */
struct node *node; /* The node found, or NULL. */
};
/* Program name. */
char *pname;
/* Number of node records in the storage area. Any portion of them may be
marked free. */
#define NREC 1000
/*
* Store a new header to inialize the space the first time.
*/
void format(char *area)
{
struct header *header = (struct header *)area;
/* Fill in the header information. */
header->;nunused = NREC; /* All records initially unused. */
header->;firstun = /* The first follows immediately. */
sizeof(struct header);
header->;firstfree = 0; /* The free list is empty. */
header->;root = 0; /* The tree is empty. */
}
/*
* Free list operations.
*/
/* Get a free node. The links are cleared. */
struct node *getnode(struct header *head)
{
struct node *retval; /* Return value. */
/* See if there is a node on the free list. */
if(head->;firstfree != 0) {
/* Use it. */
retval = OFFSET_TO_PTR(head, head->;firstfree);
head->;firstfree = retval->;left;
}
else
/* See if there is a node which has never been used. */
if(head->;nunused)
{
/* Use it. */
retval = OFFSET_TO_PTR(head, head->;firstun);
head->;firstun += sizeof(struct node);
--head->;nunused;
}
else
{
/* Cannot allocate. Bye. */
fprintf(stderr, "Allocation failed.\n");
exit(10);
}
retval->;left = retval->;right = 0;
return retval;
}
/* Add a node to the free list. */
void freenode(struct node *node, struct header *head)
{
node->;left = head->;firstfree;
head->;firstfree = PTR_TO_OFFSET(head, node);
}
/* Search the BST for a key. It takes the pointer to the control area, and
returns a locator record which contains enough info to delete, insert, or
just access the node with the indicated key. */
struct lrec locate(struct header *head, char *key)
{
int *locator = &head->;root;
while(1)
{
int cmp; /* Comparison result. */
struct node *node = /* Present node of scan. */
OFFSET_TO_PTR(head, *locator);
/* See if we reached a leaf. */
if(*locator == 0)
{
struct lrec retval = { locator, NULL };
return retval;
}
/* See if we have found the node. */
cmp = strcmp(key, node->;lname);
if(cmp == 0)
{
/* Found. */
struct lrec retval = { locator, node };
return retval;
}
else if(cmp < 0)
/* The key was less than the node. */
locator = &(node->;left);
else
/* The key was greater than the node. */
locator = &(node->;right);
}
}
/* Insert the node n into the tree, using the loc information returned by
locate. Obviously, if insert is passed a bad value for loc, it can
corrupt the tree by inserting in the wrong place. */
insert(struct header *header, struct node *n, struct lrec loc)
{
n->;right = 0;
n->;left = *loc.plink;
*loc.plink = PTR_TO_OFFSET(header, n);
}
/*
* Delete the node described by loc.
*/
delete(struct header *head, struct lrec loc)
{
struct node *node = loc.node;
if(node == NULL) return;
/* Check the cases. */
if(node->;left == 0)
/* Can connect up to right. */
*loc.plink = node->;right;
else if(node->;right == 0)
/* Can connect to left. */
*loc.plink = node->;left;
else
{
/* Two children. Must find a leaf. */
struct node *surr; /* Single child repl. node */
int surroff; /* Offset of surr. */
int *scan = &node->;left; /* Scanner to find it. */
while(1)
{
int rlink = OFFSET_TO_PTR(head, *scan)->;right;
if(rlink == 0) break;
scan = &OFFSET_TO_PTR(head, *scan)->;right;
}
/* Get information about the replacement. */
surroff = *scan;
surr = OFFSET_TO_PTR(head, surroff);
/* Detach the replacement. */
*scan = surr->;left;
/* Link it in place of the doomed node. */
surr->;left = node->;left;
surr->;right = node->;right;
*loc.plink = surroff;
}
/* Return the node to the free list. */
freenode(node, head);
}
/* Print the tree. */
prtree_r(struct header *head, struct node *node)
{
if(node->;left != 0)
prtree_r(head, OFFSET_TO_PTR(head, node->;left));
printf("%s\n", node->;lname);
if(node->;right != 0)
prtree_r(head, OFFSET_TO_PTR(head, node->;right));
}
prtree(struct header *head)
{
if(head->;root == 0)
printf("No entries.\n");
else
prtree_r(head, OFFSET_TO_PTR(head, head->;root));
}
/*
* Prompt and get an answer, and place it into place, which is of size size.
*/
void prompt(char *p, char *place, int size)
{
char buf[200]; /* Temp storage for response. */
int end; /* Loc. of last char. */
printf("%s: ", p);
fgets(buf, sizeof buf, stdin);
end = strlen(buf) - 1;
if(buf[end] == '\n') buf[end] = 0;
strncpy(place, buf, size - 1);
place[size - 1] = 0;
}
/*
* Run the command interpreter.
*/
void commands(char *area)
{
struct header *head = (struct header *)area;
char buf[200];
printf("addrs>; ");
for(;fgets(buf, sizeof buf, stdin) != NULL; printf("addrs>; "))
{
char cmd[21], lname[21];
int ret = sscanf(buf, "%20s %20s", cmd, lname);
if(ret < 1) continue;
if(strcmp(cmd, "add") == 0)
{
/* Return value of locate. */
struct lrec loc;
/* Add an entry. */
struct node *n = getnode(head);
if(ret >; 1) {
printf("Last name: %s\n", lname);
strncpy(n->;lname, lname, sizeof n->;lname);
n->;lname[sizeof n->;lname - 1] = 0;
}
else
prompt("Enter last name",
n->;lname, sizeof n->;lname);
loc = locate(head, n->;lname);
if(loc.node != NULL)
{
printf("There is alredy a %s on file.\n",
lname);
continue;
}
prompt("Enter first name", n->;fname, sizeof n->;fname);
prompt("Enter address", n->;addr, sizeof n->;addr);
prompt("Enter phone", n->;phone, sizeof n->;phone);
insert(head, n, loc);
}
else if(strcmp(cmd, "del") == 0)
{
/* Return value of locate. */
struct lrec loc;
if(ret < 2)
{
printf("Please give a name to delete.\n");
continue;
}
/* Search the tree, and delete. */
loc = locate(head, lname);
if(loc.node == NULL)
printf("%s not found.\n", lname);
else
delete(head, loc);
}
else if(strcmp(cmd, "find") == 0)
{
/* Return value of locate. */
struct lrec loc;
/* Find and print an entry. */
if(ret < 2)
{
printf("Please give a name to find.\n");
continue;
}
/* Search the tree. */
loc = locate(head, lname);
if(loc.node == NULL)
printf("%s not found.\n", lname);
else
{
printf("Last name: %s\n", loc.node->;lname);
printf("First name: %s\n", loc.node->;fname);
printf("Address: %s\n", loc.node->;addr);
printf("Phone: %s\n", loc.node->;phone);
}
}
else if(strcmp(cmd, "list") == 0)
{
printf("The following names are on file:\n");
prtree(head);
}
else if(strcmp(cmd, "quit") == 0)
return;
else
{
printf("No such command %s.\n", cmd);
}
}
}
/*
* Do the work.
*/
int main(int argc, char **argv)
{
/* Get the space. */
char *area = malloc(sizeof(struct header) + NREC*sizeof(struct node));
if(area == NULL)
{
fprintf(stderr, "Allocation failed.\n");
exit(1);
}
/* Format it into an empty phone book. */
format(area);
/* Run commands. */
commands(area);
/* Free the space. */
free(area);
exit(0);
}
复制代码
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2