字符串函数-C语言

简介: 字符串函数-C语言

介绍

字符串函数,简单说,就是处理字符串的函数,头文件是string.h,以下是今天的讲解中会讲到的一系列字符串函数

  • 头文件:#include<string.h>
  • strlen:求字符串长度
  • strcpy:拷贝字符串
  • strcat:追加字符串
  • strcmp:比对字符串
  • strstr:一个字符串中找一个字符串
  • strncpy:拷贝字符串(拷贝指定字符串个数)
  • strncmp:比对字符串(比较指定个数字符个数)
  • strncat:追加字符串(追加指定个数个字符)
  • strtok:提取被分隔字符分隔字符串
  • strerror:可将参数部分错误码对应的错误信息返回

strlen

函数声明:size_t strlen(const char* str);

功能:求字符串长度

使用条件:字符串以'\0'结尾

//函数自实现
#include <assert.h>
int my_strlen(const char* str)
{
  assert(str);
  int count = 0;
  while (*str != '\0') {
    count++;
    str++;
  }
  return count;
}

在库函数实现strlen时,是以'\0'为结尾判断标识的,如果在字符串中间混入了'\0',那么字符串长度的计算就会提前结束,计算的结果也会随之错误;反之,如果字符串结尾没有遇到'\0'那么在计时函数会一直顺着地址找下去,直到找到'\0'为止,这时候strlen返回的结果就是不可预测的了。

此处注明一下sizeof和strlen的区别,首先,sizeof是一个操作符,不是函数,其返回的值是数据类型所占内存大小,可处理的不只是字符串。而strlen恰相反,其只能用来处理字符串并计算其长度。

同时,也要注意到,strlen函数的返回值为size_t:无符号整型。

下面我举一个关于size_t易错的题

//问以下代码的输出结果
#include<stdio.h>
#include<string.h>
int main()
{
    if(strlen("abc") - strlen("abcd") > 0)
        printf("大于\n");
    else 
        printf("小于\n");
    return 0;
}

大家的第一反应是什么呢?我猜应该是输出小于。但仔细想一想,size_t作为无符号整型,相减会产生负数吗?不会的,所以最后的结果是打印大于。

//函数使用样例
#include<stdio.h>
#inlcude<string.h>
int main()
{
    char arr[] = "abcdef";
    int la = strlen(arr);
    printf("%s\n", la);//打印6
    return 0;
}

strcpy

函数声明:char* strcpy(char* destination, const char* source);

功能:将参数source字符串拷贝至参数destination所指的地址

返回值:字符串destination起始地址

使用条件:源字符串必须以'\0',结尾

               目标空间必须大于等于拷贝过去字符所占的空间:包括'\0'

//自实现
#include<assert.h>
char* my_strcpy(char* str1, const char* str2)
{
  assert(str1 && str2);
  char* ret = str1;
  while (*str1++ = *str2++);
  *str1 = *str2;
  return ret;
}
//使用样例
#include<stdio.h>
#include<string.h>
int main() {
  char arr1[20] = "abcdef";
  char arr2[20] = { 0 };
  char* p1 = strcpy(arr2, arr1);
  printf("%s\n", arr2);//打印abcdef
  return 0;
}

strcat

函数声明:char* strcat(char* destination,const char* source);

功能:将source字符串追加到destination字符串末尾

返回值:destination字符串起始地址

使用条件:两字符串均以'\0'结尾

               目标空间可被修改

               destination末尾'\0'会被覆盖

               目标空间足够大

注(追加位置):destination字符串'\0'及其后面

//自实现
char* my_strcat(char* dest, const char* src)
{
  char* ret = dest;
  while (*dest) dest++;
  while (*dest++ = *src++);
  return ret;
}
//样例使用
#inlude<stdio.h>
#inclue<string.h>
int main() {
  char arr1[20] = "abcdef";
    char arr2[] = "cd";
  printf("%s\n",strcat(arr1, arr2));//打印abcdefcd
  return 0;
}

strcmp

函数声明:int strcmp(const char* str1,const char* str2);

功能:比较字符串

返回值:两字符串相同返回0

              前一个字符串在字典排序靠前返回负数

              后一个字符串在字典排序靠前返回正数

注:区分大小写比较,如果不希望区分可参考stricmp

