天气查询项目(cJOSN)

ops/2025/3/11 4:55:17/

一.功能

二.cJOSN使用规则

1.cJOSN介绍

JSON对象是一个无序的"名称/值"键值对的集合:

  • 以"{“开始,以”}"结束,允许嵌套使用;
  • 每个名称和值成对出现,名称和值之间使用":"分隔;
  • 键值对之间用","分隔
  • 在这些字符前后允许存在无意义的空白符;

对于键值,可以有如下值:

  • 一个新的json对象
  • 数组:使用"[“和”]"表示
  • 数字:直接表示,可以是整数,也可以是浮点数
  • 字符串:使用引号"表示
  • 字面值:false、null、true中的一个(必须是小写)

  • 示例如下:

    {

        "name": "mculover666",

        "age": 22,

        "weight": 55.5

        "address":

        {

            "country": "China",

            "zip-code": 111111

        },

  • "skill": ["c", "Java", "Python"],

        "student": false

    }

2.cJOSN的输出

一段完整的JSON数据就是一条长长的链表,那么,如何打印出这段JSON数据呢?

cJSON提供了一个API,可以将整条链表中存放的JSON信息输出到一个字符串中:

(char *) cJSON_Print(const cJSON *item);

使用的时候,只需要接收该函数返回的指针地址即可。

封装数据和打印数据示例

单纯的讲述方法还不够,下面用一个例子来说明,封装出开头给出的那段JSON数据:

#include <stdio.h>

#include "cJSON.h"

int main(void)

{

    cJSON* cjson_test = NULL;

    cJSON* cjson_address = NULL;

    cJSON* cjson_skill = NULL;

    char* str = NULL;

    /* 创建一个JSON数据对象(链表头结点) */

    cjson_test = cJSON_CreateObject();

    /* 添加一条字符串类型的JSON数据(添加一个链表节点) */

    cJSON_AddStringToObject(cjson_test, "name", "mculover666");

    /* 添加一条整数类型的JSON数据(添加一个链表节点) */

    cJSON_AddNumberToObject(cjson_test, "age", 22);

    /* 添加一条浮点类型的JSON数据(添加一个链表节点) */

    cJSON_AddNumberToObject(cjson_test, "weight", 55.5);

    /* 添加一个嵌套的JSON数据(添加一个链表节点) */

    cjson_address = cJSON_CreateObject();

    cJSON_AddStringToObject(cjson_address, "country", "China");

    cJSON_AddNumberToObject(cjson_address, "zip-code", 111111);

    cJSON_AddItemToObject(cjson_test, "address", cjson_address);

    /* 添加一个数组类型的JSON数据(添加一个链表节点) */

    cjson_skill = cJSON_CreateArray();

    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C" ));

    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Java" ));

    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Python" ));

    cJSON_AddItemToObject(cjson_test, "skill", cjson_skill);

    /* 添加一个值为 False 的布尔类型的JSON数据(添加一个链表节点) */

    cJSON_AddFalseToObject(cjson_test, "student");

    /* 打印JSON对象(整条链表)的所有数据 */

    str = cJSON_Print(cjson_test);

    printf("%s\n", str);

    return 0;

}

3.cJOSN的解析方法

解析JSON数据的过程,其实就是剥离一个一个链表节点(键值对)的过程。

解析方法如下:

  •  创建链表头指针:

cJSON* cjson_test = NULL;

  •  解析整段JSON数据,并将链表头结点地址返回,赋值给头指针:

解析整段数据使用的API只有一个:

(cJSON *) cJSON_Parse(const char *value);

  •  根据键值对的名称从链表中取出对应的值,返回该键值对(链表节点)的地址

(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);

  •  如果JSON数据的值是数组,使用下面的两个API提取数据:

(int) cJSON_GetArraySize(const cJSON *array);

(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);

解析示例

下面用一个例子来说明如何解析出开头给出的那段JSON数据:

#include <stdio.h>

#include "cJSON.h"

char *message = 

"{                              \

    \"name\":\"mculover666\",   \

    \"age\": 22,                \

    \"weight\": 55.5,           \

    \"address\":                \

        {                       \

            \"country\": \"China\",\

            \"zip-code\": 111111\

        },                      \

    \"skill\": [\"c\", \"Java\", \"Python\"],\

    \"student\": false          \

}";

