《嵌入式C语言笔记(十五):字符串操作与多维指针深度解析》
1.字符串与指针安全操作
函数
函数 | 功能 | 安全替代 | 功能 |
---|---|---|---|
strcpy | 字符串拷贝 | strncpy | 复制前n个,最多strlen个,超出有效长度,按原样复制 |
strcat | 字符串拼接 | strncat | dest只连接src的前n个,如果n超过有效长度,按原样链接 |
strcmp | 字符串比较 | strncmp | 比较前n 个字符 |
strlen | 获取有效长度(不含\0 ) |
const关键字与万能指针
const关键字
1.普通变量经过const修饰后,会变为只读变量,无法直接访问,只能通过间接访问修改。
2.指针变量前加const,不是说p不能改,而是*p不能改(p指向的变量),修饰的是*p(无法通过指针运算修改指针变量所指向的变量)
void*
万能指针
- 可接收任意基类型指针,但不能做指针运算,可以降低程序的耦合性。
- 需强制类型转换。
2.数组指针与指针数组
数组指针(指向数组的指针)
- 定义:指向数组的指针,括号不能省略,一维数组使用时,p+1为野指针。二维数组使用p + 1,不是野指针(二维数组作为函数参数传递,形参是指向一维数组的指针)。
int (*p)[4]
(指向含4个整数的数组)
3.函数与指针
指针函数(返回指针的函数)
- 禁止返回局部变量地址
// 错误示例
int* func() {int a = 10;return &a; // a销毁后返回野指针
}
- 安全返回,用static修饰为静态变量,或者直接用全局变量。
int* safe_func() {static int b = 20; // 静态存储期return &b; // 合法
}
4.关键技巧总结
- 字符串常量,内容相同时,地址是一样的
void*
使用规范- 用于内存拷贝
memcpy
函数 - 用前必须强制类型转换
- 用于内存拷贝
const
最佳实践- 函数参数加
const
防止意外修改(如strlen(const char*)
)
- 函数参数加
4.代码
1)字符串的操作
void Puts(const char *s)
{while(*s){putchar(*s++);}puts("");
}int Strlen(const char *s)
{int counter = 0;while(*s){++counter;++s;}return counter;
}void Strcpy(char *dest, const char *src)
{while(*src){*dest++ = *src++;}*dest = 0;
}void Strcat(char *dest, const char *src)
{while(*dest){++dest;}while(*src){*dest++ = *src++;}*dest = 0;
}int Strcmp(const char *s1,const char *s2)
{while(*s1 == *s2 && *s1 && *s2){++s1;++s2;}return *s1 - *s2;
}void Strncpy(char *dest, const char *src, int n)
{while(n--){*dest++ = *src++;}*dest = 0;
}void Memcpy(void *dest, const void *src, int n)
{char *p = (char *)src;char *q = (char *)dest;while(n--){*q++ = *p++;}*q = 0;
}void Strncat(char *dest, const char *src, int n)
{while(*dest){++dest;}while(n-- && *src){*dest++ = *src++;}*dest = 0;
}int Strncmp(const char *s1, const char *s2, int n)
{while(--n && *s1 == *s2 && *s1 && *s2){++s1;++s2;}return *s1 - *s2;
}int main(void)
{char s1[100] = "Hello";char s2[100] = "Helloq";//Puts(s1);//printf("%d\n", Strlen(s1));//Strcpy(s2, s1);//Puts(s2);//Strcat(s1, s2);//puts(s1);//printf("%d\n",Strcmp(s1,s2));//Strncpy(s2, s1, 5);//Puts(s2);//Memcpy(s2, s1, sizeof(s1));//Puts(s2);//Strncat(s2, s1, 8);//Puts(s2);//printf("%d\n", Strncmp(s1, s2, 5));return 0;
}
2)二维数组的操作(数组指针)
void printfArray2D(int (*a)[4], int rows)
{int i, j;for(i = 0;i < rows;++i){for(j = 0;j < 4;++j){printf("%2d ", *(*(a + i) + j));}puts("");}
}int sumOfArray2D(int (*a)[4], int rows)
{int i,j;int sum = 0;for(i = 0;i < rows;++i){for(j = 0;j < 4;++j){sum += *(*(a + i) + j);}}return sum;
}void swap(int *a, int *b)
{int t = *a;*a = *b;*b = t;
}void reverse(int *begin, int *end)
{while(begin < end){swap(begin, end);++begin;--end;}
}void reverse2D(int (*a)[4], int rows)
{int i;for(i = 0;i < rows;++i){reverse(*(a + i),*(a + i) + 4 - 1);}
}int main(void)
{int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};int rows = sizeof(a) / sizeof(a[0]);//printfArray2D(a, rows);//printf("%d\n", sumOfArray2D(a, rows));//reverse2D(a, rows);//printfArray2D(a, rows);return 0;
}
3)指针函数
char *Strcat(char *dest, const char *src)
{char *ret = dest;while(*dest){++dest;}while(*src){*dest++ = *src++;}*dest = 0;return ret;
}
5.总结
- 字符串操作:
strn
系列函数更安全。 - 嵌入式安全
const
保护只读数据(如固件配置)- 静态变量/全局变量保障指针生命周期
关联知识:结合内存分区理解指针生命周期(栈/静态区/堆)