前段时间一直在学习内核监控进程创建的知识,虽然成功监视,但一直在内核输出到 DebugView 中,不能通知我们的应用程序来显示指定内容,无论如何也不方便,所以赶在周末参考了 Windows 内核安全与驱动开发 中第五章 “应用与内核通讯” 制作了以下程序。程序主要使用了内核事件 KEVENT 实现同步,更多请参考 Windows 内核安全与驱动开发,程序运行后的效果如下:

继续阅读

这几天开始做项目了,涉及到项目传输时的报文设计,在C/S架构的项目设计中,传递数据一定要有一定的格式,这样服务端和客户端才能区分开来。除了格式以外还要考虑到传递的数据如果是指针怎么办?如果是NULL怎么办?等等问题,这些问题其实有很多中解决方案,本文就介绍一种 ASN.1 编码格式,当然本文没办法大篇幅的介绍 ASN.1 编码的格式、好处等等内容,网络上的资料有很多,本文主要是记录代码上如何实现对基础数据类型的编码,以备以后忘记了具体细节时回来查看。

继续阅读

与 stl 和 boost 库中的链表差不多,都有我们常见的属性,如at、push_back、push_front、erase 等等,操作与我们以前学习过的都大相径庭,所以我只贴出代码,有更多需要可以参考 Qt 帮助文档。下面只是 QList 的代码,其实你把里面 QList 的关键字替换成 QVector 就可以切换成数组形式了。这是 Qt 对为了让大家更方便的使用,所以让接口风格装都保持一致性,只不过在遍历时,vector使用at方法要比遍历链表速度快。

继续阅读

同上一篇文章,我们一样是把以前使用C语言实现的单向链表用模版实现了一次,进一步让我们对模版和C++的封装特性有了了解。对于链表的操作我们不过多介绍了,如果有还不清楚操作的,请看以前介绍链表的文章。

继续阅读

队列是一种先进先出的数据模型,它的应用场景比较常见,比如日常生活中我们打10086的电话需要排队时、吃饭排号时的小票、Windows GUI程序的消息队列等等都是基于队列实现的。先进入队列的也是先从队列出去的。他的模型如下:继续阅读

你在使用编辑器写代码的时候是否思考过这个问题:如果少写了一个大括号或中括号,编辑器就会提示错误,这种做法是怎么做到的呢?

其实这个检测就可以通过栈模型来实现,括号的数量总是匹配出现的,并且都是与最近的一个匹配。我们可以编写代码来实现这个检测的功能。具体实现思路如下:

从第一个字符开始扫描, 当遇见普通字符时忽略,
当遇见左符号时压入栈中
当遇见右符号时从栈中弹出栈顶符号,并进行匹配.
匹配成功:继续读入下一个字符
匹配失败:立即停止,并报错
结束.
------成功: 所有字符扫描完毕,且栈为空
------失败:匹配失败或所有字符扫描完毕但栈非空

【实现代码】

以下代码需要用到栈模型链式存储的 LinkStack.h 和 LinkStack.c 头文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkStack.h"

/***************** 算法思路 *****************
从第一个字符开始扫描, 当遇见普通字符时忽略,
当遇见左符号时压入栈中
当遇见右符号时从栈中弹出栈顶符号,并进行匹配.
匹配成功:继续读入下一个字符
匹配失败:立即停止,并报错
结束.
------成功: 所有字符扫描完毕,且栈为空
------失败:匹配失败或所有字符扫描完毕但栈非空*/

int match(char left, char right)
{
	int ret = 0;
	switch (left)
	{
	case '<':	//左尖括号
		ret = (right == '>');
		break;
	case '(':	//左小括号
		ret = (right == ')');
		break;
	case '[':	//左中括号
		ret = (right == ']');
		break;
	case '{':	//左大括号
		ret = (right == '}');
		break;
	case '\'':	//左单引号
		ret = (right == '\'');
		break;
	case '\"':	//左双引号
		ret = (right == '\"');
		break;
	default:
		ret = 0;
		break;
	}

	//匹配成功返回1,不成功返回0
	return ret;
}

int isRight(char right)
{
	int ret = 0;
	switch (right)
	{
	case '>':	//右尖括号
	case ')':	//右小括号
	case ']':	//右中括号
	case '}':	//右大括号
	case '\'':	//右单引号
	case '\"':	//右双引号
		ret = 1;	//是需要检测的符号返回1
		break;
	default:
		ret = 0;	//不是需要检测的符号返回0
		break;
	}
	return ret;
}

int isLeft(char left)
{
	int ret = 0;
	switch (left)
	{
	case '<':	//左尖括号
	case '(':	//左小括号
	case '[':	//左中括号
	case '{':	//左大括号
	case '\'':	//左单引号
	case '\"':	//左双引号
		ret = 1;	//是需要检测的符号返回1
		break;
	default:
		ret = 0;	//不是需要检测的符号返回0
		break;
	}
	return ret;
}

int read(const char* code)
{
	int i = 0;
	LinkStack* stack = LinkStack_Create();

	while (code[i])
	{
		// 判断是否是左符号
		if (isLeft(code[i]))
		{
			// 是的话就压如栈中
			printf("push = %c\n", code[i]);
			LinkStack_Push(stack, (void*)&code[i]);
			//continue;
		}

		// 判断是否是右符号
		if (isRight(code[i]))
		{
			// 如果是则取出栈顶的符号与这个右符号对比
			char left = *(char*)LinkStack_Top(stack);
			if (match(left, code[i]))
			{
				// 匹配成功,从栈中弹出匹配过的左符号
				printf("pop  = %c\n", code[i]);
				LinkStack_Pop(stack);
			}
			else
			{
				// 匹配失败直接报错并终止循环
				printf("数据异常,匹配失败! left = %c, right = %c\n", left, code[i]);
				break;
			}
		}
		i++;
	}

	// 最后判断栈中是否还有数据,如果还有证明缺少右符号
	if (!LinkStack_Size(stack))
	{
		printf("匹配成功!\n");
	}
	else
	{
		char ch = *(char*)LinkStack_Top(stack);
		printf("缺少匹配 %c\n", ch);
	}
	// 销毁
	LinkStack_Destroy(stack);
	return 0;
}



int main(int argc, char* argv[])
{
	const char* code = "#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0;}";
	read(code);

	return 0;
}