strlen函数是求字符串长度的函数,里面传的是地址,函数返回的是‘\0’前面出现的字符的个数,是无符号整形(注意:如果返回值是一个负数,会自动将其转换成正数,也就是将负数的补码直接看做原码输出)
strlen函数的使用
#include
#include
int main()
{
char arr[] = "abc";
int len = strlen(arr);
printf("%d\n", len);
return 0;
}
strlen函数的模拟实现
计数器方式实现:
int my_strlen(char*str)
{
assert(str != NULL);
int count = 0;
while (*str != '\0')
{
str++;
count++;
}
return count;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
递归方式实现:
int my_strlen(char*str)
{
assert(str != NULL);
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
指针-指针方式实现:
#include
#include
#include
int my_strlen(const char*str)
{
assert(str != NULL);
const char*start = str;
while (*str)
{
str++;
}
return str - start;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
字符串拷贝函数:
1.源字符串必须有’\0’,且会将’\0’拷贝到目标字符串。
2.目标空间必须足够大且可变。
strcpy函数的使用
int main()
{
char arr1[] = "*********";
char arr2[] = "ni hao";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
strcpy函数的模拟实现
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char*ret = dest;
while (*dest++ = *src++)//拷贝字符串,包括'\0'
{
;
}
return ret;//返回的目标空间的起始地址
}
int main()
{
char arr1[20] = "*************";
char arr2[] = "hello world";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);//
return 0;
}
strcat函数(字符串追加函数):把源字符串的内容追加到目标空间的后面。
1.源字符串必须以’\0’结束。
2.目标空间必须足够大且可以被修改,同时目标空间里必须也要有\0,因为要从目标空间的’\0’处开始追加。
3.不能自己给自己追加,因为会修改掉’\0’,使得字符串没有终止条件了
strcat函数的使用
int main()
{
char arr1[20] = "hello ";//目标空间必须足够大
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
strcat函数的模拟实现
char* my_strcat(char*dest, const char*src)
{
assert(dest && src);
char*ret = dest;
//1. 找到目标空间的\0
while (*dest)
{
dest++;
}
//2. 追加
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
strcmp(字符串比较函数):
不是比较字符串的长度,而是比较字符串中对应字符的ASCII码值,当有一个字符串的某个字符的ASCII码值大于另一个字符串对应字符的ASCII码值时,则该字符串大于另一个字符串,返回一个大于0的数字。
strcmp函数的使用
int main()
{
int ret = strcmp("abc", "abcdef");
printf("%d\n", ret);
return 0;
//打印的结果是一个小于0的数字
}
strcmp函数的模拟实现
int my_strcmp(const char*s1, const char*s2)
{
assert(s1 && s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
return *s1 - *s2;
}
int main()
{
int ret = my_strcmp("abq", "abcdef");
printf("%d\n", ret);
return 0;
}
1.和strcpy函数类似,但是strcnpy函数可以拷贝具体的字符个数,以避免strcpy拷贝字符多了而目标空间存不下系统报错。
2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
和strcat函数类似,但区别在于strncat函数可以追加具体的字符个数,且追加相应的字符个数后会在后面自动补上’\0’(如果追加的长度多于一个字符串的长度时,会将该字符串全部追加完并且在后面补上’\0’)。
和strcmp函数相似,但strncmp函数可以比较具体的字符个数。
strstr函数,作用为在一个字符串中寻找另外一个字符串第一次出现的位置,返回的是地址,如果找不到的话,则会返回空指针。
strstr函数的使用
int main()
{
char arr1[] = "abcdefgbcd";
char arr2[] = "bcd";
char*ret = strstr(arr1, arr2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
return 0;
}
strstr函数的模拟实现
char* my_strstr(const char*s1, const char*s2)
{
assert(s1 && s2);
const char *cp = s1;
if (*s2 == '\0')
return (char*)s1;
while (*cp)
{
const char *p1 = cp;
const char *p2 = s2;//给p1,p2都加上const让两边类型保持一致
while ((*p1!='\0') && (*p2!='\0') && (*p1 == *p2))
{
p1++;
p2++;
}
if (*p2 == '\0')
{
return (char*)cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "defq";
char*ret = my_strstr(arr1, arr2);//在arr1中查找arr2字符串第一次出现的位置
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到子串\n");
return 0;
}
1.strtok函数会在字符串中寻找标记(分隔符),并将这个标记改成’\0’,然后返回起始位置。
2.strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。
3.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
4.从寻找第二个标记开始调用strtok函数时传的第一个参数应该为空指针。
int main()
{
char arr[] = "[email protected]";//@. 分割符
char arr2[30] = {
0 };
strcpy(arr2, arr);
char*p = ".@";
char *ret = NULL;
for (ret = strtok(arr2, p); ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}
strerror(错误报告函数),当库函数使用时发生错误时,返回错误码,把错误码转换成对应的错误信息,返回错误信息对应字符串的起始地址。
char *strerror( int errnum );
函数 | 若参数复合下列条件则返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’ |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母az或AZ |
isalnum | 字母或者数字,az,AZ,0~9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
字符转换函数
int tolower ( int c ):转换为小写
int toupper ( int c ):转换为大写
内存操作函数可以用于操作数组
1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2.这个函数在遇到 ‘\0’ 的时候并不会停下来。
3.如果source和destination有任何的重叠,复制的结果都是未定义的。
4.
void *memcpy( void *dest, const void *src, size_t count );
此函数在实现的时候,不知道未来会被用来拷贝什么类型的数据,所以此函数返回类型为void;第三个参数为要拷贝的字节个数。
5.用于拷贝两个不相关的内存(没有重叠)。
memcpy函数的使用
int main()
{
int arr1[] = {
1, 2, 3, 4, 5, 6 };
int arr2[10] = {
0 };
memcpy(arr2, arr1, 16);
return 0;
}
void* my_memcpy(void*dest, const void*src, size_t count)
{
void*ret = dest;
assert(dest && src);
while (count--)
{
*(char*)dest = *(char*)src;
++(char*)dest;//((char*)dest)++;
++(char*)src;//((char*)src)++;
}
return ret;
}
memmove函数和memcpy函数类似,参数完全相同,但区别在于memmove函数可以进行重叠拷贝。
例:
memmove函数的模拟实现
void* my_memmove(void* dest, const void*src, size_t count)
{
void* ret = dest;
assert(dest && src);
if (dest < src)
{
//前->后
while (count--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
}
else
{
//后->前
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
注意:
标准规定memcpy函数只要能够实现不重叠拷贝就行,但在有些编译器下memcpy函数也可以实现重叠拷贝。即便如此,也建议大家以后在重叠拷贝时用memmove函数,以免在部分编译器环境下达不到预期效果。
int memcmp( const void *buf1, const void *buf2, size_t count );
memcmp(内存比较函数):用于比较buf1和buf2的前count个字节,具体的返回值如下:
和strcmp的区别:strcmp比较的是字符串,strcmp在比较过程中需要注意是否遇到了’\0’,而memcmp比较的是内存块,可以指定比较的字节数。
memset函数用于将指定的某一块内存中的后n个字节的内容全部设置为指定的字符。
void *memset( void *dest, int c, size_t count );