目录

  • 1.求字符串长度
    • strlen
      • 模拟实现strlen
  • 2.长度不受限制的字符串函数
    • strcpy
      • 模拟实现strcpy
    • strcat
      • 模拟实现strcat
    • strcmp
      • 模拟实现strcmp
  • 3.长度受限制的字符串函数介绍
    • strncpy
      • 模拟实现strncpy
    • strncat
      • 模拟实现strncat
    • strncmp
      • 模拟实现strncmp
  • 4.字符串查找
    • strstr
      • 模拟实现strstr
    • strtok
  • 5.错误信息报告
    • strerror

C语言中,本身没有字符串类型的,字符串通常以字符数组和常量字符串的形式出现。

而有一些库函数可以对字符串进行操作,使我们对字符串的处理可以简单许多,但是注意的是:这些库函数不可以修改常量字符串


1.求字符串长度

strlen

size_t strlen ( const char * str );

由于strlen返回无符号整形,所以这里是一个易错点,以接下来的代码为例

#include <stdio.h>
#include <string.h>
int main()
{char str1[] = "abcdefg";char str2[] = "abcdefghijk";if (strlen(str1) - strlen(str2) < 0)printf("str1长度小于str2长度");elseprintf("str1长度大于str2长度");return 0;
}

str1长度为7,str2长度为11,7-11 = -3,但是这里的7和11是无符号整形,他们俩相减会得到一个非常大的数,而不是-3,所以这个程序会输出str1长度大于str2长度


模拟实现strlen

这里有三种方法进行模拟实现

第一种:常规方法:

#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strlen1(const char* str)
{assert(str != NULL);int count = 0;while (*str != '\0'){count++;str++;}return count;
}

第二种:递归:

#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strlen2(const char* str)
{assert(str != NULL);if (*str != '\0'){return 1 + my_strlen2(str+1);}else{return 0;}
}

第三种:指针相减:

#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strlen3(const char* str)
{assert(str != NULL);const char* start = str;while (*str != '/0'){str++;}return str - start;
}

两个指向同一块空间的两个指针,两个指针相减得到这两个指针间的元素的个数


2.长度不受限制的字符串函数

strcpy

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

strcpy的使用:

#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = {0};char arr2[] = "abcdef";strcpy(arr1, arr2);printf("%s\n", arr1);return 0;
}

如果在源字符串中提前放一个\0,那么函数只会拷贝到\0

#include <stdio.h>
#include <string.h>int main()
{char arr1[20] ="xxxxxxx";char arr2[] = "ab\0cdef";strcpy(arr1, arr2);return 0;
}

这里可以看到,在arr2ab后面放了一个\0,则在函数拷贝时只会拷贝ab\0

我们可以调试函数看一下:拷贝前的arr1

拷贝后的arr1

可以看到,只拷贝了ab\0


模拟实现strcpy

最常规写法:

#include <stdio.h>
#include<assert.h>
#include <string.h>char* my_strcpy(char* destination, const char* source)
{char* ret = destination;assert(destination && source );while (*source!='\0'){*destination =  *source;destination++;source++;}*destination = *source;//拷贝\0return ret;
}

这么要注意的一点就是,strcpy拷贝过程中会源字符串中最后的\0,但是如果以while (*source!='\0')为循环条件的话,最后的\0就不会被拷贝
所以要在循环外部额外再拷贝一次*destination = *source;

简化一点:

#include <stdio.h>
#include<assert.h>
#include <string.h>
char* my_strcpy(char* destination, char* source)
{char* ret = destination;assert(destination && source );while (*src != '\0'){*destination++ = *source++;}*destination = *source;//拷贝\0return ret;
}

再简化:

前面的两种写法都需要在循环外部额外再对\0进行拷贝,而下面的写法直接将\0的拷贝也放到了循环中进行

#include <stdio.h>
#include<assert.h>
#include <string.h>
char* my_strcpy(char* destination,const char* source)
{char* ret = destination;assert(destination && source );while (*destination++ = *source++){;}return ret;
}

strcat

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

strcat的使用:

#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "hello";char arr2[] = " world";strcat(arr1, " world");printf("%s", arr1);return 0;}

当一个字符串,自己对自己追加的时候会有问题:
以字符串abcdef追加自己为例


从\0开始追加,a追加到f,本来f后面是\0,到了\0就停止追加,但是前面追加时已经就将\0覆盖了,所以不会停止

所以当一个字符串自己追加自己,会发生死循环


模拟实现strcat

#include <stdio.h>
#include<assert.h>
#include <string.h>char* my_strcat(char* des, char* src)
{assert(des && src);char* ret = des;while (*des != '\0'){des++;}while (*des++ = *src++){;}return ret;
}

strcmp

int strcmp ( const char * str1, const char * str2 );
  • 标准规定(在非VS环境中):

    • 第一个字符串大于第二个字符串,则返回大于0的数字
    • 第一个字符串等于第二个字符串,则返回0
    • 第一个字符串小于第二个字符串,则返回小于0的数字
  • 而在VS环境中:

    • 第一个字符串大于第二个字符串,则返回1
    • 第一个字符串等于第二个字符串,则返回0
    • 第一个字符串小于第二个字符串,则返回-1

