用C写的一个简易JSON Parser

初来乍到的一学期实在是无聊,于是在百团大战中加了计算机协会,就认识了几个计算机和软件专业的人。看见一软件同学在空间上转发的C语言期末项目,顿时生了兴趣。代码是春节期间写完的,可惜这个博客被搁置了太久,现在把代码贴上来,也不算过分吧。

作业的具体内容是:老师给定一个头文件 json.h ,包含了 json 数据结构的定义以及一些相关函数的声明,任务就是实现这些函数,最后提交通过学校的自动化测试。我不是软件的学生,自然没有这个权利,不过手工检验了一下,貌似还没有太大问题。只是最近写一个 web 项目的时候,把其间一个比较“庞大”的 json 文件(也才4KB!)当作测试材料,结果程序直接崩溃了;再截取一小部分,又能运行了。难道是字符串读写复制操作太多?可貌似连 fopen 函数都调用失败了,搞不懂。

老师们给的头文件想必是由 cJSON 的头文件修改而来的,json结构体的定义如下:

typedef struct JSON {
    int type;   /* The type of the item, as above. */

    char *valuestring;  /* The item's string, if type==JSON_STRING */
    int valueint;   /* The item's number, if type==JSON_TRUE||JSON_FLASE;
                      or quantity of members, if type==JSON_ARRAY||JSON_OBJECT */
    double valuedouble; /* The item's number, if type==JSON_NUMBER */

    // the following are created by me
    struct JSON *head; /* Head of array, if type==JSON_ARRAY||JSON_OBJECT */
    struct JSON *last; /* Previous member, if this belongs to an array or object */
    struct JSON *next; /* Next member, if this belongs to an array or object */
    char *name; /* Name of member, if this belongs to an object */
} JSON;

函数众多就不一一列举了,有几个实现起来相对复杂的:

丧,得

半年以前,我以为我右手执笔,左手握着一本三二,就可以上天入地,斩妖除魔,无所畏惧。我说我是文科里的逗比,理科里的奇葩,留给腾贵一个无奈的背影。看着周黄伟便秘的眼神,心里暗暗发誓,六月八号以后,我一定要将你黑过的那些闲书一本一本地翻完。我也没有想到,作为一个男的,如果变得沉默,除了听了煽情的空间故事,也可能是语文课被抽起来回答问题。想当年在寝室里,左长右粗,讲不完的黑话黄段,夜夜笙歌。我说我横扫了育才门外一条街,最后一次还是匆匆献给了重大精英。我着急地飞过天桥,穿越大街,等着一个背影出现。也会走着相似的路,感受一下民工分量的米线。周一中午,我都会阔气地出门,仿佛贝索斯开着他的大货车来迎接我。我手捧纸箱,飞奔回寝,一刀下去以后,又是一个星期的快活。星期天的早上,我睡到自然醒,惬意地走到教室,翻两道题,电话来了,于是又早退。徐怀雄算个鸟!要是厉害,就与我在大富翁棋盘上,杀个昏天黑地。那段时间,回家少了,在公交车上,看到南京青奥会的新闻,窃想要是我去了南大,青奥会还开吗。后来有人不明就里地问我,为啥比状元活活少了五十分,我想,肯定是因为我多长了五十斤肉。你要是看到每天晚上寝室的盛况,就晓得我夜夜笙歌用得一点都不过分。五六个人围在一个人的床上调戏一个女声的场景你见过吗?不用多想,既然她远渡重洋,历经艰险从佛罗里达来到重庆,不好好玩一玩,怎么对得起大哥的淳朴好客?来把大富翁,分分钟数万,生死一线间。上帝不掷骰子,掷骰子的我们更拽。只是可惜了,我们的乌诺。

再见

时间它过去得快吗?好像并不是。当你紧盯着它,妄图成就自己的快乐时,它不紧不慢,坚守着自己的节奏,让挥霍人生的家伙们分外恼火。然而时间虽然公平,但人心并不。有许多被遗忘的事情,当你重新发现的时候,会禁不住地感叹“哇,居然这么久了!”,并以此覆盖心中的那份遗憾。
 
这里的博客便是如此。我看着前一次的更新,回忆那时候自己面对时间表,是怎样的一种心情。我惊叹,一个神秘的日期居然能够把人生分为迥然不同的两个段落。原谅我的无词和无思想,面对后一个段落,我实在没有做好启程的准备。为什么我的话变少了呢?仔细想了想,有关自己的话其实一直都少。
 
