当前位置: 首页 > 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.xdnf.cn/news/1216873.html

相关文章:

  • 企业微信API接口发消息实战:从0到1的技术突破之旅
  • MySQL索引和事务笔记
  • 2419.按位与最大的最长子数组
  • JAVAEE--4.多线程案例
  • Mac配置iterm2
  • 【动态规划 | 多状态问题】动态规划求解多状态问题
  • 信贷风控笔记8-解读商业银行资本管理办法笔记
  • Day 4-1: 机器学习算法全面总结
  • Vue路由钩子完全指南
  • 论文阅读|ArxiV 2024|Mamba进一步研究|VSSD
  • Python Pandas.concat函数解析与实战教程
  • 【力扣热题100】哈希——字母异位词分组
  • 20250730在荣品的PRO-RK3566开发板的Android13下调通敦泰的FT8206触控芯片【I2C的挂载】
  • colima 修改镜像源为国内源
  • 02 基于sklearn的机械学习-KNN算法、模型选择与调优(交叉验证、朴素贝叶斯算法、拉普拉斯平滑)、决策树(信息增益、基尼指数)、随机森林
  • MacTex+Vscode数学建模排版
  • VUE -- 基础知识讲解(二)
  • 计算机网络基础(二) --- TCP/IP网络结构(应用层)
  • 代码随想录算法训练营第三十六天
  • RHCA学习概述
  • Python 程序设计讲义(45):组合数据类型——集合类型:集合的常用操作
  • List 接口
  • nav2--安装/教程
  • Linux 系统进程管理与计划任务详解
  • 2025 年 NOI 最后一题题解
  • ORACLE的表维护
  • 学习Markdown
  • Python读取获取波形图波谷/波峰
  • 开发避坑短篇(9):解决升级Vue3后slot attributes废弃警告
  • Python Day19 时间模块 和 json模块 及例题分析