//自实现
int my_strcmp(const char* s1, const char* s2)
{
  while (*s1 == *s2) {
    if (*s1 == '\0')return 0;
    s1++;
    s2++;
  }
  if (*s1 > *s2)return 1;
  else return -1;
}
//代码使用样例
#include<stdio.h>
#include<string.h>
int main() {
  char arr1[] = "abcdef";
  char arr2[] = "cd";
  printf("%d\n", strcmp(arr1, arr2));//打印一个负数
  return 0;
}

strstr

函数声明:char* strstr(const char* str1,const char* str2);

功能:检索str2在str1中第一次出现的位置

返回值: 返回子串str2在str1中第一次出现的位置,找不到返回空指针

//自实现
char* my_strstr(const char* str1,const char* str2)
{
  const char* cur = str1;
  const char* s1 = NULL;
  const char* s2 = NULL;
  if (!*str2)return (char*)str1;
  while (*cur) {
    s1 = cur;
    s2 = str2;
    while (*s1 == *s2) {
      s1++;
      s2++;
    }
    if (*s2 == '\0')return (char*)cur;
    cur++;
  }
  return NULL;
}

以上自实现代码是一份暴力查找版,算法和时间复杂度并不像库函数中那样是最优的,如果想了解真正的内部实现可以去了解KMP算法,此代码只是想让读者更容易了解此函数的功能。

//使用样例
#include<stdio.h>
#include<string.h>
int main() {
  char arr1[20] = "abcdef";
  char arr2[] = "cd";
  printf("%s\n",strstr(arr1, arr2));//打印cdef
  return 0;
}

strncpy

函数声明:char* strncpy(char* destination,const char* source,size_t mun);

功能:与strcpy很相似,只是多累个参数,拷贝指定个数的字符串

返回值:字符串destination起始地址

使用条件:源字符串必须以'\0',结尾

               目标空间必须大于等于拷贝过去字符所占的空间:包括'\0'

注:在拷贝完指定个数字符后,不会在串的末尾再拷贝'\0'

//自实现
#include<assert.h>
char* my_strcpy(char* str1, const char* str2,size_t num)
{
  assert(str1 && str2);
  char* ret = str1;
  while ((*str1++ = *str2++)&&num!=0) num--;
  *str1 = *str2;
  return ret;
}

strncmp

函数声明:int strcmp(const char* str1,const char* str2,size_t num);

功能:和strcmp很相似,但是多了个参数,比较的是指定个数的字符

返回值:两字符串相同返回0

              前一个字符串在字典排序靠前返回负数

              后一个字符串在字典排序靠前返回正数

注:返回值描述的字符串比较的比较是用num个数截掉后的字符串,具体可参考自实现

//自实现
#include<assert.h>
int my_strncmp(const char* arr1, const char* arr2, size_t num)
{
  assert(arr1 && arr2);
  for (int i = 0; i < num; i++) {
    if (*(arr1 + i) == *(arr2 + i));
    else if (*(arr1 + i) > *(arr2 + i)) return 1;
    else return -1;
  }
  return 0;
}
//使用样例
#include<stdio.h>
#include<string.h>
int main()
{
  char arr1[] = "abcdefg";
  char arr2[] = "abcdfea";
  int ret =strncmp(arr1, arr2, 4);
  printf("%d\n", ret);//打印0
  ret = strncmp(arr1, arr2, 5);
  printf("%d\n", ret);//打印一个负数
  return 0;
}

strncat

函数声明: char* strcat(char* destination,const char* source,size_t num);

功能:与strcat功能相似,将source指定个数的字符串追加到destination字符串末尾

返回值:destination字符串起始地址

使用条件:两字符串均以'\0'结尾

               目标空间可被修改

               destination末尾'\0'会被覆盖

               目标空间足够大

注:destination字符串'\0'及其后面

       追加num个字符后会自动添加'\0'        

//自实现
#include<assert.h>
char* my_strncat(char* arr1, const char* arr2, size_t num)
{
  assert(arr1 && arr2);
  char* ret = arr1;
  while (*arr1)arr1++;
  for (int i = 0; i < num; i++) {
    *(arr1 + i) = *(arr2 + i);
  }
  *(arr1 + num) = '\0';
  return ret;
}
//使用样例
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
  char arr1[20] = "abcdefg";
  char arr2[20] = "rhmotyi";
  char* pc = strncat(arr1, arr2, strlen(arr2));
  printf("%s\n", pc);    //打印abcdefgrhmotyi
  pc = strncat(arr1, arr2, strlen(arr2) - 2);
  printf("%s\n", pc);    //打印abcdefgrhmotyirhmot
  return 0;
}

