目录
一、strlen
strlen:求字符串长度的,统计的是字符串中\0之前出现的字符个数(不包含 '\0' )
1.参数指向的字符串必须要以 '\0' 结束。
int main()
{
//a b c \0 d e f \0
char arr[] = "abc\0def";
printf("%d\n", strlen(arr));
return 0;
}
此结果输出为 3(\0结束)
2.注意strlen函数的返回值为size_t,是无符号的
#include <string.h>
int main()
{
if (strlen("abc") - strlen("abcdef") > 0)
printf(">\n");
else
printf("<\n");
return 0;
}
对于此代码,大家第一眼看到的肯定是小于,则不然,输出结果为 >
size_t,是无符号的整形(无符号减无符号为无符号),不可能返回负数
3.模拟实现strlen
#include <assert.h>
size_t my_strlen(const char* str)//不会改arr,最好使用const
{
assert(str);//保证str为空指针
const char* start = str;//记录起始位置
const char* end = str;//记录末尾位置
while (*end != '\0')
{
end++;//从a往后走直到指向\0
}
return end - start;//得到指针个数
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
运行结果:
二、strcpy
strcpy:字符串拷贝
1.源字符串中的 '\0' 拷贝到目标空间
#include <string.h>
int main()
{
char arr[10] = "xxxxxxxxxx";
const char* p = "abcdef";
strcpy(arr, p);
printf("%s\n", arr);
return 0;
}
2.源字符串必须以 '\0' 结束
2.1 没有‘ \0 ’
int main()
{
char arr[10] = "xxxxxxxxx";
char arr2[] = { 'b', 'i', 't'};
strcpy(arr, arr2);
printf("%s\n", arr);
return 0;
}
1.2有‘ \0 ’
#include <stdio.h>
int main()
{
char arr[10] = "xxxxxxxxx";
char arr2[] = { 'b', 'i','\0', 't'};;
strcpy(arr, arr2);
printf("%s\n", arr);
return 0;
}
3.目标空间必须足够大,以确保能存放源字符串
#include <string.h>
int main()
{
char arr[3] = {0};
char arr2[] = "abcdef";
strcpy(arr, arr2);
printf("%s\n", arr);
return 0;
}
4.模拟实现strcpy
char* my_strcpy(char* dest, const char* src)
{
assert(dest);//断言,保证有效性
assert(src);
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "abc";
char arr2[] = "hello bit";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
三、strcat
strcat:字符追加函数
#include <string.h>
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strcat(arr1, arr2);//字符追加函数
printf("%s\n", arr1);
return 0;
}
1.源字符串必须以 '\0' 结束
2.模拟实现strcat
#include <string.h>
#include <stdio.h>
char* my_strcat(char* dest, const char*src)
{
//1.找目标空间中的\0
char* cur = dest;
while (*cur)
{
cur++;
}
//2.拷贝源头数据到\0之后的空间
while (*cur++ = *src++)
{
;
}
return dest;
}
int main()
{
char arr1[20] = "hello \0xxxxxxxxxx";
char arr2[] = "world";
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
四、strcmp
strcmp:字符串比较(比较的是对应位置上字符的大小,而非长度)必须以 '\0' 结束
1.标准规定
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
2.模拟实现strcmp
#include <stdio.h>
#include <string.h>
#include <assert.h>
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()
{
char arr1[] = "abc";
char arr2[] = "abc";
int ret = my_strcmp(arr1, arr2);
if (ret < 0)
printf("arr1<arr2\n");
else if(ret>0)
printf("arr1>arr2\n");
else
printf("arr1==arr2\n");
printf("%d\n", ret);
return 0;
}
五、小结
长度不受限制的字符串:
strcpy
strcat
strcmp
长度受限制的字符串:
strncpy
strncat
strncmp
六、strncpy
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "abcdefghi";
char arr2[] = "xxxx";
strncpy(arr1, arr2, 2);
printf("%s\n", arr1);
return 0;
}
假设:拷贝大于arr的空间
七、strncat
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "abcdef\0qqqqqq";
char arr2[] = "xyz";
strncat(arr1, arr2, 2);
printf("%s\n", arr1);
return 0;
}
八、 strncmp
#include <stdio.h>
#include <string.h>
int main()
{
int ret = strncmp("abcdef", "abc", 3);
printf("%d\n", ret);
return 0;
}
假设比较前四个就是d和\0比较:
九、strstr
strstr: 在一个字符串中找另一个字符串是否存在
存在:返回子串第一次出现的位置
不存在:返回NULL
int main()
{
char arr1[] = "abcdefabcdef";
char arr2[] = "cdq";
char* p = strstr(arr1, arr2);
if (p == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", p);
}
return 0;
}
9.1模拟实现strstr
char* my_strstr(const char* str1, const char* str2)
{
const char* s1 = str1;
const char* s2 = str2;
const char* p = str1;
if (*str2 == '\0')
{
return str1;
}
while (*p)
{
s1 = p;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)p;//找到了
}
p++;
}
return NULL;//找不到子串
}
int main()
{
char arr1[] = "abcdefabcdef";
char arr2[] = "cdq";
char* p = strstr(arr1, arr2);
if (p == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", p);
}
return 0;
}
十、strtok
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
#include <stdio.h>
#include <stdio.h>
int main()
{
char arr[] = "zpengwei@bitedu.com";
char buf[200] = { 0 };//"zpengwei@bitedu.com"
strcpy(buf, arr);
const char* p = "@.";
char* str = strtok(buf, p);
printf("%s\n", str);
str = strtok(NULL, p);
printf("%s\n", str);
str = strtok(NULL, p);
printf("%s\n", str);
//"@."
//strtok();
//zpengwei
//bitedu
//com
return 0;
}
优化:
#include <stdio.h>
#include <stdio.h>
int main()
{
char arr[] = "zpengwei@bitedu.com";
char buf[200] = { 0 };//"zpengwei@bitedu.com"
strcpy(buf, arr);
const char* p = "@.";
char* str = NULL;
for (str=strtok(buf, p); str!=NULL; str=strtok(NULL, p))
{
printf("%s\n", str);
}
return 0;
}
十一、strerror
strerror:把错误码转换成错误信息
#include <stdio.h>
#include <stdio.h>
int main()
{
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
printf("%s\n", strerror(2));
printf("%s\n", strerror(3));
printf("%s\n", strerror(4));
return 0;
}
//错误码记录到错误码的变量中
//errno - C语言提供的全局的错误变量
//#include <errno.h>
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("");//打印的依然是errno变量中错误码对应的错误信息
//printf("%s\n", strerror(errno));
return 1;
}
//读文件
fclose(pf);
pf = NULL;
return 0;
}
十二、字符分类函数:
具体用法可以搜索:cplusplus
里边都有详细介绍
十三、memcpy
一组内存函数:
memcpy
memcmp
memmove
memset
1.memcpy:内存拷贝
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr, 20);
//float arr1[] = { 1.0f,2.0f,3.0f,4.0f };
//float arr2[5] = { 0.0 };
//memcpy(arr2, arr1, 8);
return 0;
}
2.模拟实现memcpy
// memcpy模拟实现
#include <assert.h>
void* my_memcpy(void* dest, void* src, size_t num)//返回类型 viod*
{
void* ret = dest;
assert(dest);//断言,不能为NULL
assert(src);
while(num--)//一次搞定一个字节,一共num个字节
{
*(char*)dest = *(char*)src;//viod*的指针不能直接引用,强制类型转换成char*的指针
dest = (char*)dest + 1;//同理,强制类型转换成char*的指针
src = (char*)src + 1;//不能用 (char*)src++ :++在外边
}
return ret;//不能返回dest,已经不是起始位置,定义ret
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1+2, arr1, 20);
memmove(arr1+2, arr1, 20);
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
float arr3[] = { 1.0f,2.0f,3.0f,4.0f };
float arr4[5] = { 0.0 };
my_memcpy(arr4, arr3, 8);
return 0;
}
问题: 把1 2 3 4 5 放到 3 4 5 6 7上,如果使用memcpy时源空间会和目标空间有重合,拷贝的时候可能会把目标空间的一些数据覆盖掉
需要重新换思路
例如:
总结:
则需要memmove函数
十四、memmove
c语言中重叠内存的拷贝是交给:memmove
void* my_memmove(void* dest, void* src, size_t num)
{
void* ret = dest;
assert(dest);
assert(src);
if (dest < src)//1 前->后
{
while(num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else //2 3 后->前
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
memcpy只需要实现不重叠的拷贝就可以了
memmove是需要实现重叠内存的拷贝的
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1+2, arr1, 20);
return 0;
}
memcpy只需要实现不重叠的拷贝就可以了
memmove是需要实现重叠内存的拷贝的
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
int main()
{
int arr1[] = { 1,2,3,0,5 };//01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 ..
int arr2[] = { 1,2,3,4,0 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ..
int ret = memcmp(arr1, arr2, 13);
printf("%d\n", ret);
return 0;
}
十五、memset
memset:内存设置
测试:
int main()
{
int arr[] = { 1,2,3,4,5 };
memset(arr, 0, 8);
return 0;
}