C语言 字符串函数

Posted 一朵花花

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言 字符串函数相关的知识,希望对你有一定的参考价值。

此篇介绍处理字符和字符串的库函数和注意事项~

字符串

C语言字符串函数的功能非常单一

C语言没有专门的字符串类型,C语言中字符串类型本质上是一个字符数组。
C字符串的结尾标志是“\\0”,字符串本身就带有一个“\\0”。在计算字符串长度时,“\\0”是结束标志,不算做字符串内容

以下所有函数使用时,都需包含头文件<string.h>
在头文件<string.h>中定义了两组函数。第一组函数的名字以str开头;第二组函数的名字以mem开头,本篇只讲str开头的字符串函数~

字符串函数介绍

1.求字符串长度 strlen

函数原型:
size_t strlen ( const char * str ),
此处的const限制的是地址对应的内存空间不能进行修改

从字符串起始位置开始向后找,找到’\\0’就结束,返回该C字符串的长度

strlen的注意事项
1.参数指向的字符串必须以 ’ \\0 ‘结束
2.size_t是无符号类型的整数,在标准库中用来表示"个数",在进行size_t进行相减时,特别容易溢出,故一般不适用size_t.
3.strlen函数返回的是在字符串中 ‘\\0’ 前面出现的字符个数(不包含 ‘\\0’ )
4.使用strlen必须是字符串才可以

代码实现

size_t myStrlen(const char* str) {
	//校验参数合法性
	assert(str != NULL);
	size_t count = 0;
	while (str[count] != '\\0') {
		count++;
	}
	return count;
}

2.字符串拷贝 strcpy(比较麻烦)

函数原型:
char * strcpy ( char * destination, const char * source )

strcpy的注意事项:
1.source参数必须是字符串
2.destination参数空间必须足够大,能够容纳下source,或者使用strncpy来取代
3.将source指向的C字符串复制到destination指向的数组中,包括终止空字符(’\\0’),最后返回destination

代码实现

char* myStrcpy(char* dest, const char* source) {
	//校验参数合法性
	assert(dest != NULL);
	assert(source != NULL);
	int i = 0;
	while (source[i] != '\\0') {
		dest[i] = source[i];
		i++;
	}
	dest[i] = '\\0';
	return dest;
}

3. 字符串拼接 strcat(比较麻烦)

函数原型:
char * strcat ( char * destination, const char * source )

strcat的注意事项:
1.目的地和来源不得重叠
2.destination的空间要足够大,能够容下拼接后的结果
3.destination最后的结束字符’\\0’会被覆盖掉,并在连接后的字符串的尾部再增加一个’\\0’

char dest[ ]=“hello”
char source[ ]=“world”
在这里插入图片描述

将源字符串拷贝追加(尾部增加)到目标字符串。destination 中的’\\0’被source的第一个字符覆盖,并且在由destination 中的两者连接形成的新字符串的末尾包含一个空字符,最后返回destination

代码实现

char* myStrcat(char* dest, const char* source) {
	//校验参数合法性
	assert(dest != NULL);
	assert(source != NULL);
	//1.找到dest的结束位置
	int destEnd = 0;
	while (dest[destEnd] != '\\0') {
		destEnd++;
	}
	//while循环结束,下标为destEnd的dest便指向\\0
	//2.字符串拷贝
	int i = 0;
	while (source[i] != '\\0') {
		dest[i + destEnd] = source[i];
		i++;
	}
	//3.把dest的最后位置设成\\0
	dest[i + destEnd] = '\\0';
	return dest;
}

4. 字符串比较 strcmp

函数原型:
int strcmp ( const char * str1, const char * str2 )

https://blog.csdn.net/m0_47988201/article/details/117201616?spm=1001.2014.3001.5501.
此篇文章的最后部分对strcmp进行了说明

代码实现

int myStrcmp(const char* str1, const char* str2) {
	//校验参数合法性
	assert(str1 != NULL);
	assert(str2 != NULL);
	const char* p1 = str1;
	const char* p2 = str2;
	//依次比较每个字符
	while (*p1 !='\\0'&& *p2 !='\\0') {
		if (*p1 < *p2) {
			return -1;
		}
		else if (*p1 > *p2) {
			return 1;
		}
		//相等时比较下一个字符
		else {
			p1++;
			p2++;
		}
	}
	if (*p1 < *p2) {
		return -1;
	}
	else if (*p1 > *p2) {
		return 1;
	}
	else {
		return 0;
	}
}

5.拷贝指定长度字符串 strncpy(比较麻烦)

函数原型:
char * strncpy ( char * destination, const char * source, size_t num )

strncpy诞生的目的是为了避免出现dest空间不够的情况
将source的前num个字符拷贝到destination

strncpy注意事项
1.当num比source长的时候,拷贝完源字符串之后,在目标的后边追加0,直到num个
2.当num比source短的时候,就只拷贝source的前num个字符(不会拷贝\\0)
3.num的数值,必须要保证dest能够容纳下(需考虑\\0)
4.source和destination所指的内存区域不能重叠,且destination必须有足够的空间放置num个字符

无论触发strncpy的那种情况,都建议把dest初始化为全0,防止出现没有\\0的情况
一般把num写成sizeof(dest)-1

代码实现

