字符函数和字符串函数(一)


前言

        在处理字符与字符串时,为了方便,c语言提供了很多库函数,下面我们介绍库函数。

当然在开始之前我们得知道字符和字符串,关于这些基础的知识我们给出一些简单的方面的知识。


一、字符与字符串

        像"ABC"那样带双引号的一系列字符称为字符串字面量,为了方便我们直接称之为字符串

在字符串字面量的末尾会被加上一个叫作null字符的值为0的字符。

        用八进制转义字符表示null字符就是\0。若用整数常量来表示就是0

        在计算字符串的所占空间的大小时,我们可以通过sizeof()来计算,当然也可以通过strlen()+ 1,因为字符的类型是char类型,一个char类型所占的内存空间大小是1;        

        给出下面的代码1-1:

#include <stdio.h>
int main()
{
	printf("sizeof(\"123\") = %zd \n",sizeof("123"));
	printf("sizeof(\"AB\\tC\") = %zd \n", sizeof("AB\tC"));
	printf("sizeof(\"abc\\0def\") = %zd \n", sizeof("abc\0def"));
	return 0;
}

        

        如果是strlen的话要加1,因为strlen只会读取到 \0之前的数据

        在算大小的时候注意转义字符。

二、字符分类函数

        在c语言中有一个专门做字符分类的头文件,里面有很多的字符分类的函数,这个头文件是

<ctype.h>

        用法也很简单,都很类似,我们举一个例子。

int islower ( int c );

        islower能够判断c是否为小写字母。通过它的返回值来说明是否为小写字母,如果是小写字母就返回非0的整数 ,如果不是小写字母,则返回0

        通过上面的头文件的函数我们可以实现小写转大写的操作。

代码2-1:

#include <stdio.h>
#include <ctype.h>
int main()
{
	char str[] = "THE STRING.\n";
	char ch = 0;
	int i = 0;
	while (str[i])//当是\0时就终止
	{
		ch = str[i];
		if (isupper(ch))//判断是否为大写。
		{
			ch = ch + 32;//将大写转化为小写,需要将大写字母加32
		}
		putchar(ch);//输出每一次的值
		i++;
	}

	return 0;
}

输出结果:

三、字符转换函数

        C语言中提供了俩个转换字符的函数。

int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写

int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写

        对代码2-1进行优化

#include <stdio.h>
#include <ctype.h>


int main()
{
	char str[] = "THE STRING.\n";
	char ch = 0;
	int i = 0;
	while (str[i])//当是\0时就终止
	{
		ch = str[i];
		if (isupper(ch))//判断是否为大写。
		{
			ch = tolower(ch);//将大写转化为小写,需要将大写字母加32
		}
		putchar(ch);//输出每一次的值
		i++;
	}
	return 0;
}

        结果同样。

四、strlen的使用条件与实现

        实习一个函数首先要了解它的返回类型和参数。

 size_t strlen ( const char * str );

        • 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数(不包 含 '\0' )。

• 参数指向的字符串必须要以 '\0' 结束。

• 注意函数的返回值为size_t是⽆符号的( 易错 )

• strlen的使⽤需要包含头⽂件

        这是strlen的参数与返回类型。下面我们来实现strlen,我们介绍三种方法。

方法1:

//strlen的实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
size_t my_strlen(const char* str)//因为不需要修改str的本身所以我们用const修饰。
{
	assert(str);//不可能给一个空指针给这个函数计算,不安全
	size_t count = 0;//创建中间变量来计算 
	while (*str != '\0')//从首个开始判断,是'\0'就不进入循环,写成*str也行
	{
		count++;
		str++;
	}
	return count;//返回一个size_t的值
}

int main()
{
	char str[] = "Holle World!";
	
	size_t ret = my_strlen(str);//因为strlen返回的是size_t的类型

	printf("str 有%d个字符\n", ret);

	return 0;
}

方法2(指针减指针):

#include <stdio.h>
#include <string.h>
#include <assert.h>
size_t my_strlen(const char* str)//因为不需要修改str的本身所以我们用const修饰。
{
	assert(str);//不可能给一个空指针给这个函数计算,不安全
	char* start = str;//记录下起始指针
	while (*str != '\0')//从首个开始判断,是'\0'就不进入循环,可以写成*str
	{
		str++;
	}
	return (size_t)(str - start);//返回一个size_t的值
}

int main()
{
	char str[] = "Holle World!";

	size_t ret = my_strlen(str);//因为strlen返回的是size_t的类型

	printf("str 有%d个字符\n", ret);

	return 0;
}

        这里我们需要注意地址减地址的绝对值是地址间的元素个数,但是前提是在同一个空间