对于两个字符串的大小,比较的并不是字符串的长度,而是一个一个比较组成字符串的字符,字符对应ASCII码值大的字符大。例如:'z'大于'a'


模拟实现strcmp

#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strcmp(char* str1,char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}//VS环境下:if (*str1 > *str2)return 1;elsereturn -1;//非VS环境下://return *str1-*str2;
}

3.长度受限制的字符串函数介绍

上面介绍的都是没有长度限制字符函数,它们都是进行到\0就停止,而接下来的三个函数有长度限制

strncpy

char * strncpy ( char * destination, const char * source, size_t num );
//验证strncpy是不会在拷贝后自动加'\0'的
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "xxxxxxx";char arr2[] = "abcdef";strncpy(arr1, arr2,2);return 0;
}

arr2前2个字符拷贝到arr1中,在监视中看到:

所以可知:strncpy不会自动添加\0

  • num比源字符串要长,多出来的部分用\0来补
//验证num比源字符串要长,多出来的部分用\0来补
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "xxxxxxxxxxxxx";char arr2[] = "abc";strncpy(arr1, arr2,6);return 0;
}


模拟实现strncpy

#include <stdio.h>
#include<assert.h>
#include <string.h>char* my_strncpy(char* str1, char* str2, int n)
{char* ret = str1;assert(str1 && str2);if (n < 0) return;while (n>0){if (*str2 == '\0'){*str1 = '\0';str1++;n--;}else{*str1 = *str2;str1++;str2++;n--;}}return ret;
}

这里模拟实现时,要注意当num大于源字符串长度时需要补\0这点,其余地方很简单


strncat

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

模拟实现strncat

#include <stdio.h>
#include<assert.h>
#include <string.h>char* my_strncat(char* str1, char* str2, int n)
{char* ret = str1;assert(str1 && str2);if (n < 0) return;while (*str1 != '\0'){str1++;}while (n > 0){if (*str2 == '\0'){*str1 = '\0';str1++;n--;}else{*str1 = *str2;str1++;str2++;n--;}}*str1 = '\0';return ret;
}

strncmp

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

模拟实现strncmp

#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strncmp(char* str1, char* str2, int n)
{assert(str1 && str2);if (n < 0) return;while (n > 0){while (*str1 == *str2){if (n == 1){return 0;}str1++;str2++;n--;}if (*str1 > *str2)return 1;elsereturn -1;}
}

4.字符串查找

strstr

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

模拟实现strstr

#include <stdio.h>
#include<assert.h>
#include <string.h>void* my_strstr(char* str1, char* str2)
{assert(str1 && str2);if (*str2 == '0'){return (char*)str1;}const char* s1 = str1;const char* s2 = str2;const char* cp = str1;while (*cp){s1 = cp;s2 = str2;while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '0'){return (char*)cp;}cp++;}return NULL;
}

strtok

char * strtok ( char * str, const char * sep );
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "abc#defa|gh";char arr2[] = "#|";strtok(arr1,arr2);
}

有一个字符串abc#defa|gh,可以看出它被字符#|分隔开,strtok的作用是取出被字符#|分隔开的每块字符串

#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "abc#defa|gh";char arr2[] = "#|";char arr3[20] = { 0 };strcpy(arr3, arr1);//防止strtok直接修改被操作的字符串,所以需要拷贝一份char* ret = strtok(arr3, arr2);printf("%s", ret);return 0;
}

取出第一块被分隔的字符串abc并且将#改为\0,此时的arr3abc\0defa|ghretabc的地址,输出ret为:

  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。
#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "abc#defa|gh";char arr2[] = "#|";char arr3[20] = { 0 };strcpy(arr3, arr1);//防止strtok直接修改被操作的字符串,所以需要拷贝一份char* ret = strtok(arr3, arr2);printf("%s\n", ret);ret = strtok(NULL, arr2);//为了取出剩下部分的字符串,第一个参数需要改为NULLprintf("%s\n", ret);ret = strtok(NULL, arr2);printf("%s\n", ret);return 0;
}

如果一个字符串被某些字符分隔为很多部分,如果我们一个一个地取出就会使代码冗长,这里我们可以使用循环解决

#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "abc#defa|gh";char arr2[] = "#|";char arr3[20] = { 0 };strcpy(arr3, arr1);char* ret = NULL;for (ret = strtok(arr3, arr2); ret != NULL; ret = strtok(NULL, arr2)){printf("%s\n", ret);}return 0;
}

输出结果:


5.错误信息报告

strerror

char * strerror ( int errnum );

我们可以看一下这些错误码对应的错误信息

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));printf("%s\n", strerror(5));return 0;
}


当然,平常使用时并不需要我们将具体数字传入函数中

我们通常将变量errno传入函数中strerror(errno)
而这个errno变量在头文件errno.h中,使用前必须添加这个头文件。

