目录
一,字符串函数
1.1 strlen()
size_t strlen (const char* str);
字符串以'\0作为结束标志,strlen函数返回的是在字符串中'\0'前出现的字符个数,不包含'/0',并且参数指向的字符串必须要以'\0'结束,strlen的返回值为size_t,是无符号整数,这个要注意
size_t my_strlen(const char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
void main1()
{
size_t sz = my_strlen("abc");
printf("%u\n", sz);
}
1.2 strcpy()
char* strcpy(char* destination, const char* source);
源字符串必须以'\0'结束,而且拷贝时也会将'\0'拷贝到目标空间,目标空间必须足够大以确保能存放要拷贝的字符串,而且目标空间必须可变,也就是不能是const或常量字符串
下面是使用
void main3()
{
//char arr1[3] = "";
//char arr2[] = "hello bit";
const char* arr1 = "xxxxxxxxxx";
char arr2[6] = { 'a', 'b', 'c', 'd', 'e' , '\0'};
strcpy(arr1, arr2);
printf("%s\n", arr1);
}
下面是模拟实现和测试
char* my_strcpy1(char* dest, const char* src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = *src;//还要将\0拷贝过去
return ret;
}
//上面的实现有点麻烦,下面的是简化后的,两个的结果相同
char* my_strcpy2(char* dest, const char* src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
while (*dest++ = *src++) { ; }
return ret;
}
void main3()
{
char arr1[20] = "hello world";
char arr2[] = "xxxxx";
my_strcpy2(arr1 + 6, arr2);
printf("%s\n", arr1);
}
1.3 strcat()
char* strcat (char* destination, const char* source);
字符串追加函数。源字符串必须以'\0'结束,目标空间必须足够大并且可修改
char* my_strcat(char*dest, const char *src)
{
assert(dest && src);
char* ret = dest;
//1. 找目标空间中的\0
while (*dest)
{
dest++;
}
//2. 开始对\0后的数据进行追加
while (*dest++ = *src++)
{
;
}
return ret;
}
void main4()
{
char arr1[20] = "hello ";
char arr2[] = "world";
my_strcat(arr1, arr2);
//my_strcat(arr1, arr1);自己给自己追加,程序直接炸掉
printf("%s\n", arr1);
}
1.4 strcmp()
int strcmp (const char* str1, const char* str2);
字符串比较函数,其规则如下:
①第一个字符串大于第二个字符串,则返回大于0的数组
②第一个字符串等于第二个字符串,返回0
③第一个字符串小于第二个字符串,返回小于0的数字
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);
}
void main5()
{
int ret = my_strcmp("bbq", "bcq");
if (ret > 0) printf(">\n");
printf("%d\n", ret);
}
1.5 strstr()
char* strstr (const char* str1 ,const char* str2);
这个函数表示从一个字符串中找子字符串,找到了返回原字符串中子字符串第一次出现位置的指针,没找到返回NULL
char* my_strstr(char *str1, char* str2)
{
char* cp = str1;
char* s1 = cp;
char* s2 = str2;
if (*str2 == '\0') return str1;
while (*cp)
{
//开始匹配
s1 = cp; //更新开始匹配的位置
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0') return cp;
cp++; //一次找没找到
}
return NULL; //全部找完了也没没找到
}
void main6()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char* ret = my_strstr(arr1, arr2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
}
1.6 strtok()
char* strtok (char* str, const char* sep);
strtok用得不多,但我们作为学习者还是要了解下用法,下面是strtok得使用规则:
①sep参数是个字符串,里面定义了用作分隔符得字符集合
②第一个参数是一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符得标记
③strtok函数窄带str中得下一个标记,并将其尬舞i欸\0,然后返回一个指向这个标记得指针
④strtok会改变原字符串,所以在使用strtok得时候一般都是在临时拷贝得内容上操作
⑤ strtok第一个参数部位NULL,函数将在同一个字符串中被保存得位置开始,查找下一个标记
⑥strtok第一个参数如果为NULL,函数将在同一个字符串被保存得位置开始,查找下一个标记
⑦如果字符串中不存在更多的标记,则返回NULL
有点复杂有点多,直接上代码(strtok了解使用即可,不要求模拟实现)
void main7()
{
char arr[] = "zpengwei@yeah.net@666#777";
char copy[30];
strcpy(copy, arr);
char sep[] = "@.#";
char* ret = NULL;
//有记忆功能
for (ret = strtok(copy, sep); ret != NULL; ret=strtok(NULL, sep))
{
printf("%s\n", ret);
}
}
1.7 strerror
char* strerror (int errnum);
如果库函数在执行的时候发生了错误,会将一个错误码存放进errno这个变量中,errno是C语言提供的一个全局变量
//打印部分错误码信息
void main12()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d: %s\n", i, strerror(i));
//将错误码翻译成错误信息,把错误信息字符串的首字母地址传回来
}
}
通过具体例子来看待这个函数
void main8()
{
FILE* pf = fopen("data.txt", "r"); //此时我们的项目路径下没有data.txt这个文件
if (pf == NULL)
{
printf("fopen: %s\n", strerror(errno));
perror("fopen"); //使用perror和上面打印结果一样
return 1;
}
//读文件
//...
//关闭文件
fclose(pf);
}
1.8 长度受限制的字符串函数
//strncpy
void main9()
{
char arr1[20] = "abcdef";
char arr2[] = "xxx";
strncpy(arr1, arr2, 5);
}
//strncat
void main10()
{
char arr1[20] = "abcdef\0yyyyyyyy";
char arr2[] = "xxxxxxxxx";
strncat(arr1, arr2, 3);
}
//strncmp
void main11()
{
char arr1[] = "abcqwertyuiop";
char arr2[] = "abcdef";
printf("%d\n", strncmp(arr1, arr2, 4));
}
二,内存函数
2.1 memcpy()
void* memcpy (void* destination, const void* source, size_t num);
这个函数会从source位置开始复制num个字节的数据到destination的内存位置,并且遇到\0时不会停下来,可以拷贝任意类型的数据,所以将参数类型设定为void*
使用
//将arr1中的内容,拷贝到arr2中,将arr3的内容拷贝到arr4中
void main12()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
memcpy(arr2, arr1, 40);
// int* int*
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
float arr3[] = { 1.0,2.0,3.0 };
float arr4[5] = { 0 };
memcpy(arr4, arr3, 8);
// float* float*
for (i = 0; i < 5; i++)
{
printf("%f ", arr2[i]);
}
}
模拟实现,函数拷贝结束后,返回目标空间的起始地址
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(src && dest);
while (num--)
{
//为了使参数的void*支持加减,最好用char*,一个字节一个字节地去拷贝
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
void main13()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, 21);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
}
如果想实现数组内的拷贝,比如下面代码
void main14()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
// 1 2 1 2 3 4 5 8 9 10
my_memcpy(arr1+2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
}
我们打算将arr1中的1,2,3,4,5放到3,4,5,6,7的位置上去,但是最后会打印这个
这是因为我们的memcpy是从前面往后面拷贝的,1会覆盖3的位置,2会覆盖4的位置,所以我们再去访问3的位置时最后访问到的还是1,于是造成了上面的情况。
所以memcpy函数是用来处理不重叠的内存拷贝的,如果有重叠的会有专门的函数来解决,就是下面的memmove函数
2.2 memmove()
void* memmove (void* destination, const void* source, size_t num);
和memcoy函数的差别就是memmove函数可以额处理内存重叠情况
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
if (dest < src) //不重叠的情况
{
//前->后
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else //重叠的情况
{
//为了避免重叠问题,从后面往前面拷贝
while (num--)//20
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
//将arr1中的3,4,5,6,7换到前面1,2,3,4,5的位置
void main15()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
// 3 4 5 6 7 6 7 8 9 10
my_memmove(arr1, arr1+2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
}
2.3 memcmp()
int memcmp(const void* ptr1,const void* ptr2, size_T num);
和前面的strcmp函数用法大致相同,memcmp不单单可以比较字符数据
void main16()
{
int arr1[] = { 1,2,1,4,5,6 };
int arr2[] = { 1,2,257 };
int ret = memcmp(arr1, arr2, 10);
printf("%d\n", ret);
}
2.4 memset()
内存设置函数
void main27()
{
char arr1[] = "hello bit";
memset(arr1 + 1, 'x', 4);//以字节为单位设置的
printf("%s\n", arr1);
int arr2[10] = { 0 };
memset(arr2, 1, 40);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
}