【C语言航路】第十一站:字符串、字符和内存函数(中)

简介: 【C语言航路】第十一站:字符串、字符和内存函数

4.strcmp

(1)strcmp库函数文档

1.这个函数有两个参数都是const char*类型的,因为我们不会进行修改,我们只会进行查看

2.这个函数的作用是比较两个字符串的大小,比较规则是:从第一个字符依次开始比较,一个字符一个字符比较,谁的ASCII码值大,谁就大。如果相等则比较后一个字符。

3.这个函数的返回值是int类型,如果str1大于str2,则返回一个大于0的数,如果相等则返回0,如果小于则返回小于0的一个数

4.在vs环境下:大于返回1,等于返回0,小于返回-1。但是在其他编译器上不一定成立

(2)strcmp的使用

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

(3)strcmp的模拟实现

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
  assert(str1 && str2);
  while (*str1 == *str2)
  {
    if (*str1 == '\0')
    {
      return 0;
    }
    str1++;
    str2++;
  }
  if (*str1 > *str2)
  {
    return 1;
  }
  else
  {
    return -1;
  }
  //在一些编译器上是这样实现的
  //return *str1 - *str2;
}
int main()
{
  char arr1[] = "abcefg";
  char arr2[] = "abc";
  int ret = my_strcmp(arr1, arr2);
  printf("%d\n", ret);
  return 0;
}

注意事项(函数不安全的原因)

strcpy,strcat,strcmp这些函数都是不安全的函数,因为他们都是长度不受限制的函数,如果目标空间不是很大,则会出现问题。所以我们vs上使用这些函数需要使用开头的那个预处理指令

#define _CRT_SECURE_NO_WARNINGS 1

而为了让这些更安全,我们就有了strncpy,strncat,strncmp这些长度受限制的函数

5.strncpy

(1)strncpy库函数文档

这个函数有三个参数,char* destination,const char* source和size_t num,前两个参数的意思是目标空间的地址和源头的地址,num的意思是要拷贝几个字节

意思是拷贝前num个字节到destination中

返回类型是char*返回destination的地址

(2)strncpy的使用以及注意事项

1.拷贝num个字符从源字符串到目标空间。

2.如下图1所示,如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

3.如下图2所示,我们在使用的时候要注意,不会将最后的\0给拷贝进来,需要拷贝几个字符就拷贝几个字符.

(3)strncpy的模拟实现

需要注意的事项是,由于拷贝受两个条件控制

如果num为0导致的结束的话,也就是拷贝了一部分,那么我们就不会补充\0

如果是由于源头字符串拷贝完了,但是num还没结束导致的结束,那么我们就要补充\0,要注意我们这个num是少减了一次1的,所以要前置--

第一个循环中,num和赋值的操作是不可以进行交换顺序的,这是因为&&的短路现象

#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src, size_t num)
{
  assert(dest && src);
  char* ret = dest;
  while (num && (*dest++ = *src++))
  {
    num--;
  }
  if (num)
  {
    while (--num)
    {
      *dest++ = '\0';
    }
  }
  return ret;
}
int main()
{
  char arr[] = "xxxxxxxxxxxxxxxxxxxxx";
  char* p = my_strncpy(arr, "hello", 10);
  printf("%s\n", p);
  return 0;
}

6.strncat

(1)strncat的库函数文档

这个的参数和返回类型与strncpy是一样的

不同的是函数的功能是追加source的前n的字符

这前n个字符追加后是需要补充一个\0的

(2)strncat的使用以及注意事项

1.对于这个函数,我们需要注意的就是追加之后后面会补充一个\0的

2.即便超出了source的范围,也只是补一个\0,不会补充多个\0

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[] = "xxx\0xxxxxxxxxxxxxxx";
  char* p = strncat(arr, "hello", 3);
  return 0;
}

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[] = "xxx\0xxxxxxxxxxxxxxx";
  char* p = strncat(arr, "hello", 10);
  return 0;
}

(3)strncat的模拟实现

#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
  assert(dest && src);
  char* ret = dest;
  while (*dest != '\0')
  {
    dest++;
  }
  while (num--)
  {
    if ((*dest++ = *src++) == '\0')
    {
      return ret;
    }
  }
  *dest = '\0';
  return ret;
}
int main()
{
  char arr[] = "xxx\0xxxxxxxxxxxxxxx";
  char* p = my_strncat(arr, "hello", 3);
  return 0;
}

7.strncmp

(1)strncmp的库函数文档

函数的功能是比较前n个字符的大小,返回一个值。

如果str1大,则返回大于0的数

如果str2大,则返回小于0的数

如果相等,则返回0

(2)strncmp的使用

比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完

#include<stdio.h>
#include<string.h>
int main()
{
  char* p1 = "abcdef";
  char* p2 = "abcfda";
  int ret = strncmp(p1, p2, 3);
  printf("%d\n", ret);
  return 0;
}

#include<stdio.h>
#include<string.h>
int main()
{
  char* p1 = "abcdef";
  char* p2 = "abcfda";
  int ret = strncmp(p1, p2, 4);
  printf("%d\n", ret);
  return 0;
}

