cJSON内存管理:cJSON_Delete函数的正确使用
搞懂cJSON里内存释放的正确姿势,避开野指针和内存泄漏的常见坑。
支持通配符SSL证书、多域名证书、IP证书。适配ACME接口, 支持Zerossl、Let's Encrypt和Google等渠道。登录已有账号
2026-06-13 05:15:40 C语言 strncmp 字符串
写 C 的时候,字符串比较和初始化几乎天天打交道,但有些细节不细想,确实容易翻车。
这里把 strncmp 的用法和空值初始化的几种方式放一起梳理一下,顺便提几个容易绕进去的点。
strncmp 的声明在 string.h 里,原型是 int strncmp(const char *s1, const char *s2, size_t n)。比较的是 s1 和 s2 的前 n 个字符,返回正值、0 或负值,规则跟 strcmp 一样,只是多了一个长度限制。示例代码大致长这样:
#include <stdio.h>
#include <string.h>
int main() {
const char *a = "nihao, world!";
int result = strncmp(a, "nihao", 5);
if (result == 0) {
printf("The first 5 characters of a and 'nihao' are the same.\n");
} else if (result < 0) {
printf("The first 5 characters of a are less than 'nihao'.\n");
} else {
printf("The first 5 characters of a are greater than 'nihao'.\n");
}
return 0;
}
这段代码里,a 指向 "nihao, world!",跟 "nihao" 比较前 5 个字符,结果自然是 0。
逻辑很简单,但有几个地方如果没留意,线上跑起来问题就出来了。
一个常见的问题是,如果 s1 指向的字符串实际长度比 n 小,strncmp 不会越界,它只会比较到 s1 的结尾空字符为止。这个行为本身是安全的,但可能会让你对比较结果产生误判。比如你本想比较前 10 个字符,结果 s1 只有 5 个字符,那么它实际上只在比较这 5 个字符,超出了没得比,相当于提前终止了。
这点在一些协议解析或定长字段比较时特别容易踩坑。
另外,s1 或 s2 是 NULL 的话直接崩溃,没商量。
所以调用前一定要确保指针有效,特别是从外部传进来的参数,或者动态分配后可能没检查到 NULL 的情况。很多人一开始会以为标准库函数内部会做判空处理,后来发现并没有。
还有字符编码的问题。strncmp 是按当前 locale 的字符编码逐字节比较,并不是直接比较二进制值。
如果程序切换过 locale,或者在不同环境下运行,行为可能会有差异。跨 locale 的比较,有时候得用其他办法,比如 memcmp 或者自己写比较逻辑,具体看场景。
下面说说字符串空值初始化。这个看起来很基础,但写法上的差异在某些上下文里会导致意料之外的行为。
最直接的就是用空字符串字面量 ""。你写 char str1[] = ""; 相当于定义了一个大小只有 1 的数组,里面放了个 '\0'。写成 const char *str2 = ""; 则是让指针指向字符串常量区的空字符串。这两种写法都行,但要注意 str1 是数组,之后可以修改;str2 指向常量,不能通过它去改写内容,否则段错误就来了。
如果已经有一个字符数组,想把它的内容清成空字符串,常见的有两种做法。一是用 memset:
char str[100];
memset(str, '\0', sizeof(str));
另一种是直接把第一个字符置为 '\0':
str[0] = '\0';
这两种效果上都能让 str 变成一个空字符串,但 memset 会把整个 buffer 清干净,str[0] = '\0' 只动了第一个字节,后面还是原来的残留数据。如果后面有代码基于整个 buffer 做操作,比如直接按定长写入然后 printf("%s") 倒无所谓,但如果是用 strcat 之类依赖空字符结尾的函数,两种写法都没问题。不过有时候为了防御未来可能的误用,习惯上还是 memset 一下更放心,尤其是网络收发 buffer 之类的场景。
还有一种是在定义数组时部分初始化。C 语言的规则是,只要初始化了哪怕一个元素,剩下的元素都会被自动初始化为 0,也就是 '\0'。所以写 char str[10] = {'\0'}; 和写 char str[10] = ""; 效果一样,整个数组都会是干净的。这个特性在声明静态或全局变量时也会自动起效,但局部变量如果没有显式初始化,内容就是不确定的,这时候随手 memset 一下是常见操作。
运行时空值赋值也很简单,要么给指针赋成 "",要么把字符数组头元素置 '\0'。比如:
const char *ptr;
ptr = "";
或者对于数组:
char str[100];
str[0] = '\0';
上面这些方法在不同场景里各有适用,选哪种主要看你对 buffer 干净程度的要求,以及会不会有后续操作误读到残留数据。
这些内容平时写写小 demo 可能不会出问题,但在一直运行的后台程序里,细节没处理好,真的会搞出一些很隐蔽的 bug。
上一篇: GRUB启动项修复笔记:从配置翻车到UEFI引导的那些坑
下一篇: C++实现m行n列带边框的长方形输出
搞懂cJSON里内存释放的正确姿势,避开野指针和内存泄漏的常见坑。
搞懂cJSON里内存释放的正确姿势,避开野指针和内存泄漏的常见坑。
cJSON库在处理JSON数据时涉及大量动态内存分配。本文将深入剖析cJSON_Delete函数的工作原理,指导开发者如何检查cJSON_Parse返回值、避免重复释放,以及通过规范操作彻底杜绝内存泄漏,确保程序高性能与稳定性。
还在为C语言字符串比较和初始化头疼?本文揭秘`strncmp`函数的实战技巧,教你如何精准比较字符串前N个字符。同时,提供多种字符串空值初始化的实用方案,助你避免常见陷阱,写出更安全、更高效的C代码。即学即用,告别Bug!