方法3(不创建中间变量):
       递归解决:

#include <stdio.h>
#include <string.h>
#include <assert.h>
size_t my_strlen(const char* str)//因为不需要修改str的本身所以我们用const修饰。
{
	assert(str);//不可能给一个空指针给这个函数计算,不安全
	if (*str == 0)
		return 0;
	else
		return (size_t)(1 + my_strlen(str + 1));//返回一个size_t的值
}

int main()
{
	char str[] = "Holle World!";

	size_t ret = my_strlen(str);//因为strlen返回的是size_t的类型

	printf("str 有%d个字符\n", ret);

	return 0;
}

        递归的核心思想是函数调用自身,通过不断地调用自身来解决问题。

        拆成小的,在有规律的化成大的。

        递归在解决一些问题时可以让代码更加简洁和易于理解,但需要注意避免出现无限递归的情况。

五、strcpy的使用条件与实现

        char* strcpy(char * 目标, const char * 源头 );

        拷贝源头字符串到目标字符串。

• 源字符串必须以 '\0' 结束。

• 会将源字符串中的 '\0' 拷⻉到⽬标空间。

• ⽬标空间必须⾜够⼤,以确保能存放源字符串。

• ⽬标空间必须可修改。 • 学会模拟实现。

      模拟实现:

//strcpy的模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>

char* my_strcpy(char* dest,const char* src)
{
	char* start = dest;//记录起始地址好返回该地址
	assert(dest && src);//保证表不是空指针
	while (*src != '\0')//不是'\0'开始,依次赋值再++;
	{
		*dest = *src;
		dest++;
		src++;
	}
	if(*src == '\0')//因为strlen会将\0也复制进去所以我们需要将特殊情况考虑进去
	{
		*dest = *src;
	}
	/*while (*dest++ = *src++)//这样写也可以,先算=右边的值因为后置++先使用再++
		;*/                   
	return start;
}

int main()
{
	char arr1[20] = "##########";
	char arr2[] = "abcdef";

	char* ret = my_strcpy(arr1, arr2);

	printf("%s\n", ret);

	return 0;
}

六、strcat的模拟实现

• 源字符串必须以 '\0' 结束。

• ⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。

• ⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容。

• ⽬标空间必须可修改。

• 字符串⾃⼰给⾃⼰追加,如何?

//strcat的实现
#include <stdio.h>
#include <string.h>
#include <assert.h>

char* my_strcat(char* dest,const char* src)
{
	//保存起始位置好返回
	char* start = dest;

	assert(dest && src);

	if (*src == '\0')
		return dest;
	//找到目标的\0
	while (*dest != '\0')
	{
		dest++;
	}
	while (*src != '\0')//dest的地址变成\0时开始交换,和strcpy一样
	{
		*dest = *src;
		dest++; 
		src++;
	}
	/*while (*dest++ = *src++)
		;*/
	return start;

}

int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "efg";
	char* ret = my_strcat(arr1, arr1);

	printf("%s\n", ret);

	return 0;
}

        如果使用我们模拟的strcat给同一个字符串数组实现追加是不行的.当然在使用strcat时尽量不要给同一个数组追加,虽然大部分不会出错但是,这样会有风险。

七、strcmp的使用条件和实现

int strcmp( const char *str1, const char *str2 );

◦ 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字

◦ 第⼀个字符串等于第⼆个字符串,则返回0

◦ 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字

◦ 那么如何判断两个字符串? ⽐较两个字符串中对应位置上字符ASCII码值的⼤⼩。

        

//strcmp模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;
	else
		return  -1;	
}
int main()
{
	char arr1[] = "abc";
	char arr2[] = "ab";
	char arr3[] = "aq";
	int ret =  my_strcmp(arr1, arr2);
	if (ret > 0)
		printf("arr1 > arr2");
	else if(ret == 0)
		printf("arr1 = arr2");
	else
		printf("arr1 < arr2");

	printf("\n");

	int ret2 = my_strcmp(arr1, arr2);
	if (ret2 > 0)
		printf("arr1 > arr3");
	else if (ret == 0)
		printf("arr1 = arr3");
	else
		printf("arr1 < arr3");
	return 0;
}

        当然可以使用俩数相减来判断

//strcmp模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>

int my_strcmp(const char* str1, const char* str2)
{
    assert(str1 && str2);

    while (*str1 == *str2)
    {
        if (*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    return *str1 - *str2;//使用俩数相减来判断。
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值