C语言数据结构----栈的应用(程序的符号匹配检测)

本节主要讲利用栈来实现一个程序中的成对出现的符号的检测,完成一个类似编译器的符号检测的功能,采用的是链式栈。

一、问题的提出以及解决方法

1.假定有下面一段程序:

#include <stdio.h>
#include <stdlib.h>

int main ()
{
	int a[5][5];
	int(*p)[5];
	
	p = a[0];
	
	printf ("%d", &a[3][3] - &p[3][3]);
} 

这段程序中<>[]{}""这些符号都是成对出现的,假如不是成对出现,那么我的程序在编译的时候将会报错。

2.我们即将要编写的程序的主要目的就是来检测程序中所出现的成对的符号是否都匹配。

3.解决方法:

假定我们要检测的程序是上面的一段程序,那么我们要把每一个字符都进行扫描,当程序遇见字母数字或者非成对的符号的时候直接忽略,当程序遇见了成对出现的符号的左符号时我们将左符号压入栈。当扫描的过程中遇见右括号的时候,我们将栈顶元素弹出,进行匹配,如果匹配程序则继续扫描,如果匹配失败,则报错。如果所有的都匹配成功,那么栈为空且所有字符都扫描失败。如果没有匹配成功,那么就是匹配失败或者栈不为空。

4.算法框架

程序的算法框架如下:

 

二、具体程序的实现

1.程序的具体实现主要采用链式栈的数据结构,同时链式栈是通过复用单向链表来实现的,这些在点击打开链接这篇博文中都有讲解。所以算法实现的主要部分都是在主函数中实现的,也就是我所谓的上层函数。

2.首先采用在主函数中调用其他函数的方式来实现整个程序的运行。

int main()
{
	char *a = "#include <stdio.h> #include <stdlib.h> int main () { int a[5][5]; int(*p)[5]; p = a[0]; printf (\"%d\", &a[3][3] - &p[3][3]); } ";
	scan(a);
	return 0;
}

定义的是一个字符串数组,将字符串数组的首地址传递给scan,这里直接说字符串数组可能不太确切,关于字符和字符串的问题我始终没有搞清楚,拖到了现在。

3.scan函数接部分

(1)scan函数接收的是字符串数组的指针

int scan (char *a) 

(2)调用链式栈的函数进行建栈的操作,返回的是栈指针(因为以后只要涉及到栈的操作都要使用到栈指针)

LinkStack * stack = LinkStack_Create();

(3)因为程序的算法中已经说明,我们要不断的扫描所有的字符,直到整个字符串结束,字符串结束的标志是'\0',这里采用while循环来实现

while (a[i] != '\0')

这里通过传递进来的字符串数组的首地址,我们可以通过这个首地址来定义一个字符数组,然后进行操作。

(4)首先判定数组中的元素是否为成对匹配的符号的左符号,如果是左符号,那么将左符号压进栈。

if (left(a[i]) == 1)
       {
	LinkStack_Push(stack, (void*)(a + i));
       }

在将左符号压进栈的操作中,我们压进栈的是数组元素的地址,这里也是链式栈的可复用性的一个体现。

(5)接下来判定数组中的元素是否为成对匹配的符号的右符号,如果是右符号,那么将栈顶元素弹出,并和相应的右符号进行比较。如果栈顶元素为空或者比较失败,那么将进行报错。

if (right(a[i]) == 1)
{
	char* bijiao = (char*)LinkStack_Pop(stack);
	if ((bijiao == NULL) || !match(*bijiao, a[i]))
	{
		printf ("%c\n", a[i]);
		ret = 0;
		break; 
	}
}

(6)最后,成功的完成了检测的条件是:栈顶为空且已经检测到了最后一个结束符。

if (LinkStack_Top(stack) == NULL && a[i] == '\0')
	{
		printf ("编译成功\n");
	}

(7)程序执行的过程中还有其他几个子函数

1)检测是否为左符号的函数2)检测是否为右符号的函数3)进行比较的函数

三、具体代码

1.程序实现所复用的链式栈的详细代码请看点击打开http://blog.csdn.net/cheyuxuan/article/details/9852779http://blog.csdn.net/cheyuxuan/article/details/10349867部分,这里粘的是主函数的实现部分。由于是菜鸟,所以可能有的代码部分写的比较粗糙,望大家见谅。

2.主函数的实现部分代码:

#include <stdio.h>
#include <stdlib.h>
#include "1.h"

/*******************************************************************************
*函数名:left
*参数:char a 传进来的数组元素 
*返回值:int类型 如果是左侧符号,那么返回1,不是返回0
*功能:判断传进来的字符是否是左侧字符 
*******************************************************************************/
int left (char a)
{
	int ret = 0;
	switch(a)
    {
        case '<':
			ret = 1;
        	break;
        case '(':
			ret = 1;
        	break;
        case '[':
			ret = 1;
        	break;
        case '{':
			ret = 1;
        	break;
        case '\'':
			ret = 1;
        	break;
        case '\"':
            ret = 1;
        	break;
        default:
            ret = 0;
            break;
    }
    return ret;
}

/*******************************************************************************
*函数名:right
*参数:char a 传进来的数组元素 
*返回值:int类型 如果是右侧符号,那么返回1,不是返回0
*功能:判断传进来的字符是否是右侧字符 
*******************************************************************************/
int right (char a)
{
	int ret = 0;
	switch(a)
    {
        case '>':
        case ')':
        case ']':
        case '}':
        case '\'':
        case '\"':
            ret = 1;
        	break;
        default:
            ret = 0;
            break;
    }
    return ret;
}

/*******************************************************************************
*函数名:right
*参数:char a 传进来的数组元素 
*返回值:int类型 如果是右侧符号,那么返回1,不是返回0
*功能:判断传进来的字符是否是右侧字符 
*******************************************************************************/
int match(char bijiao, char a)
{
	int ret = 0;
	int i = 0;
	switch(bijiao)
    {
        case '<':
			ret = (a == '>');
			break;
        case '(':
			ret = (a == ')');
			break;
        case '[':
			ret = (a == ']');
			break;
        case '{':
			ret = (a == '}');
			break;
        case '\'':
			ret = (a == '\'');
			break;
        case '\"':
            ret = (a == '\"');
			break;
        default:
            ret = 0;
            break;
    }
    return ret;
}

/*******************************************************************************
*函数名:scan
*参数:char *a 传进来的字符数组元素的地址
*返回值:int类型 如果是右侧符号,那么返回1,不是返回0
*功能:符号匹配算法的主要实现部分
*******************************************************************************/
int scan (char *a) 
{
	LinkStack * stack = LinkStack_Create();
	int i = 0;
	int ret = 0;
	
	while (a[i] != '\0')
	{
		if (left(a[i]) == 1)
		{
			LinkStack_Push(stack, (void*)(a + i));
		}
		
		if (right(a[i]) == 1)
		{
			char* bijiao = (char*)LinkStack_Pop(stack);
			if ((bijiao == NULL) || !match(*bijiao, a[i]))
			{
				printf ("%c\n", a[i]);
				ret = 0;
				break; 
			}
		}
		i++;	
	}
	
	if (LinkStack_Top(stack) == NULL && a[i] == '\0')
	{
		printf ("编译成功\n");
	}
	else
	{
		printf ("出现错误\n");
	} 
	LinkStack_Destroy(stack);
	
	return ret;
}



int main()
{
	char *a = "#include <stdio.h> #include <stdlib.h> int main () { int a[5][5]; int(*p)[5]; p = a[0]; printf (\"%d\", &a[3][3] - &p[3][3]); } ";
	scan(a);
	return 0;
}
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值