文章目录
目录
前言
在处理字符与字符串时,为了方便,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语言中有一个专门做字符分类的头文件,里面有很多的字符分类的函数,这个头文件是
用法也很简单,都很类似,我们举一个例子。
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;//使用俩数相减来判断。