C语言字符串篇——常用字符串函数介绍及模拟实现(下)

简介: 笔记

strtok函数


char * strtok ( char * str, const char * sep );(字符串切割函数)


sep 参数是个字符串,定义了用作分隔符的字符集合, sep中放分隔符

第一个参数指定一个字符串,它包含了 0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标记。 第一个参数是待切割的字符串,里面可有分隔符,也可以没有

strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。 找到分割符后,将分隔符变为\0,并且返回a这个位置

1.png

(注: strtok函数会改变被操作的字符串,所以在使用strtok 函数切分的字符串一般都是临时拷贝的内容 并且可修改。) 使用strtok进行切割时,最好临时拷贝一份,不要破坏原数据

strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串 中的位置。 当地一个参数不为NULL时,找到第一个标记(上面标记为@),并把它变为\0,同时它会保存这个分隔符的位置,然后返回a的地址

strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。 当记住上面的位置之后,下一次寻找分隔符,将会从上面所记住的位置开始找,也就是说传参的时候在找到第一个分隔符之前传参要穿地址,找到第一个分隔符之后传参就要传空指针

如果字符串中不存在更多的标记,则返回 NULL 指针, 没有标记时就返回空指针2.png


#include<stdio.h>
#include<string.h>
int main()
{
  char a[] = "123@456#789";
  char b[] = "@#";
  char* ret = strtok(a, b);
  printf("%s\n", ret);
  ret = strtok(NULL, b);
  printf("%s\n", ret);
  ret = strtok(NULL, b);//第三次找到末尾\0,也会停下来
  printf("%s\n", ret);
  return 0;
}

3.png

当俩个分隔符挨着的时候,程序获取不到任何东西,它会直接跳过第二个分隔符

4.png

sterror函数


char * strerror ( int errnum );


errnum 错误码,


C语言中程序执行失败的时候,都会返回一个错误码,sterror是来查看错误码的具体含义的

5.png6.png

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
  //errno:全局错误码存放的全局变量
  FILE *pf=fopen("test.txt", "r");
  if (pf == NULL)
  {
  printf("%s", strerror(errno));
  return 1;
  }
  return 0;
}

字符分类函数


7.png8.png

memcpy函数


void * memcpy ( void * destination, const void * source, size_t num );

内存拷贝函数,将源内容拷贝到目标内容中区,并可以设置所拷贝的字节大小,参数为void *,返回目标的起始地址 ,是为了使这个函数具有通用性,void *不能直接解引用,也不能直接进行指针相减

9.png10.png

模拟实现memcpy函数

void* my_memcpy(void* a,const void* b, size_t s)
{
  assert(a && b);
  void* ret = a;
  while (s--)
  {
  *(char*)a = *(char*)b;
  a=(char*)a+1;
  b=(char*)b+1;
  }
  return ret;
}
int main()
{
  int arr1[] = { 1,23,54,165,56,1,51,65 };
  int arr2[] = { 165,195 };
  my_memcpy(arr1, arr2, 8);
  for (int i = 0; i < 8; i++)
  printf("%d ", arr1[i]);
  return 0;
}


这里最好采用a=(char*)a+1,这个写法比较通用,当写成(char *)a++之后,这个在有些编译器上跑不过去

11.png12.png

memcpy无法实现通过自我拷贝,改变自身的值,因为:这是arr1,将它的值传给arr1+2,arr1每传一个数,原数据就会被改变一次,这里arr1走了四次,原数据就被改变了四次,然后接着赋值13.png


14.png

我们用memcpy函数却能实现,自我拷贝,这里不是我们的模拟函数有问题,而是memcpy函数不用来处理重叠的内存数据处理,应该使用memmove,只不过这里的memcpy能力比较强,完成了memmove应该做的事情


memmove函数


void * memmove ( void * destination, const void * source, size_t num );


跟memcpy参数一样,返回值为目标首地址


15.png

#include<stdio.h>
#include<string.h>
int main()
{
  int arr1[] = { 1,23,54,165,56,1,51,65 };
  int arr2[] = { 165,195 };
  memmove(arr1 + 2, arr1, 12);
  for (int i = 0; i < 8; i++)
  printf("%d ", arr1[i]);
  return 0;
}

模拟实现memmove

16.png

当dest<src时,应该从4开始往后拷贝,即从前向后拷17.png

当两块位置没什么关联的时候,从4-8拷贝或者从8-4拷贝都可以

18.png


当dest>src时,应该从8-4进行拷贝,即从后向前拷贝

19.png


