boost 库中不单单这一种智能指针类型。但只有 shared_ptr 是最接近普通指针的一种智能指针,他具有一些非常良好的特性,比如计数器等等,使用 shared_ptr 可以让我们不用花费精力在内存回收上。其他的一些指针与 shared_ptr 的区别如下表:继续阅读

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

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

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

【实现代码】

以下代码需要用到栈模型链式存储的 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;
}

 

栈(Stack)也是数据存储的一种方式,我们可以将其理解为一种线性的表,只不过他是前去后继的关系,他只能在线性表的尾部插入和取出数据,这个尾部所指的就是栈的栈顶,而最先被存入的数据则是栈底。它具有后进先出、先进后出的特性。表示图如下:

继续阅读

循环链表与单向链表十分相似,两者唯一不同之处就是,循环链表的尾节点的next属性指向了链表的首节点(非头节点,头节点是没有数据的,头节点的下一个有数据的节点我们称为首节点)。他的表现形式有常见的两种,如下图:继续阅读

上文中我们介绍了线性表顺序储存的方式,并给大家画了一幅比较详细的图(虽然看着比较凌乱),本文介绍的是数据储存的另外一种方式“链式储存”,这相当于我们之前提到过的单向链表,但是,本文与上一篇文章一样,都将数据的储存和算法进行了分离。这才是我们真正应该晋级了解的东西,如果只是一个单向链表,不足以我们耗费这么多精力。继续阅读

所谓智能指针,就是可以随便申请而无需管理自动释放,就像 java 或 C# 的垃圾回收机制一样。我们无需关心销毁只管尽情的申请,系统提供了一个 auto_ptr 类可以使用这样的功能。后面我们也会用简单的代码示例介绍 auto_ptr 内部是如何实现的。代码如下:

继续阅读

在C++中,可以定义一个指针,使其指向类成员或成员函数,然后通过指针
来访问类的成员。这包括指向属性成员的指针和指向成员函数的指针。它类似与static成员函数或成员变量,具有共享的属性。每一个实例化的对象都可以借助指向类数据成员的指针来访问指向的数据。它的结构图如下:继续阅读

在C中,我们只了解到有两种传参方式,一种是值传递,另外一种是传递指针,一般情况下我们选择使用指针传递参数。在C++中,又新增了一种传参方式,那就是引用(type &),引用传参给我们带来了更好的体验。那三者的具体区别在哪里呢?继续阅读