字符串长度:strlen
长度不受限制的字符串函数 :strcpy strcat strcmp
长度受限制的字符串函数:strncpy strncat strncmp
字符串查找:strstr strtok
错误信息报告:sterror
内存操作函数:memcpy memmove memset memcmp
函数介绍:
strlen
size_t strlen (const char* str)
- 字符串已'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面的字符串个数(不包含'\0')
- 参数指向的字符串必须以'\0'结束
- 注意函数的返回值是size_t,也就是无符号整形(size_t == unsigned int)
strlen的模拟实现
#include <assert.h>
#include <stdio.h>
#include <string.h>
//strlen 的模拟实现
//size_t == unsigned int
int my_strlen(const char* str)
{
int count = 0;
assert(str != NULL);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("len = %d\n", len);
// 3 - 6 = -3但是strlen返回的是无符号整形
if (strlen("abc") - strlen("abcdef") > 0)
{
printf("hehe\n");
}
else
{
printf("haha\n");
}
return 0;
}
strcpy
char* strcpy(char* destination, const char* source)
- 源字符必须以'\0'结束, 否则拷贝的时候会发生越界访问
- 目标空间必须足够大,能够容纳下源字符的内容
- 目标空间必须可修改
strcpy的模拟实现:
#include <string.h>
#include <assert.h>
#include <stdio.h>
char* my_strcpy(char* str1,const char* str2)//源头的地址不发生变化,用const修饰
{
assert(str1 != NULL);
assert(str2 != NULL);
//strcpy返回的是目的地的起始位置,后面的循环将str1的位置发生了变化,
char* ret = str1;
while (*str1++ = *str2++)//开始的时候将b赋值给str1,最后将'\0'赋值给str1,表达式的结果的ascall码值为0,跳出循环
{
;
}
//返回目的地起始位置的地址
return ret;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "bit";
//注意事项:
//1 源头必须包含'\0',否则拷贝的时候会发生越界访问
// char arr2 = {'a', 'b', 'c'};没包含'\0'
//2 目标空间必须足够大,包含源字符串
//3 目标空间可以被修改
// char* p = "abcdef";p指向的是常量字符串,不能被修改
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
strcat
char* strcat(char* destination, const char* source)
- 源字符必须以'\0'结束, 否则拷贝的时候会发生越界访问
- 目标空间必须足够大,能够容纳下源字符的内容
- 目标空间必须可修改
strcat的模拟实现:
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcat(char* dest, char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
//1 找到目的地字符串的'\0'
while(*dest != '\0')
{
dest++;
}
//2 开始将src的字符串赋值给dest
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[30] = "abcdefg";//arr1 的空间必须足够大,必须要有'\0',arr2是从'\0'的位置开始追加
char arr2[] = "bit";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
strncat
char * strncat(char *dest, const char *src, size_t n);
模拟实现
char* my_strncat(char* dest, char* src, size_t n)
{
assert("dest != NULL");
assert("src != NULL");
char* ret = dest;
while (*dest != '\0')
{
dest++;
}
while (n--)
{
*dest++ = *src++;
}
return ret;
}
int main()
{
char arr1[30] = "abcdef";
char arr2[] = "sorry";
my_strncat(arr1, arr2, 2);
printf("%s\n", arr1);
return 0;
}
strcmp
int strcmp(const char* str1, const char* str2)
- 第一个字符串大于第二个字符串,返回大于0的数字
- 第一个字符串等于第二个字符串,返回0
- 第一个字符串小于第二个字符串,返回小于0的数字
strcmp的模拟实现:
#include <stdio.h>
#include <assert.h>
#include <string.h>
int my_strcmp(char* str1, char* str2)
{
assert(str1 && str2);
//比较
while (*str1 == *str2)
{
if (*str1 == '\0')//两个都是'\0'
return 0;
str1++;
str2++;
}
if (*str1 > *str2)
return 1;//大于
else
return 0;//小于
}
int main()
{
char* p1 = "abcdef";
char* p2 = "aqwer";
int ret = strcmp(p1, p2);//先比较两字符串的首地址的ASCLL码值,相等向后延伸比较
printf("%d\n", ret);
return 0;
}
strncpy
char *strncpy( char *strDest, const char *strSource, size_t count )
- 如果源字符串小于拷贝的字符串,拷贝过去后面补'\0'
-
举例:
int main()
{
char arr1[30] = "hello\0xxxxxx";
char arr2[] = "world";
//指定长度的增加
strncat(arr1, arr2, 3);//将arr2前3个值拷贝到arr1中,拷贝完后系统自动加'\n'
printf("%s\n", arr1);
}
模拟实现
char* my_strncpy(char* dest, const char* src, size_t num)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
while (num--)
{
*dest++ = *src++;
}
return ret;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "haoren";
my_strncpy(arr1, arr2, 3);
printf("%s\n", arr1);
return 0;
}
strncmp
int strncmp(const char *string1, const char *string2, size_t count);
举例:
int main()
{
//strcmp - 字符串比较
const char* p1 = "abcdef";//指向的是常量字符串,最好用const修饰
const char* p2 = "abcqwer";
//int ret = strcmp(p1, p2);//返回的是大于、小于、等于0的数字
int ret = strncmp(p1, p2, 3);//可以限制比较的字符个数 返回的是大于、小于、等于0的数字 (同strcmp)
printf("%d\n", ret);
return 0;
}
strstr - 查找字符串
char *strstr(const char *string, const char *strCharSet);因为是查找,不希望改变两个字符串,用const
举例:
int main()
{
//NULL - 空指针
//NUll/Null - '\0'
char* p1 = "abcdefghi";
char* p2 = "def";
char* ret = strstr(p1, p2);//在p1里面查找p2是否存在
if (ret == NULL)
printf("子串不存在\n");
else
printf("%s\n", ret);//defghi 找的是d地址第一次出现后面的字符串打印
return 0;
}
strtok
char* strok(char* str, const char* sep)
- sep参数是个字符串,定义了用作分隔符的字符集合
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
- strtok函数找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针(注:strtok函数会改变操作被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可以被修改)
- strtok函数的第一参数不为NULL,函数将找到的str中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一参数为NULL,函数将在同一字符串中被保存的位置开始,查找一下个标记。
- 如果字符串不存在更多的标记,则返回NULl指针。
-
举例:
-
int main() { //zpw@bitedu.tech //char arr[] = "zpw@bitedu.tech"; char* p = "@."; char arr[] = "192.168.1.3"; char* p = ".";//把分隔符传过来 char buf[1024] = {0}; //切割buf中的字符串 strcpy(buf, arr); char* ret = NULL; for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))//strtok会记住上次分割的位置,下次从要分割的位置开始寻找,所以传空指针 { printf("%s\n", ret); } //简单举例 //char* ret = strtok(arr, p); //printf("%s\n", ret);//返回的是s的地址,并将@改成'\0' //char* ret1 = strtok(NULL, p);//第二次以后不需要传数组地址,传空指针 //printf("%s\n", ret1);//返回的是b的地址,并将.改成'\0' //char* ret2 = strtok(NULL, p); //printf("%s\n", ret2); return 0; }
strerror
-
char* strerror(int errnum)
返回错误码对应的错误信息。
-
举例:
-
int main() { //char* ret = strerror(1); //printf("%s\n", ret); //错误码 错误信息 //0 No error //1 Operation not permitted //2 No such file or directory //... //erron 是一个全局的错误码的变量 //当c语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值到errno中 //char* str = strerror(errno); //printf("%s\n", str); //打开文件 FILE* pf = fopen("test.txt", "r");//打开text.txt文件,r是读文件 if (pf == NULL) { printf("%s\n", strerror(errno)); } else printf("open file sccess\n"); return 0; }
字符转换:
-
int tolower( int c) 将字符转换成小写
-
int toupper( int c) 将字符转换成大写
-
举例:
#include <ctype.h>
int main()
{
//char ch = '1';
int ret = islower(ch);//判断是否是小写字母,是返回大于0的数字
//int ret = isdigit(ch);
//printf("%d\n", ret);
//char ch = tolower('q');//字母转小写函数
//putchar(ch);
char arr[] = "I AM A Student";
int i = 0;
while (arr[i])
{
if (isupper(arr[i]))
{
arr[i] = tolower(arr[i]);
}
i++;
}
printf("%s\n", arr);
return 0;
}
memcpy
void *memcpy(void *dest, const void *src, size_t count);
- trcpy 只能拷贝字符串,不能拷贝数组 数组拷贝用memcpy
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置
- 这个函数在遇到'\0'的时候不会停下来
- 如果source和destination有任何的重复,复制的结果都是未定义的
-
举例:
-
struct S { char name[20]; int age; }; int main() { int arr1[] = { 1, 2, 3, 4, 5}; int arr2[5] = { 0 }; struct S arr3[] = { {"张三", "23"}, {"李四", "24"} }; struct S arr4[4] = {0}; memcpy(arr4, arr3, sizeof(arr3)); //memcpy(arr2, arr1, sizeof(arr1));//拷贝arr1的大小,5个字节 return 0; }
模拟实现:
-
#include <stdio.h> #include <assert.h> struct S { char name[20]; int age; }; void* my_memcpy(void* dest, void* src, size_t num) { void* ret = dest; assert(dest != NULL); assert(src != NULL); while (num--)//一共拷贝num次,单位字节 { *(char*)dest = *(char*)src;//因为不清楚src里面放置的内容,通过一个一个字节进行拷贝 ++(char*)dest;//先转换,再++ ++(char*)src; } return ret;//最后返回起始位置的地址 } int main() { int arr1[] = { 1, 2, 3, 4, 5}; int arr2[5] = { 0 }; struct S arr3[] = { {"张三", "23"}, {"李四", "24"} }; struct S arr4[4] = {0}; memcpy(arr4, arr3, sizeof(arr3)); return 0; }
memmove
-
void* memmove(void* destination, const void* source, size_t num)
处理重叠拷贝的情况
-
举例:
-
int main() { int arr[] = {1,2,3,4,5,6,7,8,9,10}; int i = 0; memmove(arr+2, arr, 20); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
memcmp -内存比较
-
int memcmp(const void* ptr1, const void* ptr2, size_t num)