strtok

函数声明:char* strtok(char* str, const char* sep);

功能:提取被分隔字符分隔字符串

          其中:sep里面放的是分隔符;str里面放的是带分隔符的字符串

          调用一次,将最首先找到的分隔符变成'\0',并标记下一个位置

返回值:上一次标记位置(如第一次调用则返回str首元素地址)

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

注:strtok第一个参数不为NULL时,函数找到str中第一个标记,保存在其字符串中的位置

      strtok第一个参数为NULL时,函数将从被保存的位置开始,寻找下一个标记

      strtok内部其实存在静态变量,运行结束后上一次运行数据会有存留(也就是标记地址)

//使用样例
#include <stdio.h>
#include <string.h>
int main()
{
  const char* p = "@.";
  char arr[] = "zhangsan@1623.com";
  char* s = strtok(arr, p);
  printf("%s\n", s);//zhangsan
  s = strtok(NULL, p);
  printf("%s\n", s);//1623
  s = strtok(NULL, p);
  printf("%s\n", s);//com
  return 0;
}

但是上面的代码似乎有点冗杂,你完全可以写在循环中,见代码

//使用样例(循环版)
#include <stdio.h>
#include <string.h>
int main()
{
  const char* p = "@.";
  char arr[] = "zhangsan@1623.com";
  //char* s = strtok(arr, p);
  //printf("%s\n", s);//zhangsan
  //s = strtok(NULL, p);
  //printf("%s\n", s);//1623
  //s = strtok(NULL, p);
  //printf("%s\n", s);//com
  for (char* s = strtok(arr, p); s != NULL; s = strtok(NULL, p))
    printf("%s\n", s);
  return 0;
}

这两份代码打印出来的结果是相同的

strerror

函数声明:char* strerror(int errnum);

功能:可以将参数部分错误码对应的错误信息字符串返回

C语言规定了一些错误码,放在errno.h这个头文件中说明

//样例使用
#include <stdio.h>
#include <string.h>
int main()
{
  for (int i = 0; i < 10; i++)
    printf("%d:%s\n",i, strerror(i));
  return 0;
}

下面是输出结果

结语

那么本篇博客到这里就要结束了,我们介绍了大部分在平时coding中可能运用到的字符串函数,以及一些函数的自实现,大家可以看看,更利于对函数的了解。如果觉得这篇博客对你有帮助的话,还请点个小赞收藏一下再走啊,如果本篇博客有任何错误也欢迎在评论区讨论或者私我哦--比心♥

相关文章
|
1月前
|
C语言 C++
【C语言】解决不同场景字符串问题:巧妙运用字符串函数
【C语言】解决不同场景字符串问题:巧妙运用字符串函数
|
22天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
19 0
|
1月前
|
存储 安全 编译器
深入C语言库:字符与字符串函数模拟实现
深入C语言库:字符与字符串函数模拟实现
|
1月前
|
C语言
C语言常见字符函数和字符串函数精讲
C语言常见字符函数和字符串函数精讲
|
1月前
|
C语言
【C语言】模拟实现深入了解:字符串函数
【C语言】模拟实现深入了解:字符串函数
|
3月前
|
安全 程序员 C语言
【C语言】字符串函数及其模拟实现
【C语言】字符串函数及其模拟实现
|
3月前
|
C语言
【C语言篇】字符和字符串以及内存函数详细介绍与模拟实现(下篇)
perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。
61 0
|
3月前
|
存储 安全 编译器
【C语言篇】字符和字符串以及内存函数的详细介绍与模拟实现(上篇)
当然可以用scanf和printf输入输出,这里在之前【C语言篇】scanf和printf万字超详细介绍(基本加拓展用法)已经讲过了,这里就不再赘述,主要介绍只针对字符的函数.
54 0
|
4月前
|
存储 缓存 C语言
【C语言】字符函数,字符串函数,内存函数
C语言中的字符串函数和内存函数
54 0
【C语言】字符函数,字符串函数,内存函数
|
5月前
|
C语言
【c语言】字符串函数的模拟实现(二)
【c语言】字符串函数的模拟实现(二)
25 1