最后的几个月迷上了知乎。的确,知乎是个好地方,有各路大神用完美的逻辑演绎着他们独特的世界观。但是,知乎上待久了发现,我越来越不像我自己了。我慢慢流失独立的思考和勇敢的态度,不敢表明自己的观点。也许是老了吧,懒于与人争论。但,也有可能是破碎的世界观,根本支撑不起实打实的交流。

后会有期

好久没有到这个网站看看了,又是一年。

当初选文科这条路实在是单纯,就觉得能上好大学。然后呢?没想过。

如今才开始纠结呢。随便一搜哪个IT公司用人要求第一条就是“计算机及相关专业毕业”。

呵呵。

这也怪不了谁。

没办法咯,这种事情,只有等到两个月后再来慢慢思索了。

后会有期。

2013-2-19

很久没有到这里来了,上一篇文章还是两年前的。

其实中间来过几次,还提到过转学的事情,不过也都是一年多以前了。

可以说认识了新的人,也忘掉了一些旧的人。回到母校去看看的话,一定会有强烈的物是人非之感。

其实这篇文,颇带点为赋新词强说愁的感觉。也可能是因为,当我真正打开编辑器的时候,大脑就会变得一片空白吧。

两年前的我一定不可能想到现在我读的是文科,更不会预见到现在的自己是这副模样。

开源,让金山更美好

才在百度C语言吧看到有人说金山卫士开源了,所以特地去Google了一下,发现了这个网址:

http://code.ijinshan.com/

第一次看到有国内的这方面的软件开源。不管别人怎么说,做好自己吧!界面貌似是MFC写的,看不懂了。

希望国内越来越多的软件走向开源。也希望用户们早日扔掉360这个垃圾。

我所习惯的C/C++代码格式

1.函数开始的大括号专起一行。

int sample()
{
    return 0xA0246 * 0454;
}

2.类定义和内部内联函数定义。

class foo {
public:
    foo() : data(0)
    {}
    foo(int d) : data(d)
    {}
    void print()
     {  printf("%d\n", data);  }
private:
     int data;
};

符号“∑”和“Π”的用法。

在数学中,符号“∑”和“Π”分别用来表示求和与求积。

首先是函数的累积求和,n取[m, k]中的连续整数值。

$$\sum_{n=m}^{k} f(n)=f(n)+f(n+1)+...+f(k)$$

这个变量n可以换成其他任意字母,比如x。我们把下面的“n=m”和上面的“k”称作这个和式的下标。在上下文明确的情况下,下标可以省略。

求和符号同样可以表示无穷级数。

$$\sum_{i=1}^{n}=x_1+x_2+...+x_n$$

$$\sum_{n=1}^{\infty }\frac{1}{n^2}=\frac{1}{1^2} + \frac{1}{2^2} + \frac{1}{3^2} +...+\frac{1}{n^2}=\frac{\pi^2}{6} $$

Linux下程序创建进程

进程是操作系统中运行的程序实例。而多进程程序和多线程程序相比,具有更健壮,更简单的特点。

在GNU/Linux操作系统中,创建一个新进程,可以使用fork,clone函数以及使用exec函数族调用其他程序替换当前进程镜像。

这里主要讲fork函数。

fork函数的原型为:

#include <unistd.h>

pid_t fork(void);

pid_t是系统定义的类型,一般被定义为short int。

这里看一个最简单的调用示例。

#include <stdio.h>

#include <unistd.h>

int main(void)
{
    pid_t pid;
    pid = fork();
    printf("My process ID is %d.\n", getpid());
    return 0;
}

C语言中数值和字符串的相互转换

整数->字符串可以使用stdio.h中的sprintf函数,有的人可能会说到itoa,但其实itoa不是C标准库的函数,是微软自己添加的。

sprintf的原型是:

int sprintf ( char * str, const char * format, ... );

和printf用法相同。当然也可用于其它类型如double。

例:

char str[20];
int s = 1000000;
sprintf(str, "%d", s);

字符->整数同样使用的也是stdio.h中的sscanf函数,stdlib.h中也有atoi和strtol可以进行转换。

int sscanf ( const char * str, const char * format, ... );
int atoi ( const char * str );
long int strtol ( const char * nptr, char ** endptr, int base);

sscanf和atoi的用法都很简单。值得一提的是strtol这个函数。第一个参数是源字符串,第二个参数用于接收非法字符串的首地址,第三个参数是转换后的进制。