#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* des, const void* src, size_t num)
{
  assert(des && src);
  char* ret = des;
  if (des < src)
  {
  while (num--)
  {
    *(char*)des = *(char*)src;
    des = (char*)des + 1;
    src = (char*)src + 1;
  }
  }
  else
  {
  while (num--)
  {
    *((char*)des + num) = *((char*)src + num);
  }
  }
  return ret;
}
int main()
{
  int arr1[] = { 1,23,54,165,56,1,51,65 };
  int arr2[] = { 165,195 };
  my_memmove(arr1+2, arr1, 12);
  for (int i = 0; i < 8; i++)
  printf("%d ", arr1[i]);
  return 0;
}

20.png

memcmp函数


int memcmp ( const void * ptr1,const void * ptr2,size_t num );

21.png

依旧比较的时ASCII码,num是要比较的字节数大小

22.png

比较方法跟strcmp一样。只不过这里是一个字节一个字节进行比较


memset函数


void *memset( void *dest, int c, size_t count );

22.png



返回值是目标首地址 ,给目标地址设置值,值的具体内容在参数里是int c,size_t是要设置的字节数,中间的int参数可以是字符也可以是整数,因为都是以ASCII码形式存储的

23.png

25.png26.png27.png

这个函数是以字节为单位的,这里将每个字节都改为了1


习题1


写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。


例如:给定s1 =AABCD和s2 = BCDAA,返回1


给定s1=abcd和s2=ACBD,返回0.


AABCD左旋一个字符得到ABCDA


AABCD左旋两个字符得到BCDAA


AABCD右旋一个字符得到DAABC


方法一


int is_left_move(char* arr1, char* arr2)
{
  int str = strlen(arr1);
  int i = 0, j = 0;
  for (i = 0; i < str; i++)
  {
  char tmp = arr1[0];
  for (j = 0; j < str - 1; j++)
  {
    arr1[j] = arr1[j + 1];
  }
  arr1[j] = tmp;
  if (strcmp(arr1, arr2) == 0)
    return 1;
  }
  return 0;
}
int main()
{
  char arr1[] = "abcdef";
  char arr2[] = "bcdefa";
  int z=is_left_move(arr1, arr2);
  if (z == 1)
  printf("是");
  else
  printf("否");
  return 0;
}


方法二


int is_left_move(char* arr1, char* arr2)
{
  int str1 = strlen(arr1);
  int str2 = strlen(arr2);
  if (str1!=str2)
  return 0;
  strncat(arr1, arr1, str1);
  char* ret = strstr(arr1, arr2);
  if (ret == NULL)
  return 0;
  else
  return 1;
}
int main()
{
  char arr1[20] = "abcdef";
  char arr2[] = "bcdefa";
  int z=is_left_move(arr1, arr2);
  if (z == 1)
  printf("是");
  else
  printf("否");
  return 0;
}


将所有的可能性都加进去,然后判断,采用这种方法注意arr1的空间必须足够大,而且可变



相关文章
|
4天前
|
存储 编译器 C语言
C语言:字符函数 & 字符串函数 & 内存函数
C语言:字符函数 & 字符串函数 & 内存函数
11 2
|
7天前
|
C语言
C语言中 字符串和数字的相互转换
C语言中 字符串和数字的相互转换
12 1
|
18天前
|
C语言 C++
C语言利用ASCII码表统计字符串每个字符出现的次数
C语言利用ASCII码表统计字符串每个字符出现的次数
16 0
|
18天前
|
C语言
C语言:字符函数和字符串函数(strlen strcat strcmp strncmp等函数和模拟实现)
C语言:字符函数和字符串函数(strlen strcat strcmp strncmp等函数和模拟实现)
|
20天前
|
存储 C语言
C语言中字符串的引用与数组元素操作
C语言中字符串的引用与数组元素操作
21 0
|
20天前
|
安全 C语言
指针与字符串:C语言中的深入探索
指针与字符串:C语言中的深入探索
15 0
|
1月前
|
存储 C语言
爱上C语言:scanf、gets以及getchar输入字符串你真的懂了吗
爱上C语言:scanf、gets以及getchar输入字符串你真的懂了吗
|
1月前
|
程序员 C语言 开发者
C语言库函数 — 字符串函数(含模拟实现字符串函数)
C语言库函数 — 字符串函数(含模拟实现字符串函数)
37 0
|
1月前
|
算法 C语言
字符串函数-C语言
字符串函数-C语言
|
1月前
|
C语言
【C语言】字符串函数strcpy&&strcat&&strcmp&&strstr的使⽤和模拟实现2
【C语言】字符串函数strcpy&&strcat&&strcmp&&strstr的使⽤和模拟实现