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

《嵌入式C语言笔记(十六):字符串搜索、动态内存与函数指针精要》

今日学习内容

字符串操作进阶

查找与统计长字符串中的短字符串,使用strncmp

遍历长字符串每个起始位置,比较从该位置开始的子串与短字符串。

int subString(const char *s, const char *sub)
{int i;int sLen = strlen(s);int subLen = strlen(sub);int k = sLen - subLen;for(i = 0;i <= k;++i){if(strncmp(s + i, sub, subLen) == 0){return i;}}return -1;
}int main(void)
{printf("%d\n", subString("Hello He is handsome He He She", "He"));return 0;
}

计数,匹配成功时计数增加。需处理重叠匹配情况。

int counterString(const char *s, const char *sub)
{int counter = 0;int t = 0;int ret;ret = subString(s, sub);while(ret >= 0){++counter;t = t + ret + strlen(sub);ret = subString(s + t, sub);}return counter;
}int main(void)
{printf("%d\n", counterString("Hello He is handsome He He She", "He"));return 0;
}

strcpy自复制优化

标准库函数strcpy(s, s)能安全处理自复制情况。

char *Strcpy(char *dest, const char *src)
{if(dest == src){return dest;}char *ret = dest;while(*src){*dest++ = *src++;}*dest = 0;return ret;
}

strcat自连接陷阱

strcat(s, s)会覆盖结束符导致无限循环。动态内存分配是可靠解决方案:

char *Strcat(char *dest, const char *src)
{char s[100];char *p = s;if(dest == src){strcpy(s, src);}char *ret = dest;while(*dest){++dest;}while(*p){*dest++ = *p++;}*dest = 0;return ret;
}int main(void)
{char s[100] = "Hello";Strcat(s, s);puts(s);return 0;
}


动态内存管理

核心函数

函数原型功能
mallocvoid* malloc(size_t size)分配未初始化内存
callocvoid* calloc(size_t num, size_t size)分配归零内存
reallocvoid* realloc(void *ptr, size_t new_size)调整内存块大小
freevoid free(void *ptr)释放内存

使用规范

        使用完内存后,要用free释放内存

malloc

char *p = malloc(strlen(s) + 1);

realloc:重新分配,并且复制原来的内容,归还之前的内存

p = realloc(p, strlen(p) + strlen(t) + 1);

calloc:分配为零的内存

int *p = calloc(n, sizeof(int));

free:归还内存,不归还会导致内存泄漏。

    free(p);p = NULL;


函数指针与多级指针

函数指针声明

语法:返回类型 (*指针名)(参数列表)

能指向函数入口地址的指针

回调函数

        降低耦合性

int add(int a, int b)
{return a + b;
}int sub(int a, int b)
{return a - b;
}int main(void)
{int (*p)(int , int ) = NULL;p = add;printf("%d\n", p(10, 20));return 0;
}

排序(qsort)

传参方式,例子在下下一个。

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
int pow2(int n)
{return n * n;
}int fn(int n)
{return n;
}void sort(int *a, int len, int (*pfn)(int))
{int i, j;for(i = 0;i < len - 1;++i){for(j = i + 1;j < len;++j){if(pfn(a[i]) > pfn(a[j])){int t = a[i];a[i] = a[j];a[j] = t;}}}
}void printArray(int *a, int len)
{int i;for(i = 0;i < len;++i){printf("%d ", a[i]);}puts("");
}int main(void)
{int a[] = {-1,2,-3,4,-5,6,-7,8,-9,0};int len = sizeof(a) / sizeof(*a);sort(a, len, pow2);printArray(a, len);return 0;
}

降低耦合性

int intcmp(const void *p1, const void *p2)
{int *q1 = (int *)p1;int *q2 = (int *)p2;if(*q1 > *q2){return 1;}else if(*q1 == *q2){return 0;}else{return -1;}}int main(void)
{double a[] = {1,2,3,4,5,6,7,8,9,0};qsort(a, sizeof(a) / sizeof(*a), sizeof(*a), intcmp);int i ;for(i = 0;i < sizeof(a) / sizeof(*a);++i){printf("%d\n", a[i]);}return 0;
}

指针的指针(二级指针)应用,修改一级指针的内容