int main(void)

{

    cJSON* cjson_test = NULL;

    cJSON* cjson_name = NULL;

    cJSON* cjson_age = NULL;

    cJSON* cjson_weight = NULL;

    cJSON* cjson_address = NULL;

    cJSON* cjson_address_country = NULL;

    cJSON* cjson_address_zipcode = NULL;

    cJSON* cjson_skill = NULL;

    cJSON* cjson_student = NULL;

    int    skill_array_size = 0, i = 0;

    cJSON* cjson_skill_item = NULL;

    /* 解析整段JSO数据 */

    cjson_test = cJSON_Parse(message);

    if(cjson_test == NULL)

    {

        printf("parse fail.\n");

        return -1;

    }

    /* 依次根据名称提取JSON数据(键值对) */

    cjson_name = cJSON_GetObjectItem(cjson_test, "name");

    cjson_age = cJSON_GetObjectItem(cjson_test, "age");

    cjson_weight = cJSON_GetObjectItem(cjson_test, "weight");

    printf("name: %s\n", cjson_name->valuestring);

    printf("age:%d\n", cjson_age->valueint);

    printf("weight:%.1f\n", cjson_weight->valuedouble);

    /* 解析嵌套json数据 */

    cjson_address = cJSON_GetObjectItem(cjson_test, "address");

    cjson_address_country = cJSON_GetObjectItem(cjson_address, "country");

    cjson_address_zipcode = cJSON_GetObjectItem(cjson_address, "zip-code");

    printf("address-country:%s\naddress-zipcode:%d\n", cjson_address_country->valuestring, cjson_address_zipcode->valueint);

    /* 解析数组 */

    cjson_skill = cJSON_GetObjectItem(cjson_test, "skill");

    skill_array_size = cJSON_GetArraySize(cjson_skill);

    printf("skill:[");

    for(i = 0; i < skill_array_size; i++)

    {

        cjson_skill_item = cJSON_GetArrayItem(cjson_skill, i);

        printf("%s,", cjson_skill_item->valuestring);

    }

    printf("\b]\n");

    /* 解析布尔型数据 */

    cjson_student = cJSON_GetObjectItem(cjson_test, "student");

    if(cjson_student->valueint == 0)

    {

        printf("student: false\n");

    }

    else

    {

        printf("student:error\n");

    }

    

    return 0;

}

编译:

gcc cJSON.c example2.c -o example2.exe

运行结果如图:

三.函数代码

1.getch函数

  1. 获取当前终端属性:使用 tcgetattr(STDIN_FILENO, &oldt) 获取当前终端的属性,并存储在 oldt 结构体中。

  2. 复制旧属性:将 oldt 的内容复制到 newt 中,以便修改。

  3. 修改终端属性:通过 newt.c_lflag &= ~(ICANON | ECHO) 修改 newt 结构体中的 c_lflag 字段,去除 ICANONECHO 标志。ICANON 表示规范模式(canonical mode),在这种模式下,输入是缓冲的,直到按下回车键才会读取。去除 ICANON 标志后,输入将不被缓冲,可以立即读取。ECHO 标志表示是否回显输入到终端,去除 ECHO 标志后,输入的字符不会显示在终端上。

  4. 设置新的终端属性:使用 tcsetattr(STDIN_FILENO, TCSANOW, &newt) 立即应用新的终端属性。

  5. 读取字符:使用 getchar() 函数从标准输入读取一个字符,存储在变量 ch 中。

  6. 恢复终端属性:使用 tcsetattr(STDIN_FILENO, TCSANOW, &oldt) 恢复原来的终端属性,确保终端状态不会因为这个函数的调用而永久改变。

  7. 返回读取的字符:函数返回读取的字符。

这个函数通常用于需要从键盘读取单个字符而不显示输入的应用中,例如在编写简单的文本编辑器或游戏时。

2.一级菜单打印函数(VCT100)

使用vct100

使用频率高的总结:

VT100控制码归类如下。

