字符串函数(整理)

字符串函数

  • 使用前#include <string.h>

strlen

  • 返回字符串长度,不包括字符串结尾的’\0’;
int myStrlen(const char *p) {
	int cnt = 0; //变量,尤其是这种实现计数目的的变量使用前一定要初始化;
	while ( *p++ != '\0' )  // 条件甚至可以写为*p++,但是可读性不好
		cnt++;
	return cnt;
}
  • 这是自己写的函数,实际上的函数返回类型,执行语句都和这有区别,而且没有输入不正确数据时的处理;下面的myStrCmp函数等也是。

strcmp

  • 比较两个字符串:
    • 0 : s1 == s2;
    • <0 : s1 < s2;
    • >0 : s1 > s2;
int mycmp(const char *s1, const char *s2) {
	int idx;
	whlie ( true ) {
		if ( s1[idx] != s2[idx] ) {
			break;
		} else if ( s1[idx] == '\0' ) {
			break;
		}
		idx++;
	}
	return s1[idx] - s2[idx];
}

作为老师的分析,这里的while循环尽管并不“简洁”,但是他反映出当写一个循环时我们可能并不清楚循环的条件,这时候就可以采取这样的方法,逐层分析跳出的情况。 (true == 1,bool)

  • 我这里调用strcmp函数返回值是1/-1/0;并不是老师所说返回差值,有点奇怪;

修改过的循环

while ( s1[idx] == s2[idx] && s1[idx] != '\0' ) {
	idx++;
}
while ( *s1 == *s2 && *s1) {
	s1++;
	s2++;
}
  • 上面是两种处理字符串的方法:
    • 当成数组,定义一个整数作为数组下标来遍历这个字符串
    • 指针
  • idxcnt, ret。相较于i, j有一定实际含义的变量名,分别用作数组下标,计数,返回/运算结果。

strcpy

  • char* strcpy(char *restrict dst, const char *restrict src);
  • 把src的字符串拷贝到dst里;
  • 注意dst在前,src在后。
  • 关于这个原型声明现在需要注意的是返回dst
    • 为了让strcpy的结果在参与其他的运算,能链起代码来

小套路(复制一个字符串)

char *dst = (char*)malloc(strlen(src)+1);//sizeof(char) == 1;
//+1是因为strlen返回的长度不包括'\0',需要注意。
strcpy(dst, src); 

myStrcpy

char* myStrcpy(char *s1, const char *s2) {
	int idx;
	while ( s2[idx] != '\0' ) {
		s1[idx] = s2[idx];
		idx++;
	}
	s1[idx] = '\0';
	
	return s1;
}

注意点:

  1. 当循环结束时,s2[idx] == '\0',但是并没有给s1字符串结尾赋’\0’,需要在循环外再写一条赋值语句
  2. 当用指针实现这个函数,需要注意因为最后要返回s1,所以应当定义指针保存s1字符串的首地址,或是另外定义工作指针。
  3. 使用指针时可以写成while ( *s1++ = *s2++) ;,但并不代表实际写时一定要追求这种写法

代码写的简单可读性高一点,就现代的编辑器来说,最后会做出一样的编译效果。

'\0’的问题

‘\0’代表着字符串的结束,没有就会出现问题
在上面的myStrcpy函数中如果最后没有给字符串的结尾赋’\0’,也许侥幸执行结果没有报错,但不能保证每次执行都不出错。

c变量存取地址规律

先定义的变量会存取在较高的地址上,而后定义的变量会在较低的低地址上。

问题

char s1[6] = "Hello";
char s2[5] = {'H', 'e', 'l', 'l', 'o',};

printf("%s\n", s1);
printf("%s\n", s2);
  • 输出s2会打印出HelloHello,如果s2先定义,然后输出s2则会打印奇怪的字符。

strcat

  • 将第二个字符串连接到第一个上,返回连接后字符串的首地址。
char* myStrcat(const char* s1, const char* s2) { 
	char *p;
	p = (char*)malloc(strlen(s1)+strlen(s2)+1);
	strcpy(p, s1);
	
	char *q = p;
	while ( *q != '\0' ) {
		q++;
	}
	strcpy(q, s2);
	
	return p;
}
  • 这个函数写得应该是和原本函数差异最大的了。因为第一个功能都实现不了,这个只能返回连接后字符串的地址,
  • 主要考虑到目标串指向的空间不一定能容下衔接后的整个字符串,这也是strcat函数使用前需要注意的。看下面这个例子
char s[6] = "Hello";

printf("%d\n", strlen(s));
printf("%d\n", sizeof(s));
strcat(s, "*");
printf("%s\n", s);
printf("%d\n", strlen(s));
printf("%d\n", sizeof(s));
  • 输出为5,6,Hello*,6,6,我的理解是s指向的空间大小没有变,但是确实将超出s范围的地方赋值了,反映在strlen长度的变化,应该是已经产生错误了,但也许他会修改不能修改的地方的值,那是就会报错了。

其他字符串函数

查找指定字符

  • char* strchr(const char *s, int c);//从左边寻找c第一次出现的位置
  • char* strrchr(const char *s, int c);//从右边找
  • 找不到返回NULL;找到则返回一个指针,指向字符串中c的位置。
  • 类似于strcpy,让strchr返回的结果+1后再次作为函数参数调用函数即可找第二个c
char s[] = "Hello";
char *p = strchr(s, 'l');
//p = strchr(p+1, 'l');找到第二个
char *q = (char*)malloc(strlen(p)+1);
strcpy(q, p);
printf("%s\n", q);//输出l之后的内容
// char c = *p; //临时存*p的值 
// *p = '\0'; 
// char *q = (char*)malloc(strlen(s)+1);
// strcpy(q, s);
// *p = c; //将内容复制后,可以将*p的值恢复;
// printf("%s\n", q);输出l之前的内容
free(q);

查找字符串

  • char* strstr(const char *s1, const char *s2);
  • char* strcasestr(const char *s1, const char *s2);//无视大小写

关于字符串

  • c语言中没有专门的字符串类型,只能用字符数组,和指针来描述它,所以有时候会混淆一些东西,但主要原因其实是指针和数组的一些概念没有理解透彻
  • 比如:
  1. char *p = "asdf";**“asdf”**作为一个字符串常量,这个指针应当是指向常量的一个指针,是不能通过指针来修改这个字符串。但是指针本身是变量,可以改变,指向另一个字符串。
  2. char s[] = "asdf";这里的实际操作是将这个"asdf"这个字符串赋值给s数组里的元素,所以是可以通过下标改变其中某个字符。但是s是一个常指针,类似于s = "qwer";或者是s = p这样的操作都是不可以做的。
  • 还有一些注意点以后遇到在补充
  • 因为处理字符串的函数一般都要把字符串首地址传进去,所以在你没有想修改字符串时,有可能不小心修改了其中的值,这时候const修饰可以用来保护这个字符串,包括之后结构体中也会有这样的操作(对于定义较大的结构,传地址进函数是个更好的方法K&R);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值