当前位置: 首页 > news >正文

一个自动定位并查询天气的工具(c语言)

一、代码

#include <stdio.h>        // 引入标准输入输出库,用于打印和输入操作
#include <string.h>       // 引入字符串处理库,用于字符串复制、查找等操作
#include <stdlib.h>       // 引入标准库,用于内存分配(malloc/free)等函数
#include <sys/socket.h>   // 引入socket相关库,用于网络通信
#include <netinet/in.h>   // 引入网络地址结构库,用于定义IP地址和端口
#include <netdb.h>        // 引入主机信息库,用于域名解析
#include <unistd.h>       // 引入POSIX系统调用库,用于关闭文件描述符等操作
#include "cJSON.h"        // 引入cJSON库,用于解析JSON数据extern int h_errno;       // 声明外部变量h_errno,用于获取域名解析错误码// HTTP请求函数:向指定主机发送GET请求并返回JSON数据
char* http_get_json(const char* host, const char* path) {struct hostent *ht = gethostbyname(host);  // 解析域名到IP地址(DNS解析)if (!ht) {  // 如果解析失败,打印错误信息并返回NULLfprintf(stderr, "DNS解析失败: %s\n", hstrerror(h_errno));return NULL;}int sockfd = socket(AF_INET, SOCK_STREAM, 0);  // 创建TCP socket(IPv4协议,流式传输)if (sockfd == -1) {  // 如果socket创建失败,打印错误并返回NULLperror("socket创建失败");return NULL;}// 初始化服务器地址结构struct sockaddr_in addr = {.sin_family = AF_INET,       // 使用IPv4地址族.sin_port = htons(80),       // 设置端口为80(HTTP默认端口),转换为网络字节序.sin_addr = *(struct in_addr *)ht->h_addr  // 绑定解析得到的IP地址};// 连接服务器if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {perror("连接服务器失败");  // 连接失败时打印错误close(sockfd);              // 关闭socket释放资源return NULL;}char request[1024];  // 定义HTTP请求缓冲区// 格式化HTTP GET请求内容(包含路径、主机等信息)snprintf(request, sizeof(request),"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path, host);// 发送HTTP请求到服务器if (send(sockfd, request, strlen(request), 0) <= 0) {perror("发送请求失败");  // 发送失败时打印错误close(sockfd);            // 关闭socketreturn NULL;}char *response = malloc(16384);  // 分配内存存储服务器响应(16384字节)if (!response) {  // 如果内存分配失败,打印错误并返回NULLperror("内存分配失败");close(sockfd);return NULL;}int total = 0, n;  // total:已接收总字节数;n:每次接收的字节数// 循环接收服务器响应,直到接收完毕while ((n = recv(sockfd, response + total, 16384 - total - 1, 0)) > 0) {total += n;  // 累加接收的字节数}response[total] = '\0';  // 给响应字符串添加结束符close(sockfd);           // 关闭socketchar *json_start = strstr(response, "{");  // 找到第一个'{'作为JSON起始位置char *json_end = strrchr(response, '}');   // 找到最后一个'}'作为JSON结束位置if (!json_start || !json_end) {  // 未找到JSON起止标志,释放内存返回NULLfree(response);return NULL;}size_t len = json_end - json_start + 2;  // 计算JSON数据长度(包含结束符)char *json = malloc(len);  // 为JSON数据分配独立内存if (!json) {  // 内存分配失败,释放资源返回NULLfree(response);return NULL;}snprintf(json, len, "%s", json_start);  // 复制提取的JSON数据到新缓冲区free(response);  // 释放原始响应缓冲区return json;     // 返回提取的JSON数据
}// 从att字段提取城市名(att格式:"国家,省份,城市")
char* extract_city(const char* att) {if (!att) return NULL;  // 如果att为NULL,直接返回NULLchar *last_comma = strrchr(att, ',');  // 找到最后一个逗号的位置(分割城市名)// 找到逗号返回逗号后子字符串(城市名),否则返回原始字符串return last_comma ? strdup(last_comma + 1) : strdup(att);
}// 获取本机IP对应的城市(通过IP查询API)
char* get_ip_city() {// 调用HTTP请求函数,获取IP定位的JSON响应char *json = http_get_json("api.k780.com", "/?app=ip.local&appkey=AppKey&sign=Sign&format=json");if (!json) return NULL;  // 获取失败返回NULLcJSON *root = cJSON_Parse(json);  // 解析JSON数据if (!root) {  // 解析失败,释放内存返回NULLfree(json);return NULL;}cJSON *result = cJSON_GetObjectItem(root, "result");  // 提取"result"字段(IP定位信息)// 从result中提取"att"字段(格式:"国家,省份,城市")cJSON *att = result ? cJSON_GetObjectItem(result, "att") : NULL;char *city = att ? extract_city(att->valuestring) : NULL;  // 调用extract_city提取城市名cJSON_Delete(root);  // 释放cJSON解析内存free(json);          // 释放JSON缓冲区return city;         // 返回提取的城市名
}// 获取城市天气(通过天气API)
void get_weather(const char *city) {if (!city || strlen(city) == 0) {  // 检查城市名是否有效(非NULL且非空)printf("无效的城市名称\n");return;}char path[1024];  // 定义天气API请求路径缓冲区// 格式化天气API路径,将城市名插入请求参数snprintf(path, sizeof(path),"/?app=weather.today&cityNm=%s&appkey=AppKey&sign=Sign&format=json", city);char *json = http_get_json("api.k780.com", path);  // 获取天气JSON响应if (!json) {  // 获取失败打印提示并返回printf("获取天气失败\n");return;}cJSON *root = cJSON_Parse(json);  // 解析天气JSON数据if (!root) {  // 解析失败释放内存返回printf("JSON解析失败\n");free(json);return;}cJSON *result = cJSON_GetObjectItem(root, "result");  // 提取"result"字段(天气信息)if (result) {  // 天气数据存在,打印信息printf("\n%s天气信息:\n", city);cJSON *item;  // 临时变量存储JSON字段if ((item = cJSON_GetObjectItem(result, "days"))) printf("日期: %s\n", item->valuestring);  // 打印日期if ((item = cJSON_GetObjectItem(result, "weather"))) printf("天气: %s\n", item->valuestring);  // 打印天气状况if ((item = cJSON_GetObjectItem(result, "temperature"))) printf("温度: %s\n", item->valuestring);  // 打印温度if ((item = cJSON_GetObjectItem(result, "wind"))) printf("风向: %s\n", item->valuestring);  // 打印风向if ((item = cJSON_GetObjectItem(result, "humidity"))) printf("湿度: %s\n", item->valuestring);  // 打印湿度} else {  // 未找到天气数据打印提示printf("未找到天气数据\n");}cJSON_Delete(root);  // 释放cJSON内存free(json);          // 释放JSON缓冲区
}// 主函数:程序入口
int main() {printf("正在获取本机位置...\n");char *city = get_ip_city();  // 调用get_ip_city获取本机IP对应的城市if (!city) {  // 自动获取城市失败,手动输入printf("无法自动获取位置,请手动输入城市名称: ");city = malloc(100);  // 分配内存存储手动输入的城市名fgets(city, 100, stdin);  // 读取用户输入city[strcspn(city, "\n")] = '\0';  // 去除输入中的换行符} else {  // 自动获取成功,打印城市名printf("自动定位到: %s\n", city);}get_weather(city);  // 调用get_weather查询该城市的天气free(city);         // 释放城市名字符串内存(避免泄漏)return 0;           // 程序正常结束
}

 把AppKey和Sign换成对应获取天气平台API的(各2处)

比如我用的是控制台 - NowAPI

二、编译

gcc 自动获取当地天气.c cJSON.c -o 自动获取当地天气 -lm

三、终端显示

四、整体功能说明

该程序是一个自动定位并查询天气的工具,核心功能流程如下:

  1. 自动定位城市:通过调用api.k780.com的 IP 查询 API,获取本机 IP 对应的地理位置信息(格式为 “国家,省份,城市”),并从中提取城市名。
  2. 手动输入降级:如果自动定位失败(如 API 不可用),程序会提示用户手动输入城市名。
  3. 查询天气信息:将获取到的城市名作为参数,调用api.k780.com的天气 API,获取并解析该城市的天气数据(日期、天气状况、温度、风向、湿度等),最后打印结果。

程序通过封装 HTTP 请求、JSON 解析、字符串处理等功能,实现了从 “IP 定位” 到 “天气查询” 的完整流程,同时包含了错误处理和内存管理,确保运行的稳定性。

http://www.dtcms.com/a/320323.html

相关文章:

  • 八股文智力题
  • 目标检测数据集 - 高架视角道路车辆检测数据集下载「包含VOC、COCO、YOLO三种格式」
  • 为什么会有反射
  • js中的设计模式
  • UnivNet论文分析(20210615)
  • Flutter报错...Unsupported class file major version 65
  • 接口测试-mock测试
  • sigfillset 函数详解
  • Dash 中的 dcc.Clipboard 组件详解:实现一键复制功能
  • Caffeine 三种过期策略详解
  • Git 文件删除操作指南:管理与恢复已删除文件
  • python---pass函数
  • 【沉浸式解决问题】mysql-connector-python连接数据库:RuntimeError: Failed raising error.
  • React.memo
  • 【C#补全计划:类和对象(十)】密封
  • 阿里云可观测 2025 年 7 月产品动态
  • MCU中的USB
  • 虚拟乐队“天鹅绒落日”:AI生成音乐引发的行业风暴
  • STM32——STM32CubeMX
  • 【华为机试】113. 路径总和 II
  • Java异常处理机制深度解析:构建健壮程序的核心
  • C++ AVL树实现详解:理论+代码+图解
  • 使用Cloud Document Converter将飞书文档导出为markdown
  • 神经网络中一般都包含哪些关键层,每一层的作用是什么?
  • Gemini-CLI-项目原理流程总结
  • 大模型2位量化原理解析
  • Redis面试精讲 Day 16:Redis性能监控与分析工具
  • Microsoft Office PowerPoint 制作简单的游戏素材
  • 腾讯位置服务 —— 预估订单路线金额(使用Drools规则引擎处理)
  • Gitee上免费搭建博客