• C进阶-字符串和内存函数


    • 文章目录

    • 一、求字符串长度
    • 二、长度不受限制的字符串函数
    • 三、长度受限制的字符串函数介绍
    • 四、字符串查找
    • 五、错误信息报告
    • 六、字符操作
    • 七、内存操作函数

    前言

    C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符串数组中。字符串常量适用于那些对他不做修改的字符串函数


    1.函数介绍:

    长度不受限制的字符串函数:strcpy,strcat,strcmp

    长度受限制的字符串函数:strncpy,strncat,strncmp

    1.1strlen

    size_t strlen ( const char * str );

    字符串已经'\0' 作为结束标志,strlen函数返回的是在字符串中'\0' 前面出现的字符个数(不包含'\0' )。

    参数指向的字符串必须要以'\0' 结束。

    注意函数的返回值为size_t,是无符号的( 易错)

    学会strlen函数的模拟实现

    1. // int main()
    2. // {
    3. // if ((int)strlen("abc") - (int)strlen("abcdef") > 0)
    4. // {
    5. // printf("大于\n");
    6. // }
    7. // else
    8. // {
    9. // printf("小于等于\n");
    10. // }
    11. // return 0;
    12. // }
    13. //1
    14. size_t my_strlen(const char* str)
    15. {
    16. int count = 0;
    17. while (*str != '\0')
    18. {
    19. count++;
    20. str++;
    21. }
    22. return count;
    23. }
    24. //2.指针-指针
    25. //3.递归的方法
    26. int main()
    27. {
    28. size_t sz = my_strlen("abc");
    29. printf("%d\n",sz);
    30. return 0;
    31. }

     1.2 strcpy

    char* strcpy(char * destination, const char * source );

    Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
    源字符串必须以 '\0'结束。
    会将源字符串中的 '\0'拷贝到目标空间。
    目标空间必须足够大,以确保能存放源字符串。
    目标空间必须可变。
    学会模拟实现。

    1. char* my_strcpy(char* dest,const char* src)
    2. {
    3. char* ret = dest;
    4. assert(dest != NULL); //断言,dest不为空指针
    5. assert(src != NULL);
    6. // while(*src != '\0')
    7. // {
    8. // *dest = *src;
    9. // dest++;
    10. // src++;
    11. // }
    12. // *dest = *src; // \0
    13. while(*dest++ = *src++)
    14. {
    15. ;
    16. }
    17. return ret;
    18. }
    19. int main()
    20. {
    21. char arr1[20] = "hello xiaofan";
    22. //char arr2[40] = "hello xiaofan";
    23. char arr2[] = "xxxxx";
    24. //strcpy(arr1,arr2);
    25. my_strcpy(arr1,arr2);
    26. printf("%s\n",arr1);
    27. return 0;
    28. }

    1.3 stract

    char * strcat ( char * destination, const char * source );

    Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
    源字符串必须以 '\0'结束。
    目标空间必须有足够的大,能容纳下源字符串的内容。
    目标空间必须可修改。

    1. char* my_strcat(char* dest,const char* src)
    2. {
    3. assert(dest != NULL);
    4. assert(src != NULL);
    5. char* ret = dest;
    6. //1.找到目标空间中的\0
    7. while (*dest != '\0')
    8. {
    9. dest++;
    10. }
    11. while (*dest++ = *src++)
    12. {
    13. ;
    14. }
    15. return ret;
    16. }
    17. int main()
    18. {
    19. char arr1[20] = "hello ";
    20. char arr2[] = "world";
    21. //strcat(arr1,arr2);
    22. my_strcat(arr1,arr2);
    23. printf("%s\n",arr1); //helloworld
    24. return 0;
    25. }

    1.4 strcmp

    int strcmp ( const char * str1, const char * str2 );

    标准规定:

        第一个字符串大于第二个字符串,则返回大于0的数字

        第一个字符串等于第二个字符串,则返回0
        第一个字符串小于第二个字符串,则返回小于0的数字

        那么如何判断两个字符串?

    1. int my_strcmp(const char* str1,const char* str2)
    2. {
    3. assert(str1 && str2 != NULL);
    4. while (*str1 == *str2)
    5. {
    6. if (*str1 == '\0')
    7. {
    8. return 0;
    9. }
    10. str1++;
    11. str2++;
    12. }
    13. // if(*str1 > *str2)
    14. // {
    15. // return 1;
    16. // }
    17. // else
    18. // {
    19. // return -1;
    20. // }
    21. return (*str1 - *str2);
    22. }
    23. int main()
    24. {
    25. //char arr1[] = "abcdef\0";
    26. //char arr2[] = "abcddddd\0";
    27. int ret = my_strcmp("abcdefa","abcdefb"); //-1
    28. printf("%d\n",ret);
    29. return 0;
    30. }

    1.5 strncpy

    char * strncpy ( char * destination, const char * source, size_t num );

    拷贝num个字符从源字符串到目标空间。
    如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

    1. int main()
    2. {
    3. char arr1[20] = "abcdef";
    4. char arr2[] = "ab";
    5. strncpy(arr1,arr2,4);
    6. printf("%s\n",arr1);
    7. return 0;
    8. }

    1.6 strncat

    char * strncat ( char * destination, const char * source, size_t num ); 

    1. int main()
    2. {
    3. char arr1[20] = "abcdef";
    4. char arr2[] = "ab";
    5. strncat(arr1,arr2,0);
    6. printf("%s\n",arr1);
    7. return 0;
    8. }

    1.7 strncmp

    int strncmp ( const char * str1, const char * str2, size_t num )

    1. int main()
    2. {
    3. char arr1[] = "abcqbertyui";
    4. char arr2[] = "abcqcfg";
    5. printf("%d\n",strncmp(arr1,arr2,5));
    6. return 0;
    7. }

     1.8 strstr  -字符串中找子字符串

    char * strstr ( const char *, const char * );

    1. char* my_strstr(const char* str1,char* str2)
    2. {
    3. assert(str1 && str2 != NULL);
    4. char* cp = str1;
    5. char* s1 = cp;
    6. char* s2 = str2;
    7. while (*cp)
    8. {
    9. //开始匹配
    10. s1 = cp;
    11. s2 = str2;
    12. while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
    13. {
    14. s1++;
    15. s2++;
    16. }
    17. if (*s2 == '\0')
    18. {
    19. return cp;
    20. }
    21. cp++;
    22. }
    23. return NULL;
    24. }
    25. int main()
    26. {
    27. char arr1[] = "abcdefabcdef";
    28. //char arr2[] = "deq"; //null
    29. char arr2[] = "def";
    30. //char* ret = strstr(arr1,arr2);
    31. char* ret = my_strstr(arr1,arr2);
    32. if (ret != NULL)
    33. {
    34. printf("%s\n",ret);
    35. }
    36. else
    37. {
    38. printf("找不到\n");
    39. }
    40. return 0;
    41. }

     1.9 strtok

    char * strtok ( char * str, const char * sep );

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

    第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。


    strtok函数找到str中的下一个标记,并将其用 \0结尾,返回一个指向这个标记的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)


    strtok函数的第一个参数不为 NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。 strtok函数的第一个参数为 NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。


    如果字符串中不存在更多的标记,则返回 NULL指针。

    1. int main()
    2. {
    3. char arr[] = "fsy@qq.com@77#2222";
    4. char copy[20];
    5. strcpy(copy,arr);
    6. char sep[] = "@.#";
    7. // char* ret = strtok(copy,sep);
    8. // printf("%s\n",ret);
    9. // ret = strtok(NULL,sep);
    10. // printf("%s\n",ret);
    11. // ret = strtok(NULL,sep);
    12. // printf("%s\n",ret);
    13. char* ret = NULL;
    14. for(ret = strtok(copy,sep); ret != NULL; ret = strtok(NULL,sep))
    15. {
    16. printf("%s\n",ret);
    17. }
    18. return 0;
    19. }

     1.10 strerror

    char * strerror ( int errnum );  

    返回错误码,所对应的错误信息

    库函数在执行的时候吗,发生了错误,会将一个错误码放在errno这个变量中

    errno是C语言提供的一个全局的变量

    1. int main()
    2. {
    3. int i = 0;
    4. for (i= 0; i < 10; i++)
    5. {
    6. printf("%s\n",strerror(i));
    7. }
    8. return 0;
    9. }
    10. int main()
    11. {
    12. //C语言中可以操作文件
    13. //操作文件的步骤
    14. //1.打开文件
    15. //2.读/写文件
    16. //3.关闭文件
    17. //FILE* pf = fopen("/Users/fan/Documents/c_study/c_test20/data.txt","r");
    18. FILE* pf = fopen("fan/Documents/c_study","r");
    19. if (pf == NULL)
    20. {
    21. printf("%s\n",strerror(errno));
    22. perror("fopen");
    23. return 1;
    24. }
    25. //读文件
    26. //关闭文件
    27. fclose(pf);
    28. return 0;
    29. }

    1.11字符分类函数

    1. int main()
    2. {
    3. //判断为真是非0,为假是0
    4. //printf("%d\n",isupper('A'));
    5. //printf("%d\n",isdigit('1'));
    6. //字符转换
    7. // printf("%c\n",tolower('A'));
    8. // printf("%c\n",tolower('s'));
    9. char arr[20] = {0};
    10. gets(arr); //遇到空格也会往后读
    11. printf("%s\n",arr);
    12. char* p = arr;
    13. while(*p)
    14. {
    15. if(isupper(*p)) //*p >= 'A' && *p<='Z'
    16. {
    17. *p = tolower(*p); //*p = *p+32
    18. }
    19. p++;
    20. }
    21. printf("%s\n",arr);
    22. return 0;
    23. }

    1.11 memcpy

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

    函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。这个函数在遇到 '\0'的时候并不会停下来。
    如果source和destination有任何的重叠,复制的结果都是未定义的。

    1. //memcpy(void* dest,)
    2. //memcpy 是内存拷贝 拷贝字符串,拷贝整型数组,拷贝结构体数据
    3. // int main()
    4. // {
    5. // // int arr1[] = {1,2,3,4,5,6,7,8,9,10};
    6. // // int arr2[20] = {0};
    7. // float arr1[] = {1.0,2.0,3.0};
    8. // float arr2[5] = {0};
    9. // //将arr1的内容,拷贝到arr2中
    10. // memcpy(arr2,arr1,8);
    11. // int i = 0;
    12. // for (i = 0 ;i < 5; i++)
    13. // {
    14. // printf("%f ",arr2[i]);
    15. // }
    16. // return 0;
    17. // }
    18. //模拟实现
    19. //函数拷贝结束后,返回目标空间的起始地址
    20. void* my_memcpy(void* dest,const void* src,size_t num)
    21. {
    22. assert(dest && src != NULL);
    23. void* ret = dest;
    24. while (num--) //4,3,2,1,0
    25. {
    26. *(char*)dest = *(char*)src;
    27. dest = (char*)dest+1; //强制转换成char* ,跳过一个字节
    28. src = (char*)src+1;
    29. }
    30. return ret;
    31. }
    32. int main()
    33. {
    34. int arr1[] = {1,2,3,4,5,6,7,8,9,10};
    35. //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 00
    36. int arr2[20] = {0};
    37. //my_memcpy(arr2,arr1,21);
    38. //my_memcpy(arr1+2,arr1,21); //memcpy函数是用来处理,不重叠的内存拷贝的
    39. memmove(arr1+2,arr1,20); //memmove函数可以用来处理重叠的内存拷贝
    40. int i = 0;
    41. for (i = 0 ;i < 10; i++)
    42. {
    43. printf("%d ",arr1[i]);
    44. }
    45. return 0;
    46. }

     1.12 memmove

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

    和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。

     

    1. void* my_memmove(void* dest,void* src,size_t num)
    2. {
    3. void* ret = dest;
    4. assert(dest && src != NULL);
    5. if (dest < src)
    6. {
    7. //前->后
    8. while (num--)
    9. {
    10. *(char*)dest = *(char*)src;
    11. dest = (char*)dest +1;
    12. src = (char*)src +1;
    13. }
    14. }
    15. else
    16. {
    17. //后->前
    18. while (num--) //20
    19. {
    20. *((char*)dest + num) = *((char*)src + num);
    21. }
    22. }
    23. return ret;
    24. }
    25. int main()
    26. {
    27. int arr1[] = {1,2,3,4,5,6,7,8,9,10};
    28. //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 00
    29. //int arr2[20] = {0};
    30. //my_memcpy(arr2,arr1,21);
    31. //my_memcpy(arr1+2,arr1,21); //memcpy函数是用来处理,不重叠的内存拷贝的
    32. //memmove(arr1+2,arr1,20); //memmove函数可以用来处理重叠的内存拷贝
    33. my_memmove(arr1+2,arr1,20);
    34. //memcpy(arr1+2,arr1,20);err
    35. int i = 0;
    36. for (i = 0 ;i < 10; i++)
    37. {
    38. printf("%d ",arr1[i]);
    39. }
    40. return 0;
    41. }

    1.13 memcmp

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

    比较从ptr1和ptr2指针开始的num个字节

    1. // int main()
    2. // {
    3. // char arr[] = "hello bit";
    4. // memset(arr+1,'x',4);//以字节为单位设置的
    5. // printf("%s\n",arr); // hxxxx bit
    6. // return 0;
    7. // }
    8. int main()
    9. {
    10. int arr[10] = {0};
    11. //memset(arr,1,10); err
    12. memset(arr,1,40);
    13. return 0;
    14. }

     

  • 相关阅读:
    Python中unittest的数据驱动
    Hyperledger Fabric无系统通道启动及通道的创建和删除
    MySQL索引的类型有哪些?
    基于ARM+FPGA的ISA总线/MMи总线接口转换设计在轨道交通的应用
    为全志T507-H开发板配置Samba服务,高效实现跨系统的文件共享
    第2章 控制结构和函数(编程题)
    Wpf 使用 Prism 实战开发Day04
    如何有效的进行服务器稳定性测试?
    1916. 统计为蚁群构筑房间的不同顺序 费马小定理+快速幂+DFS
    webpack5学习进阶:模块、依赖与扩展功能(PostCSS、Web Works、TypeScript)
  • 原文地址:https://blog.csdn.net/qq_61658398/article/details/133464009