一.strlen
求结果?
#include<stdio.h>
int main()
{
if (strlen("abc") - strlen("abcdef") > 0)
{
printf("hehe\n");
}
else
{
printf("haha\n");
}
return 0;
}
strlen 返回的是一个(size_t)unsigned int 类型的数。
所以结果返回的是hehe ,因为3-6 = -3 但是在内存中是以补码的形式进行存储的,返回的应该是一个size_t类型的值电脑认为-3的补码就是原码,所以这是一个很大的正数
strlen的两种实现方式
#include<assert.h>
//①计数器写法
int my_strlen(const char* str)
{
int count = 0;
assert(str != NULL);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
//如果这里使用我们的my_strlen这个函数去求上面的my_strlen("abc") - strlen("abcdef") 得到的结果就应该是haha,因为这里我们自己所设定的返回值是int类型
//②递归写法(不创建临时变量,写一个求字符串长度的代码)
int my_strlen(const char* str)
{
if (*str == '\0')
{
return 0;
}
else
{
return 1 + my_strlen(str + 1);
}
}
长度不受限制的字符串函数
有时候对于目的地空间根本就不够大,你把源的字符串拷贝到目标空间内,即使程序崩溃了,但是依旧会显示你想要的的结果
二.strcpy
①源字符串必须以’\0’结束
char arr2[] = {‘b’,‘i’,‘t’}; 如果是这种形式进行拷贝,你就会发现他找不到‘\0’,就很有可能会造成越界访问
②会将源字符串中的’\0’拷贝到目标空间
③目标空间必须足够大,以确保能存放源字符串
④目标空间必须可变
char* p = “abcdef”; 这也是错的,因为这是常量字符串,不可变
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
return ret;
int main()
{
char arr1[] = "abcdefghi";
char arr2[] = "bit";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
上面的代码不够精简,这样的代码才是最完美的
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
//拷贝src指向的字符串到dest指向的空间,包含'\0'
while (*dest++ = *src++) // 解引用的优先级比++高
{
;
}
//返回目的地空间的起始地址
return ret;
}
三.strcat(字符串追加函数)
①源字符串必须以’\0’结束
②目标空间必须有足够大,能容纳下源字符串的内容
目标空间不够大的情况。
对于这段代码来说,你是会在上面看到显示的结果,但是程序也崩溃了,因为arr1的空间不够,并不能够把arr2里面的内容直接追加过去。
模拟实现strcat
char* my_strcat(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
//1.找到目的字符串的'\0'
while (*dest != '\0')
{
dest++;
}
//2.追加
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[30] = "hello";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
四.strcmp(字符串比较)
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
那么strcmp比较的是两个字符串谁长吗?
int main()
//比较'a' 和'c'哪一个ASCII的值更大,在VS编译器下,直接就判断出来了第一个字符串大于第二个字符串
char* p = "abcdef";
char* pp = "crgjk";
//第一个字符一样时,顺序比较下一个字符的大小
char* p = "abcd";
char* pp = "aced"
// 相等的时候
char* p = "abcd";
char* pp = "abcd"
}
难道因为第一个字符串长度为6,第二个字符串长度为5,所以第一个就大于第二个吗? 不是的,strcmp比较的是字符串首字符的大小(在VS编译器下如果字符串1的首字符大于第二个字符串的首字符,就会直接返回一个大于0的数(一般是1))如果两个首字符一样大,那就比较第二个字符,顺序往下推。
模拟实现strcmp
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
//比较
while (*str1 == *str2)
{
if (*str1 == '\0')
{
return 0; //相等
}
str1++;
str2++;
}
//vs编译器下实现的结果
if (*str1 > *str2)
return 1; // 大于
else
return -1; // 小于
//gcc编译器下返回的结果
//return (*str1 - *str2);
}
int main()
{
char* p1 = "abcdef";
char* p2 = "abcqwe";
int ret = my_strcmp(p1, p2);
printf("ret = %d\n", ret);
return 0;
}
长度受限制的字符串函数
strncpy
①拷贝num个字符从源字符串到目标空间
②如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后面追加0,直到num个
strncat
strncmp
int strncmp(const char* string1,const char* string2,size_t count)
strstr---------查找字符串函数
找到了就给我返回查找到的那个字符串的地址,没有找到你就给我返回一个NULL。这个函数的实现逻辑还是挺复杂的,需要在后续多次的重复理解。
#include<assert.h>
char* my_strstr(const char* p1, const char* p2)// 这里我只是需要查找,所以不会改变里面的内容
{
assert(p1 != NULL);
assert(p2 != NULL);
char* s1 = NULL;
char* s2 = NULL;
char* cur = (char*)p1;//可能报警告//记住他们两个相等的的位置,方便返回地址和进行下一次继续判断(字符串还有可能是"abbbcdef" "bbc")
if (*p2 == '\0') // 传过去的字符串p2有可能是空字符串的情况
{
return (char*)p1;
}
//在p1里面查找p2,如果p1是一个空字符串那就根本没有办法查找,但是当p1不是空字符串的时候,说明就是可以查找的,我用p1的第一个字符和p2的
//第一个字符相比较,如果不一样,我让p1的指针往后走一下,在比较直到p1指向的和p2指向的字符相等了,然后让他们一起向后走
while (*cur) // 只有第一个字符串不为空,才有查找的必要
{
s1 = cur;
s2 = (char*)p2; // 因为p2是一各const类型的,所以可能汇报警告,需要强制类型转换一下
//循环停止的条件有三个
//1.首先p1先找到了'\0' 说明找不到p2了
//2.在p1里面把p2彻底找到了,且p2已结遇见了'\0'所以停止了
//3.*p1 != *p2循环也要停下来的
// "abcde" "def" "abcdef" "def"
while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
//库里面的函数写法(*s1 && *s2 && !(*s1-s2))
{
s1++;
s2++;
}
if (*s2 == "\0") // 唯有这个条件下说明查找到,但是你会发现代码写到这里的时候,p1和p2的值一直都在改变,但是当我想要返回地址的时候
//我不知道该怎么返回了,所以这里需要把起始的地址保存在一个变量里面,好方便下一次的继续使用
{
return cur;
}
cur++;
}
return NULL;
}
strtok
①strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
②strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
③strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记
int main()
{
char arr[] = "[email protected]";
char* p = "@.";
char buf[1024] = {
0 };
strcpy(buf, arr);
//切割buf中的字符串
char* ret = NULL;
for(ret = strtok(arr,p);ret !=NULL;ret = strtok(NULL,p))
{
printf("%s\n",ret);
}
//这里之所以这么写,是因为你会发现在切割字符串的时候,只有第一次传字符串的首地址,其余都是传NULL,这样子的写法就要比下面的方法感觉好很多。
char* ret = strtok(arr,p);
printf("%s\n", ret);
ret = strtok(NULL, p);
printf("%s\n", ret);
ret = strtok(NULL, p);
printf("%s\n", ret);
return 0;
}
strerror
可以把错误码转换成我们所认识的内容。
字符函数
#include<ctype.h>需要引入的头文件
int main()
{
//char ch = 'w';
//如果是小写就会返回一个大于0的数
//int ret = islower(ch);
//printf("%d\n",ret);
//char ch = tolower('Q');
//char ch = toupper('q');
//putchar(ch);
//把字符串内容全部转为小写
char arr[] = "I Am A Student";
int i =0;
while(arr[i] != '\0')
{
if(isupper(arr[i]))
{
arr[i] = tolower(arr[i]);
}
i++
}
printf("%s\n",arr);
return 0;
}