\33[nA 光标上移n行

\33[nB 光标下移n行

\33[nC 光标右移n行

\33[nD 光标左移n行

\33[1m 设置高亮度

背景颜色范围:40----49

40:黑

41:深红

42:绿

43:黄色

44:蓝色

45:紫色

46:深绿

47:白色

  前景字符颜色:30-----------39

30:黑

31:红

32:绿

33:黄

34:蓝色

35:紫色

36:深绿

37:白色

3.功能选择函数(VCT100)

4.解析实时天气cJOSN函数

【1】进入www.api.k780.com实时天气网站

【2】选择功能,通过测试实例进入查询

【3】F12相当于wireshark跟踪tcp数据获得返回数据头

【1】函数中传入socket的fd

【2】将传入的的地址和请求头发送给服务器

(1)注意格式为字符串数组,每个字符串以\r\n结尾,最后一个字符串由\r\n\r\n结尾

(2)第一行字符串为weaid=%s,%s为需要查询的地址名

appkey和sign为服务器提供给用户的

【3】将读入的数据存入buf中

【4】数据以键值对的形式存储,使用cJOSN解析

【1】strstr:

  1. 使用 strstr 函数在 buf(可能是一个包含响应数据的字符串)中查找第一个 { 字符,这通常表示JSON对象的开始。
  2. 如果找不到 {,则打印错误消息 "No JSON found in respon

【2】解析JSON

  • 使用 cJSON_Parse 函数解析找到的JSON字符串。

  • 如果解析失败(即 rootNULL),则打印错误消息 "JSON解析失败"

【3】检查success字段

  • 从解析后的JSON对象中获取 success 字段。

  • 如果 success 字段不存在或其值不是字符串 "1",则打印错误消息 "请求失败",并删除解析后的JSON对象,然后退出函数。

【4】获取result对象

  • 从解析后的JSON对象中获取 result 对象。

  • 如果 result 对象不存在,则打印错误消息 "无天气数据",并删除解析后的JSON对象

【5】获得天气数据

  • 定义一个 cJSON * 类型的数组 items,用于存储从 result 对象中获取的各个天气数据项。

  • 使用 cJSON_GetObjectItem 函数从 result 对象中获取以下天气数据项:

    • citynm:城市名称

    • week:星期

    • temperature:日温

    • temperature_curr:时温

    • humidity:湿度

    • aqi:空气质量指数(AQI)

    • weather:天气状况

    • wind:风向

    • winp:风力

    • days:日期

  【6】各个部分的作用

  • strstr(buf, "{"):在 buf 中查找第一个 { 字符,表示JSON对象的开始。

  • cJSON_Parse(json_str):解析JSON字符串,生成一个 cJSON 对象。

  • cJSON_GetObjectItem(root, "success"):从JSON对象中获取 success 字段,用于检查请求是否成功。

  • cJSON_GetObjectItem(result, ...):从 result 对象中获取各种天气数据项。

  • cJSON_Delete(root):删除解析后的JSON对象,释放内存。

【7】打印表格

5.解析未来天气cJOSN函数

  1. 提示用户输入日期

    • 定义一个字符数组 date,用于存储用户输入的日期。

    • 使用 printf 函数提示用户输入日期,格式为 YYYY-MM-DD

    • 使用 scanf 函数从标准输入读取用户输入的日期,并存储在 date 数组中。

  2. 遍历result数组,查找对应日期的天气信息

    • 定义一个整型变量 found,用于标记是否找到匹配的日期,初始值为0(未找到)。

    • 使用 cJSON_GetArraySize(result) 获取 result 数组的大小,即包含的天气信息条目数。

    • 使用 for 循环遍历 result 数组中的每个条目。

    • 对于每个条目,使用 cJSON_GetArrayItem(result, i) 获取对应的JSON对象,并存储在 day 指针中。

    • 如果 dayNULL,则跳过当前条目,继续下一个条目。

  3. 提取日期并检查是否匹配

    • day 对象中获取 days 字段,该字段包含日期信息。

    • 如果 daysNULL,则跳过当前条目,继续下一个条目。

    • 打印调试信息,显示JSON中的日期。

    • 使用 strcmp 函数比较JSON中的日期和用户输入的日期是否匹配。

    • 如果日期匹配,则将 found 变量设置为1(找到匹配的日期),并继续提取天气信息。

  4. 提取天气信息

    • 如果找到匹配的日期,则从 day 对象中提取以下天气信息:

      • week:星期

      • citynm:城市名称

      • temperature:温度

      • humidity:湿度

      • weather:天气状况

      • wind:风向

      • winp:风力

5.各个部分的作用

  • char date[20];:定义一个字符数组,用于存储用户输入的日期。

  • printf("请输入要查询的日期(格式:YYYY-MM-DD):");:提示用户输入日期。

  • scanf("%s", date);:从标准输入读取用户输入的日期。

  • int found = 0;:定义一个整型变量,用于标记是否找到匹配的日期。

  • int num_days = cJSON_GetArraySize(result);:获取 result 数组的大小。

  • for (int i = 0; i < num_days; i++):遍历 result 数组中的每个条目。

  • cJSON_GetArrayItem(result, i):获取 result 数组中的第 i 个条目。

  • cJSON_GetObjectItem(day, "days"):从 day 对象中获取 days 字段,包含日期信息。

  • strcmp(days->valuestring, date) == 0:比较JSON中的日期和用户输入的日期是否匹配。

  • cJSON_GetObjectItem(day, ...):从 day 对象中提取各种天气信息字段。

三.主函数实现二级菜单打印和用户操作界面


http://www.ppmy.cn/ops/164841.html

相关文章

捌拾贰- 贝尔不等式 (2)

1. 贝尔不等式理解 我感觉我前期理解的不是很对 柒拾玖- 贝尔不等式 … 思来想去几天&#xff0c;感觉贝尔不等式应该是这样来的 因为观测的值只有可能是 1 (别问我为什么) , 设观测角度 Q 值为 1 的概率为 a , -1 的概率为 b , Q 的数学期望值为 E(Q) a * 1 b * (-1) a…

laravel中 添加公共/通用 方法/函数

一&#xff0c;现在app 下面创建Common目录&#xff0c;然后在创建Common.php 文件 二&#xff0c;修改composer.json文件 添加这个到autoload 中 "files": ["app/Common/Common.php"]"autoload": {"psr-4": {"App\\": &quo…

Linux 入门:常用命令速查手册

目录 一.指令 1.pwd&#xff08;显示所在路径&#xff09; 2.ls&#xff08;列出所有子目录与文件&#xff09; 3.touch&#xff08;创建文件&#xff09; 4.mkdir&#xff08;创建目录&#xff09; 5.cd&#xff08;改变所处位置&#xff09; 6.rm&#xff08;删除&…

两数之和 力扣1

一、题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。 你可以按任意顺序返回答案…

[项目]基于FreeRTOS的STM32四轴飞行器: 五.Motor驱动

基于FreeRTOS的STM32四轴飞行器: 五.Motor驱动 一.配置CubeMX二.Motor驱动3.bug修改 一.配置CubeMX 观察motor原理图引脚对应的TIM&#xff1a; 使用内部时钟&#xff0c;配置4分频&#xff0c;后为18M&#xff0c;在设置Counter Period为1000-1&#xff0c;之后频率为18K&am…

游戏引擎学习第139天

决定做一个音频混音器 我们正在进行一个完整的游戏开发&#xff0c;完全从零开始&#xff0c;不使用任何游戏引擎或第三方库&#xff0c;而是亲手实现所有底层技术。目前&#xff0c;我们正处于一个决策点&#xff0c;思考接下来的开发方向。在上一次的开发过程中&#xff0c;…

解决电脑问题(1)——硬件问题

电脑硬件出现问题可以按照以下思路和方法进行解决&#xff1a; 电源问题 症状&#xff1a;电脑完全无法开机&#xff0c;电源指示灯不亮&#xff0c;风扇不转。检查方法&#xff1a;首先检查电源插头是否插紧&#xff0c;尝试更换一个电源插座&#xff0c;看是否能解决问题。如…

家政小程序源码功能方案详细php

家政小程序功能方案详解&#xff0c;开发语言后端php&#xff0c;前端uniapp&#xff0c;九九网络技术独立开发系统&#xff0c;可以源码搭建&#xff0c;也可以二开、定制开发。选择多样性。 核心功能模块&#xff1a; 一用户端&#xff1a;小程序 1.选择服务&#xff1a;服务…