C语言 – 字符函数和字符串函数 (二)
书接上回,本篇博客是笔者欲写的有关字符串函数的第二篇。
4. 字符串查找
这一部分常用两种函数,分别为strstr、strtok
(1). strstr
char * strstr(const char *dest,const char *src);
注意:
a. 函数功能:在目标字符串dest中查找第一次出现源字符串src的位置;
b. 在使用该函数时,需检查该函数输入参数中相关字符串的合法性,并对其进行保护,以下函数模拟亦须如此;
c. 该函数返回在 dest 中第一次出现 src字符串的位置,如果未找到则返回 NULL;
d. 不包含终止符 ‘\0’。
该函数模拟实现如:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char *my_strstr(const char*dst, const char*src)
{
assert(dst != NULL && src != NULL);
const char *p1 = dst;
const char *p2 = src;
int n;
while (*p1)
{
for (n = 0; *(p1 + n) == *(p2 + n); n++)
{
if (!*(p2 + n + 1))
return p1;
}
p1++;
}
return NULL;
}
int main()
{
char dst[20] = "abcd12ghi123hjj";
char *src = "123";
printf("%s \n", dst);
char *s = my_strstr(dst, src);
//printf("%s \n", dst);
printf("%s \n", s);
system("pause");
return 0;
}
(2). strtok
char * strtok ( char * str, const char * sep );
a. sep参数是个字符串,定义了用作分隔符的字符集合;
b. 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
c. strtok函数找到str中的下一个标记,并将其用\0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
d. strtok函数的第一个参数不为NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
e. strtok函数的第一个参数为NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
f. 如果字符串中不存在更多的标记,则返回NULL 指针。
该函数的调用示例:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "- This, a sample string.";
char * pch;
printf("Splitting string \"%s\" into tokens:\n", str);
pch = strtok(str, " ,.-");
while (pch != NULL)
{
printf("%s\n", pch);
pch = strtok(NULL, " ,.-");
}
system("pause");
return 0;
}
编译结果如下:
5. 错误信息报告
该部分在C语言中常用函数之一为 strerror.
char * strerror( int errnum);
a. 函数功能:返回错误码对应的错误信息;
b. 若想调用该函数,需添加 errno.h 头文件。
该函数的调用方式如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <errno.h>//必须包含的头文件
int main()
{
FILE * pFile;
pFile = fopen("unexist.ent", "r");
if (pFile == NULL)
printf("Error opening file unexist.ent: %s\n", strerror(errno));
//errno: Last error number
system("pause");
return 0;
}
编译结果如下:
6. 内存操作函数
该部分主要讲述一下几个函数:
内存操作函数:(需设定所应用的内存字节数)
(1)memset:内存设置函数,相当于初始化,往内存中存入自设的值(任何类型),但需注意,内存的开辟应该是所存数据数据类型的总字节数,如memset(br,0,sizeof(int)*10), br 是int型数组,开辟40个字节空间, 该程序功能为将 br 字符串中的前 40 个字节的内容全部置0;
void * memset(void * destination, int ch, size_t num);
(2)memcpy:内存拷贝函数,如: memcpy(br,ar,sizeof(int)*10) ,将ar内存中sizeof(int)*10)字节的数据拷贝到br中;
void * memcpy ( void * destination, const void * source, size_t num );
(3)memmove:相当于内存拷贝函数,如果源空间和目标空间出现重叠,就得使用memmove函数处理。避免出现内存重叠;
void * memmove ( void * destination, const void * source, size_t num )
(4)memcmp:内存比较函数,如:memcmp(ar,br,sizeof(int)*5),比较ar与br数组内存中sizeof(int)*5个字节的数据。
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
以上函数都是对内存中的内容直接进行操作,不需要关注内存中内容的类型。
memcpy 之模拟实现:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void *my_memcpy(void *dst, void *src, size_t count)
{
assert(dst != NULL && src != NULL);
void *p1 = dst;
const void *p2 = src;
while (count--)
{
*(char *)p1 = *(char *)p2;
p1 = (char *)p1 + 1;
p2 = (char *)p2 + 1;
}
return dst;
}
int main()
{
char dst[20] = "abcdefghijk";
char *src = "fgha";
printf("%s \n", dst);
void *s = my_memcpy(dst+2, dst, 4);
printf("%s \n", dst);
printf("%s \n", s);
system("pause");
return 0;
}
memmove 之模拟实现:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void *my_memmove(void *dst, void *src, size_t count)
{
assert(dst != NULL && src != NULL);
char *p1 = dst;
const char *p2 = src;
//printf("%s ", (char *)p1);
//printf("%s ", (char *)p2 + count);
if ((p1 <= p2) || ((char *)p1 >= (char *)p2 + count))//不发生地址重叠
{
while (count--)
{
*(char *)p1 = *(char *)p2;
p1 = (char *)p1 + 1;
p2 = (char *)p2 + 1;
}
}
else//会发生地址重叠
{
p1 = (char *)p1 + count - 1;
p2 = (char *)p2 + count - 1;
while (count--)
{
*(char *)p1 = *(char *)p2;
p1 = (char *)p1 - 1;
p2 = (char *)p2 - 1;
}
}
return dst;
}
int main()
{
char dst[20] = "abcd";
char *src = "fghaasd";
printf("%s \n", dst);
void *s = my_memmove(dst , src, 4);
printf("%s \n", dst);
printf("%s \n", s);
system("pause");
return 0;
}
此处由于笔者自身原因,便不对 memset 和 memcmp 函数进行模拟实现说明。
以上对有关函数进行的模拟实现是用于帮助读者更好的了解对应函数的工作原理。又因为对应函数的正常调用格式与模拟实现中主函数中的调用形式大致相同,所以此处便不再进行赘述!
以上内容中所讲函数不多,总体内容多少会有点残缺,请见谅!