#include<stdio.h>
#include<string.h>
int main()
{
  char* p1 = "abdef";
  char* p2 = "abcfda";
  int ret = strncmp(p1, p2, 4);
  printf("%d\n", ret);
  return 0;
}

8.strstr

(1)strstr库函数文档

这个函数有两个参数,都是const char* 类型的

功能是子str1中查找是否存在str2字符串

返回一个const char* 类型的地址,如果存在,则返回在str1中第一次出现str2的地址,如果不存在,则返回NULL

(2)strstr的使用

#include<stdio.h>
#include<string.h>
int main()
{
  char arr1[] = "abcdef";
  char arr2[] = "bcd";
  const char* ret = strstr(arr1, arr2);
  if (ret != NULL)
  {
    printf("%s\n", ret);
  }
  else
  {
    printf("找不到\n");
  }
  return 0;
}

#include<stdio.h>
#include<string.h>
int main()
{
  char arr1[] = "abcdef";
  char arr2[] = "bcdf";
  const char* ret = strstr(arr1, arr2);
  if (ret != NULL)
  {
    printf("%s\n", ret);
  }
  else
  {
    printf("找不到\n");
  }
  return 0;
}

(3)strstr的模拟实现

我们在这里采用的是暴力循环遍历的方法。当然也可以使用KMP算法,在此不做介绍了

#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
  assert(str1 && str2);
  if (*str2 == '\0')
  {
    return (char*)str1;
  }
  const char* s1 = NULL;
  const char* s2 = NULL;
  const char* cp = str1;
  while (*cp)
  {
    s1 = cp;
    s2 = str2;
    while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
    {
      s1++;
      s2++;
    }
    if (*s2 == '\0')
    {
      return cp;
    }
    cp++;
  }
  return NULL;
}
int main()
{
  char arr1[] = "abcdef";
  char arr2[] = "bcdef";
  char* ret = my_strstr(arr1, arr2);
  if (ret != NULL)
  {
    printf("%s\n", ret);
  }
  else
  {
    printf("找不到\n");
  }
  return 0;
}

9.strtok

(1)strtok的库函数文档

这个函数有两个参数,str是目标字符串。它是需要被修改的

delimiters是一个字符串,定义了用作分隔符的集合

函数的功能是,在str字符串中找到,delimiter这个集合中的任意一个字符,然后将最先出现的这个字符修改为\0,并且返回分割好的这个字符串的地址,并且内部有一个静态变量记录之前切割的位置

这个str可以是一个null,如果传的是空指针的话,那么就在后面的字符串中找到集合中的某个元素,并且修改为\0,然后返回这个字符串。

(2)strtok的使用以及注意事项

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

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

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

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

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

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

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[] = "192.168.120.86#56789";
  char sep[] = ".#";
  char buf[30] = { 0 };
  strcpy(buf, arr);
  char* ret = NULL;
  for (ret = strtok(buf, sep); ret != NULL; ret = strtok(NULL, sep))
  {
    printf("%s\n",ret);
  }
  return 0;
}

10.strerror

(1)strerror的库函数文档

这个函数它会接受一个整型的数字,这个数字是一个错误码,然后返回一个字符串的地址,我们可以打印出这个字符串的地址,显示我们的错误信息

C语言在运行时,如果发生错误,就会将错误码存放到errno

这个变量中,而这个函数可以将错误码翻译成字符串

相关文章
|
10天前
|
C语言
C语言:内存函数(memcpy memmove memset memcmp使用)
C语言:内存函数(memcpy memmove memset memcmp使用)
|
13天前
|
编译器 C语言
字符串与内存函数
字符串与内存函数
24 0
|
4天前
|
存储 C语言 开发者
【C言专栏】C 语言实现动态内存分配
【4月更文挑战第30天】C语言中的动态内存分配允许程序运行时按需分配内存,提供处理未知数据量的灵活性。这涉及`malloc()`, `calloc()`, `realloc()`, 和 `free()`四个标准库函数。`malloc()`分配指定大小的内存,`calloc()`同时初始化为零,`realloc()`调整内存大小,而`free()`释放内存。开发者需谨慎处理内存泄漏和指针使用,确保程序的稳定性和性能。动态内存分配是C语言中的重要技能,但也需要良好的内存管理实践。
|
5天前
|
存储 程序员 C语言
C语言进阶第九课 --------动态内存管理-2
C语言进阶第九课 --------动态内存管理
|
5天前
|
编译器 C语言
C语言进阶第九课 --------动态内存管理-1
C语言进阶第九课 --------动态内存管理
|
10天前
|
C语言 C++
C语言利用ASCII码表统计字符串每个字符出现的次数
C语言利用ASCII码表统计字符串每个字符出现的次数
12 0
|
10天前
|
程序员 编译器 C语言
C语言知识:动态内存管理(malloc free calloc realloc)
C语言知识:动态内存管理(malloc free calloc realloc)
|
10天前
|
存储 编译器 C语言
C语言基础知识:数据在内存中的存储解析(整数,浮点数)
C语言基础知识:数据在内存中的存储解析(整数,浮点数)
|
11天前
|
存储 C语言
C语言中字符串的引用与数组元素操作
C语言中字符串的引用与数组元素操作
15 0
|
12天前
|
存储 安全 程序员
C语言内存四区详解
C语言内存四区详解
19 0