/* * stacks.h * Header file for stack operations */ #ifndef STACKS_H #define STACKS_H 1 struct stack_struct { struct StkElement *base; /* point to base of stack */ int stack_size; /* number of elements */ int min_stack; /* bottom-most element */ int max_stack; /* last possible element */ int top; /* current top */ }; typedef struct stack_struct Stack; extern void ClearStack(Stack *); extern Stack* CreateStack(int); extern int PopElement( Stack *, struct StkElement *); extern int PushElement( Stack *, struct StkElement *); extern struct StkElement * ViewElement( Stack *, int ); /* * Application-specific material goes below */ extern struct StkElement{ int line_no; char opener; }; /* 阅读后注释: 1.栈和队列都是简单的线性数据结构,可以使用链表或数组表示。链表允许无限地调整大小, 而数组则要求在开发过程的早期就确定一个最大大小。对于栈和队列,建议在编译时而不是 运行时确定最大大小,因此,数组是实现这些数据结构的合理方式,也一种就是通过缓冲池 或是使用一个空闲的回收链负责动态的分配而不是每次都向操作系统申请和释放. 2.这里显示定义StkElement结构,我们也可以参考双向链的方式使用void*以使得可以更容易 扩展 */ #endif /* * stacks.c * Primitives for array-based stacks */ #include <stdlib.h> #include <string.h> #include <assert.h> #include "stacks.h" /* * clear the stack by pointing the top of the stack * at an invalid item; that is, the stack is empty. */ void ClearStack(Stack *this_stack) { this_stack->top = -1; } /* * allocate the stack, set the maximum and minimum bounds * on the stack, and show that the stack is empty. */ Stack *CreateStack( int how_many ) { Stack *pstk; assert( how_many>0 ); /* make sure the size is legal */ pstk = (Stack*) malloc(sizeof(Stack)); pstk->base = (struct StkElement*) malloc(how_many*sizeof(struct StkElement)); if (pstk->base==NULL) /* error in allocating stack */ return NULL; pstk->min_stack = 0; pstk->max_stack = how_many-1; ClearStack(pstk); return pstk; } /* * pop an element from the stack. If stack is not already empty. * copy the element, and decrement stack top. */ int PopElement(Stack *this_stack, struct StkElement *destination) { if ( this_stack->top==-1) /* stack empty, return error */ return 0; memmove(destination, &((this_stack->base)[this_stack->top]), sizeof(struct StkElement)); this_stack->top -= 1; return 1; } /* * push an element onto the stack. If stack is not already full, * point StackTop to the next slot, and copy the new element. */ int PushElement(Stack *this_stack, struct StkElement *to_push) { /* is stack full? */ if (this_stack->top==this_stack->max_stack) return 0; this_stack->top+=1; memmove(&((this_stack->base)[this_stack->top]), to_push, sizeof(struct StkElement)); return 1; } /* * view an element on the stack, Function is passed a value that * specifies the element's position in terms of its distance * from the top. 0 is the top, 1 is the element below the top. * 2 is the element below that. If an invalid value is passed. * the function returns NULL; otherwise, it returns a pointer to * the requested element. */ struct StkElement* ViewElement( Stack *this_stack, int which_element ) { if (this_stack->top==-1) return NULL; if (this_stack-which_element<0) return NULL; return &((this_stack->base)[this_stack->top-which_element]); } /* * 阅读后注释: * 这里拷贝使用memmove,memmove与memcpy一样对内存块进行拷贝,但是memmove对于重叠内存区域的拷贝 * 是100%正确,而memcpy可能就会导致结果有误.因此,若是包含重叠内存区域的拷贝请使用memmove */ /* * braces.c * Checks that braces, brackets, and parentheses are properly * paired in a C program. If they're not, an error message * is printed to stderr saying at what line the unmatched * opening item is found. Uses a stack. * * Usage: brances filename.ext */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "stacks.h" int main(int argc, char *argv[]) { FILE *fin; /* file we'll be reading from */ char buffer[128]; /* read file into this buffer */ int line_count; /* current line count */ struct StkElement *stk_el; /* sratch stack element */ Stack *stk; /* the stack we will use */ char ch; /* character we're examining */ int i; /* for loop count */ if (argc!=2) { fprintf( stderr, "Usage: braces filename.ext/n" ); exit( EXIT_FAILURE ); } fin = fopen( argv[1], "rt" ); if (fin==NULL) { fprintf( stderr, "Cannot open/find %s/n", argv[1]); exit( EXIT_FAILURE ); } /* Create and initialize the stack */ stk = CreateStack(40); /* create a stack of 40 items */ if (stk==NULL) { fprintf( stderr, "Insufficient Memory/n" ); exit( EXIT_FAILURE ); } /* Create the scratch stack element */ stk_el = (struct StkElement *)malloc( sizeof(struct StkElement)); if (stk_el==NULL) { fprintf( stderr, "Insufficient memory/n"); exit(EXIT_FAILURE); } line_count = 0; while( !feof(fin)) { /* read a line of a C program */ if (fgets(buffer, 127, fin)==NULL) break; line_count += 1; /* scan and process braces, brackets, and parenthese */ for (i=0; buffer[i]!='/0'; i++) { switch (ch=buffer[i]) { case '(': case '[': case '{': stk_el->opener = ch; stk_el->line_no = line_count; if (!PushElement(stk, stk_el)) { fprintf(stderr, "Out of stack space/n"); exit(EXIT_FAILURE); } break; case ')': case ']': case '}': if (!PopElement(stk, stk_el)) fprintf(stderr, "Stray %c at line %d/n", ch, line_count); else if ( (ch==')'&&stk_el->opener!='(')|| (ch==']'&&stk_el->opener!='[')|| (ch=='}'&&stk_el->opener!='{')) fprintf(stderr, "%c at line %d not matched by %c at line %d/n", ch, line_count, stk_el->opener, stk_el->line_no); break; default: continue; } } } /* we are at the end of file. Are there unmatched items? */ if ( ViewElement( stk, 0)!=NULL ) { while (PopElement(stk, stk_el)!=0) fprintf(stderr, "%c from line %d unmatched/n", stk_el->opener, stk_el->line_no ); } fprintf(stderr, "Error checking complete/n" ); fclose(fin); return EXIT_SUCCESS; } /* * 阅读后注释 * 主程序使用栈实现了一个行列数限制为128的,基本括号匹配检测。 * 此检测相对简单,并不能对注释中包含括号进行正确处理 */