C语言-字符串函数

字符串函数

strlen

函数原型:size_t strlen(const char* str);

字符串以’\0’作为结束标志,strlen()函数返回的是在字符串中’\0’之前出现的字符的个数,不包含’\0’
字符串必须要以’\0’结束
函数的返回值size_t是unsigned int,无符号数

#include<stdio.h>
#include<string.h>

int main(void)
{
	//char arr[] = {'a', 'b', 'c', 'd', '\0'};//输出4.以{}表示的字符串,一定要在{}的最后加上'\0',不加的话,strlen求出的数字未知
	char arr[] = "abcd";//常量字符串,会自动在末尾加'\0'
	int len = strlen(arr);
	printf("%d", len);
	getchar();
	return 0;
}

简单实现strlen()函数

int my_strlen(char* arr){
	int count = 0;
	assert(arr != NULL);
	while(*arr != '\0'){//while中的条件也可以写成*arr,只要*arr不为0,*arr就一定大于0,就能进while循环,因为ASCII码中,0是最小的
		count++;
		arr++;
	}
	return count;
}

对strlen()的返回值size_t是unsigned int(无符号数)的理解

int main(void)
{
	if(strlen("abc") - strlen("abcdef") > 0){
		printf("abc");
	}else{
		printf("abcdef");
	}
	getchar();
	return 0;
}

输出的是abc,因为两个无符号数相减的结果依然是无符号数,所以3-6=-3,这个-3要当做无符号数来看待,肯定大于0

strcpy

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

源字符串必须以’\0’结束
会将源字符串中的’\0’拷贝到目标空间
目标空间必须足够大,保证能存储源字符串
目标空间必须可修改
返回值是目标空间的起始地址

#include<stdio.h>
#include<string.h>

int main(void)
{
	char source[] = "test";
	char dest[] = "abcdefg";
	strcpy(dest, source);//从内存中看,可以发现dest数组中的值变为了test\0fg\0
	getchar();
	return 0;
}

简单实现strcpy()函数

char* my_strcpy(char* dest, const char* source){

	assert(dest != NULL);
	assert(source != NULL);
	while(*source != '\0'){//
		*dest = *source;
		*dest++;
		*source++;
	}
	*dest = '\0';
	return dest;
}

简化写法

char* my_strcpy(char* dest, const char* source){
	char * res = dest;
	assert(dest != NULL);
	assert(source != NULL);
	//先赋值,后运算。*dest++ = *source++表达式的结果是*dest的值,所以只要*dest不为\0,while循环就不会退出
	while(*dest++ = *source++){
		
	}
	return res;
}

strcat

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

源字符串必须以’\0’结束
目标空间必须足够大,能够容纳源字符串的内容
目标空间必须可修改

#include<stdio.h>
#include<string.h>

int main(void)
{
	char source[] = "world";
	char dest[30] = "hello\0xxxxxx";
	//strcat函数是找到目标字符串中\0的位置,在\0的前面,追加整个源字符串
	//如果目标字符串在非结尾处中有\0,则会在此\0的前面,追加整个源字符串
	strcat(dest, source);
	//dest变为helloworldx,world\0替换了6个x的位置
	getchar();
	return 0;
}

简单实现strcat()函数

char* my_strcat(char* dest, const char* source){
	char * res = dest;
	assert(dest != NULL);//也可以写成assert(dest);
	assert(source != NULL);

	while(*dest != '\0'){
		*dest++;
	}
	while(*dest++ = *source++){

	}
	return res;
}

strcmp

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

第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串小于第二个字符串,则返回小于0的数字
第一个字符串等于第二个字符串,则返回等于0的数字

#include<stdio.h>
#include<string.h>

int main(void)
{
	char str1[] = "123457";
	char str2[] = "123456";
	//strcmp会逐个比较两个字符串中的每个char字符,一旦有某个char字符要小,则包含此char字符的字符串为较小的
	int res = strcmp(str1, str2);
	printf("%d", res);
	getchar();
	return 0;
}

简单实现strcmp()函数

int my_strcmp(char* str1, const char* str2){
	assert(str1 != NULL);
	assert(str2 != NULL);
	while(*str1 == *str2){
		if(*str1 == '\0'){
			return 0;
		}
		*str1++;
		*str2++;
	}

	if(*str1 < *str2 ){
		return -1;
	}else{
		return 1;
	}
}

strcpy,strcat,strcmp都是字符串长度不受限制的字符串函数

strncpy,strncat,strncmp都是字符串长度受限制的字符串函数

strncpy

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

从源字符串拷贝num个字符至目标空间
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后面追加’\0’,直到总长度达到num个字符

#include<stdio.h>
#include<string.h>

int main(void)
{
	char str1[10] = "abcde";
	char str2[] = "de";
	//str1的内容就会变成de\0de\0\0\0\0\0
	strncpy(str1, str2, 3);
	getchar();
	return 0;
}

简单实现my_strncpy()