char* myStrncpy(char* dest, const char* source, size_t num) {
	//校验参数合法性
	assert(dest != NULL);
	assert(source != NULL);
	assert(num != 0);
	int i = 0;
	while (source[i] != '\\0' && i < num) {
		dest[i] = source[i];
		i++;
	}
	while (i < num) {
		dest[i] = '\\0';
		i++;
	}
	return dest;
}

6.追加指定长度字符串 strncat(比较麻烦)

函数原型:
char * strncat ( char * destination, const char * source, size_t num )

将source的前num 个字符追加到destination,再加上一个\\0. 如果source 中C字符串的长度小于num,则只复制\\0之前的内容。

strncat注意事项
1.destination要有足够大的空间来容纳要拷贝的字符串
2.如果num大于字符串source的长度,那么仅将source全部追加到destination的尾部
3.strncat会将destination字符串最后的’\\0’覆盖掉,字符追加完成后,再追加’\\0’

代码实现

char* myStrncat(char* dest, const char* source, size_t num) {
	//校验参数合法性
	assert(dest != NULL);
	assert(source != NULL);
	assert(num != 0);
	//1.先找到dest的末尾位置
	size_t destEnd = 0;
	while (dest[destEnd] != '\\0') {
		destEnd++;
	}
	size_t i = 0;
	while (source[i] != '\\0'&& i < num) {
		dest[destEnd + i] = source[i];
		i++;
	}
	dest[destEnd + i] = '\\0';
	return dest;
}

7. 比较指定长度字符串 strncmp

函数原型:
int strncmp ( const char * str1, const char * str2, size_t num )
比较str1和str2的前num个字符
比较规则遵循字典序

代码实现

int myStrncmp(const char* str1, const char* str2, size_t num) {
	//校验参数合法性
	assert(str1 != NULL);
	assert(str2 != NULL);
	assert(num != 0);
	size_t i = 0;
	while (str1[i] != '\\0' && str2[i] != '\\0' && i < num) {
		if (str1[i] < str2[i]) {
			return -1;
		}
		else if (str1[i] > str2[i]) {
			return 1;
		}
		else {
			i++;
		}
	}
	if (i == num) {
		return 0;
	}
	return str1[i] - str2[i];
}

8. 查找字符串 strstr

函数原型:
const char * strstr ( const char * str1, const char * str2 )

判断一个字符串是否包含另一个字符串(字符串子串)

举例:
str1:helloworld
str2:llo
比较str1是否包含str2

分析过程:
在这里插入图片描述

代码实现

const char* myStrstr(const char* str1, const char* str2) {
	//校验参数合法性
	assert(str1 != NULL);
	assert(str2 != NULL);
	assert(*str1 != '\\0');
	assert(*str2 != '\\0');
	//创建指针black和sub,分别指向str1和str2的起始位置
	const char* black = str1;
	const char* sub = str2;
	while (*black != '\\0') {
		const char* tmp = black;
		//每次匹配未成功就要从起始位置从新匹配
		char* sub = str2;
		//比较结束的条件:black和sub指针当中有任意一个已经到达了\\0 处
		while (*sub != '\\0' && *tmp != '\\0') {
			//若相等,sub和tmp继续向后比较
			if (*tmp == *sub) {
				sub++;
				tmp++;
			}
			//不相等,直接跳出当前循环
			else {
				break;
			}
		}
		if (*sub == '\\0') {
			return black;
		}
		//匹配未成功,从下一位置继续进行比较
		black++;
	}
	return NULL;
}

9. 字符串切分 strtok

函数原型:
char * strtok ( char * str, const char * delimiters )
此函数需多次调用

对此函数的调用序列将str拆分为标记,这些标记是由作为delimiters一部分的任何字符分隔的连续字符序列

举例:
str为 aaa bbb ccc

  1. 第一次调用:strtok(str," “)
    从str起始位置开始,向后找” “,当遇到” “时,就返回第一个aaa,同时把刚才的” "改成’\\0’
  2. 第二次调用:strtok(NULL," “)
    此时第一个参数为NULL,表示从上次的切分结果位置继续往下切分~当找到bbb后面的” “时,仍然把” "改成’\\0’,并且返回bbb
  3. 第三次调用:strtok(NULL," “)
    第一个参数仍为NULL,继续从上次的结束位置继续往下切分,没找到” ",找到ddd后的’\\0’,函数返回ddd
  4. 第四次调用:strtok(NULL," ")
    第一个参数仍为NULL,继续从上次的结束位置继续往下切分,上次结束位置后没有东西了,即找完了,说明整个字符串切分完毕,此时直接返回NULL

代码实现

   char str[] = "aaa bbb ccc";
   char* pch = strtok(str, " ");
   while (pch != NULL) {
   	printf("%s\\n", pch);
   	pch = strtok(NULL, " ");
   }

strtok的缺点:
1.需要多次调用才能完成功能;
2.多次调用的过程中参数不同;
3.调用过程中会破坏原来的字符串;
4.strtok内部使用静态变量记录上次调用的位置,导致线程不安全;
故实际开发中不建议使用strtok

参考文档: http://cplusplus.com/.

以上是关于C语言 字符串函数的主要内容,如果未能解决你的问题,请参考以下文章

c语言字符串的长度怎么看

关于C语言程序代码加颜色的问题!

VBS 环境下如何调用EXCEL内置函数

C语言字符串长度如何数?

C语言 编写递归函数

Qt编程遇到的问题,我在qt中直接使用C语言的程序片段,有问题 ,求解