【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

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

相关文章
|
2月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
36 3
|
2天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
23 6
|
21天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
40 6
|
2月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
2月前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
27 0
|
2月前
|
C语言 C++
c语言回顾-内存操作函数
c语言回顾-内存操作函数
41 0
|
4月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
394 0
|
2月前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
64 1
|
2月前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。