void printStrings(char **p, int len)
{int i;for(i = 0;i < len;++i){puts(p[i]);}
}void reverseStrings(char **p, int len)
{int i;for(i = 0;i < len / 2;++i){
//		char t[100];
//		strcpy(t, p[i]);
//		strcpy(p[i], p[len - i - 1]);
//		strcpy(p[len - i - 1], t);char *t;t = p[i];p[i] = p[len - i - 1];p[len - i - 1] = t;}
}char *maxStrings(char **p, int len)
{char *max;max = p[0];int i;for(i = 1;i < len;++i){if(strcmp(max, p[i]) < 0){max = p[i];}}return max;
}void swap(char **a, char **b)
{char *t;t = *a;*a = *b;*b = t;
}void sortStrings(char **p, int len)
{int i, j;for(i = 0;i < len - 1;++i){for(j = i + 1;j < len;++j){if(strcmp(p[i], p[j]) > 0){swap(p + i, p + j);//		char *t;//		t = p[i];//		p[i] = p[j];//		p[j] = t;}}}
}

指针数组参数

        指针数组作为函数的参数,形参是指向指针的指针(下面的代码是调用上面的函数)

int main(void)
{char *s[] = {"Hello", "World!", "China"};int len = sizeof(s) / sizeof(*s);const char *n = "China";
//	puts(maxStrings(s, len));
//	reverseStrings(s, len);sortStrings(s, len);printStrings(s, len);return 0;
}

关键技巧

  1. 字符串安全:动态内存解决自操作问题,始终验证缓冲区容量
  2. 堆内存铁律malloc/calloc必须配对freerealloc用临时变量接收
  3. 函数指针:实现策略模式,减少模块耦合
  4. 多级指针:二级指针通过pppvalue间接访问数据

常见问题

内存泄漏

char *p = malloc(100);
// 忘记free导致泄漏

解决方案:

free(p);
p = NULL;

野指针访问

int *p = malloc(sizeof(int));
free(p);
printf("%d", *p);  // 危险!

解决方案:

free(p);
p = NULL;  // 立即置空


核心要点

  1. 字符串操作:动态内存是解决自连接问题的根本方案
  2. 堆内存管理realloc优先尝试原地扩展,需手动控制生命周期
  3. 函数指针:本质是代码入口地址,实现"相同接口不同行为"
  4. 多级指针:理解main函数参数传递机制与指针数组内存布局

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

相关文章:

  • RocketMQ 核心特性解析及与 Kafka区别
  • 思途JSP学习 0730
  • DP-v2.1-mem-clean学习(3.6.7)
  • 片上变化(OCV)
  • 7.Origin2021如何绘制拟合数据图?
  • Python 之抽象方法 @abstractmethod 的理解
  • Day06_C++编程
  • 9《MySQL 教程》MySQL 的数据类型(2)
  • 云原生环境里的显示变革:Docker虚拟浏览器与cpolar穿透技术实战
  • 赵义弘-----补题报告
  • 【python】Python爬虫入门教程:使用requests库
  • 【git】在 GitLab 上如何把 A 分支(如 feature/xxx)合并到 B 分支(如 trunk)
  • Scala实现常用排序算法
  • 深入理解 Kotlin Flow:异步数据流处理的艺术
  • MidJourney精选图集与提示词生成器:AI创意灵感与高效提示词工具
  • composer 常用命令
  • 高防CDN与高防IP的选择
  • docker可视化管理工具lazydocker
  • 【百卷编程】Go语言大厂高级面试题集
  • 3GPP TS 38.331 V18.6.0 (2025-06)中文版
  • 工业5G路由器赋能高速公路实时监控
  • 【问题未解决-寻求帮助】VS Code 中使用 Conda 环境,运行 Python 后 PowerShell 终端输出内容立即消失
  • 《Java 程序设计》第 12 章 - 异常处理
  • T113-i Linux系统完整构建指南:从SDK开箱到内核镜像量产烧录全流程
  • 2025年湖北中级注册安全工程师报考那些事
  • docker 用于将镜像打包为 tar 文件
  • 【MySQL学习|黑马笔记|Day3】多表查询(多表关系、内连接、外连接、自连接、联合查询、子查询),事务(简介、操作、四大体系、并发事务问题、事务隔离级别)
  • 【公有云部署模型】yolo模型公有云部署
  • 用聊天方式聊聊msvcr100.dll丢失的解决方法有哪些?msvcr100.dll是什么
  • 7.pcl滤波(一)