char* my_strncpy(char* str1, const char* str2, int num){
	int flag = 0;
	char* res = str1;
	assert(str1 && str2);
	while(flag < num){
		if(*str2 != '\0'){
			*str1 = *str2;
			str1++;
			str2++;
			flag++;
			continue;
		}
		*str1 = '\0';
		*str1++;
		flag++;
	}
	return res;
}

strncpy的源码更简洁

char* my_strncpy(char* str1, const char* str2, int num){
	char* res = str1;
	while(num && (*str1++ = *str2++)){//*str1++ = *str2++的结果就是*str1的值
		num--;
	}
	if(num){
		while(num--){
			*str1++ = '\0';
		}
	}
	return res;
}

strncat

函数原型:char* strncat(char* dest, const char* source, size_t num);
目标空间必须足够大,能够容纳源字符串的内容
目标空间必须可修改
如果源字符串的长度要小于num,则只会拷贝源字符串到目标空间,不会额外补’\0’
拷贝字符串的最后,会拼接一个’\0’

#include<stdio.h>
#include<string.h>

int main(void)
{
	char str1[20] = "abcde\0xxxxxx";
	char str2[] = "def";
	//str1的内容就会变成abcdedef\0xxx
	strncat(str1, str2, 5);
	getchar();
	return 0;
}

strncmp

函数原型:char* strncmp(char* str1, const char* str2, size_t count);

比较两个字符串中count个字符的大小

strstr

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

在str1中寻找str2是否存在,如果存在,则返回str1中str2首次出现的首字符地址,如果不存在,则返回空指针

库函数strstr的实现(const类型的指针到非const类型的指针要强制类型转化)

char * __cdecl strstr (
        const char * str1,
        const char * str2
        )
{
        char *cp = (char *) str1;
        char *s1, *s2;

        if ( !*str2 )
            return((char *)str1);

        while (*cp)
        {
                s1 = cp;
                s2 = (char *) str2;

                while ( *s1 && *s2 && !(*s1-*s2) )
                        s1++, s2++;

                if (!*s2)
                        return(cp);

                cp++;
        }

        return(NULL);

}

strtok

函数原型:char* strtok(char* str, const char* seq);

seq参数是个字符串,定义了用作分隔符的字符集合
str是一个字符串,包含了若干个seq字符串中的分隔符。strtok函数会改变被操作的字符串,所以使用strtok函数切分的字符串一般都是临时拷贝的内容并且可以修改

#include<stdio.h>
#include<string.h>
 
int main(void)
{
	char arr[] = "abc@def.zxc";
	char seq[] = "@.";
	char copy[20] = {0};
	char* res = NULL;
	strcpy(copy, arr);
	//第一次分割的时候,会找到字符串中的@,将@替换为\0,同时返回分割的前一段的字符串的首地址,即abc中a字符的地址
	//同时strtok会记录此时@出现的位置,再次调用时,只需要传一个NULL作为被分割的字符串参数
	res = strtok(copy, seq);
	printf("%s\n", res);

	//第二次分割的时候,会找到字符串中的.,将.替换为\0,同时返回分割的前一段的字符串的首地址,即def中d字符的地址
	//同时strtok会记录此时.出现的位置,再次调用时,只需要传一个NULL作为被分割的字符串参数
	res = strtok(NULL, seq);
	printf("%s\n", res);

	//第三次分割的时候,字符串中已经没有需要分割的字符了,返回字符串分割的最后一段的首地址,即zxc中z字符的地址
    //如果再分割,字符串中没有需要分割的字符,则返回空指针
	res = strtok(NULL, seq);
	printf("%s\n", res);
	getchar();
	return 0;
}

for循环的方式进行分割

#include<stdio.h>
#include<string.h>
 
int main(void)
{
	char arr[] = "abc@def.zxc";
	char seq[] = "@.";
	char copy[20] = {0};
	char* res = NULL;
	strcpy(copy, arr);
	for(res = strtok(copy, seq); res != NULL; res = strtok(NULL, seq)){
		printf("%s\n", res);
	}
	getchar();
	return 0;
}

strerror

函数原型:char* strerror(int errnum);

根据传入的数字,返回对应的错误信息

#include<stdio.h>
#include<string.h>
 
int main(void)
{
	//输入0  输出No error
	//输入1  输出Operation not permitted 等等
	//传给strerror的数字,就是错误码,返回的就是错误信息
	char* res = strerror(1);
	printf("%s\n", res);
	getchar();
	return 0;
}

实际点的用法

#include<stdio.h>
#include<string.h>
#include<errno.h>
 
int main(void)
{
	//errno 是一个全局的错误码变量
	//当库函数在执行过程中,发生了错误,就会把对应的错误码,赋值到errno中
	FILE* file = fopen("test.txt", "r");
	if(file == NULL){
		printf("%s\n", strerror(errno));//会输出No such file or directory
	}
	getchar();
	return 0;
}
上一篇:结构体排序 or pair排序 ?


下一篇:不止短信,教你用 Python 发送告警通知到微信