用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;

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

我所习惯的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这个函数。第一个参数是源字符串,第二个参数用于接收非法字符串的首地址,第三个参数是转换后的进制。