另外还有一个perror函数,使用这个函数,可以直接将错误信息打印出来,并且如果perror中传了字符串,这个函数会先将传过去的字符串打印出来,再打印一个冒号,最后打印错误信息


C语言中字符串库函数相关推荐

  1. B00009 C语言分割字符串库函数strtok

    切割字符串是常用的处理. 这里给出一个使用函数strtok切割字符串的例子. 使用C语言的库函数strtok来切割字符串的好处在于,可以指定任意字符作为分隔符来切割单词.使用该函数,切割字符串的分隔符 ...

  2. c语言中字符串数组的地址存放以及%s输出单个字符导致程序崩溃的问题

    代码 总结下c语言中字符串数组的地址存放问题 #include <iostream> using namespace std; #include<bits/stdc++.h>i ...

  3. Go语言中字符串的查找方法小结

    这篇文章主要介绍了Go语言中字符串的查找方法小结,示例的main函数都是导入strings包然后使用其中的方法,需要的朋友可以参考下 1.func Contains(s, substr string) ...

  4. [工具]-C语言中字符串的形式打印16进制数据

    C语言中字符串的形式打印16进制数据. 这样写,输出更直观些 #define PRINT_BUF_MAX (32) #define TAG_STRING_MAX (32) static void pr ...

  5. c语言中字符 12是多少,c语言中字符串的讲解(DOC可编).doc

    c语言中字符串的讲解(DOC可编).doc 第一部分:字符串的概念 ---字符串:用双引号引起来的一串字符.在C语言,系统将自动的为字符串添加一个结束标志\0 ,该结束标志不作为字符串的实际长度,但作 ...

  6. C语言中字符串的处理方式(一)

    写多了 Java 代码,对 String 类 很是喜爱,可惜经典的 C 语言没有...最近在做程序过程中,发现对C语言字符串的处理很模糊,一会儿用数组,一会儿用指针,一会儿又引入 string.h.. ...

  7. C语言中字符串的处理方式

    http://www.cnblogs.com/robin-ty/archive/2010/09/03/1817294.html 交流纽带" --<C语言程序设计 现代方法> 写多 ...

  8. C语言中字符串和字符数组的区别

    C语言中字符串和字符数组的区别 1.基本概念 2.代码分析 3.总结 1.基本概念 字符串和字符数组很相似,但是有本质上的区别. (1) C语言中,字符串是双引号括起来的单个或多个字符的集合,编译器自 ...

  9. 有关C语言中字符串入栈的理解

    C语言中字符串的入栈 写在前面 对于C语言中变量入栈的顺序实际上需要具体情况具体分析,不同操作系统下的编译器可能对此有不同的解释,即使对于同一个C的编译器而言,参数设定的不同也会导致编译器调整局部变量 ...

最新文章

  1. 源码分析Handler机制
  2. CSS图片布局 flex(竖着的几张图片改为一排)
  3. 网线主管(信息学奥赛一本通-T1242)
  4. 之前画得太丑了,再来张好看的.我试着改小点.但是就看不清了
  5. 【ElasticSearch】Es 源码之 PersistedClusterStateService 源码解读
  6. WidsMob Viewer Pro Mac如何批量调整照片大小及格式
  7. matlab调用cplex
  8. kettle入门教程
  9. Android apps 拍立知-功能实现(百度tts语音合成使用)
  10. 虚拟服务器的真实ip,虚拟ip和真实ip区别(图文)
  11. AS13 facets cannot be loaded. you can mark them as ignored to suppress this error notification处理
  12. Unity3d Platformer Pro 2D游戏开发框架使用教程
  13. 网上赚钱风口,捡芝麻丢西瓜
  14. 关于数据库突然变得很卡,然后发现数据库文件变的超大的时候
  15. KM算法matlab实现
  16. 2015移动安全挑战赛MSC(第二届)第一题解题思路
  17. 2023-01-05 长亭科技 Go 后端开发实习生二面
  18. matlab演奏七里香,沈员外,起风了,未闻花名,卡农
  19. STM32 SD FatFs读写文件FR_DISK_ERR错误可能原因
  20. 120个huo源地址,快来收藏!

热门文章

  1. angular10 从私服中安装依赖
  2. win7 系统时间服务器地址,win7更新系统时间的服务器地址
  3. matlab静脉识别,GitHub - ChenShihuan/Finger-vein-recognition: 华南理工大学课程设计——手指静脉识别项目...
  4. 双一流学科计算机科学与工程,“双一流”建设高校及建设学科名单
  5. 从建筑角度来看软件体系结构
  6. 王者荣耀cpu测试软件,王者荣耀90帧模式实测:骁龙888对比骁龙865,谁最强?
  7. 用pry阅读ruby源码--以task方法为例
  8. [3]云计算概念、技术与架构Thomas Erl-第7章 云基础设施机制
  9. Oracle 队列锁类型 Oracle Enqueue Lock Type Reference including 11g new locks
  10. 千禧入队问题(2023版)