C语言进阶学习日志:字符串和内存函数(一)(下)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: C语言进阶学习日志:字符串和内存函数(一)(下)

长度受限制的字符串函数


strncpy函数:

bb0e7c62fa3641c497c6415c99509fcd.png

第三个参数 size_t count 是要拷贝的元素个数

要注意的是当我们拷贝的元素个数大于我们被拷贝的字符串的长度时他会自动往不够的那片空间添加'\0'

#include <stdio.h>
int main()
{
  char string1[]="xxxxxxxxxxx";
  char string2[]="123";
  strncpy(string1,string2,5);
  这时string1就会变成123'\0'\0'xxxxxxxxx;
}

同时strncpy函数也更加安全一些 因为这样可以避免你拷进去的字符串过长 以至于目标的字符串不足以存储拷贝进来的字符串

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
char* my_strncpy(char* rest, const char* tmp, unsigned int num)
{
  assert(rest && tmp);
  char* ret = rest;
  while (num)
  {
    if (*tmp == '\0')
    {
      *rest++ = *tmp;
      num--;
    }
    while (*tmp)
    {
      *rest++ = *tmp++;
      num--;
      if (!num) return ret;
    }
  }
  return ret;
}
int main()
{
  char rest[] = "xxxxxxxxxx";
  char tmp[] = "123";
  printf("%s",my_strncpy(rest, tmp, 5));//这里打印出来也就是123 前面已经给大家说过了
}

这个是库函数里的写法

char * __cdecl strncpy (
        char * dest,
        const char * source,
        size_t count
        )
{
        char *start = dest;
        while (count && (*dest++ = *source++) != '\0')    /* copy string */
                count--;
        if (count)                              /* pad out with zeroes */
                while (--count)
                        *dest++ = '\0';
        return(start);
}

strncat函数:

这个是往目标字符串追加 size_t num 的字符个数的字符串

212a888cddc24f97996e993c68f53d77.png

要注意的点除了前面说的 追加字符串要足够长 可变以外

这个函数还有一个要注意的点 在指定链接的字符个数后 如果我们原函数的长度大于字符串的长度 就好像这样 "hello" "world"这时如果链接的字符个数 num为3 那我们链接wor后

后面应该是什么样呢

#include <stdio.h>
int main()
{
  char string1[]="hello";
  char string2[]="world";
  strncpy(string1,string2,3);
  这样操作后string1的结果是什么内 留给大家思考一下
}

 提示 我们既然时链接两个字符串 那我们链接后肯定也是一个字符串 即使链接的元素个数中没有'\0' 大家想想字符串不可少的是什么 就知道答案了

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
char* my_strncat(char* rest,const char* tmp,unsigned int num)
{
  assert(rest && tmp);
  char* ret = rest;
  while (*rest)
  {
    rest++;
  }
  while (*tmp)
  {
    *rest++ = *tmp++;
    num--;
    if (!num)break;
  }
  *rest = '\0';
  return ret;
}
int main()
{
  char string1[20] = "hello";
  char string2[] = "world";
  printf("%s",my_strncat(string1, string2, 4));
}

这个是库函数里的写法

char * __cdecl strncat (
        char * front,
        const char * back,
        size_t count
        )
{
        char *start = front;
        while (*front++)
                ;
        front--;
        while (count--)
                if ((*front++ = *back++) == 0)
                        return(start);
        *front = '\0';
        return(start);
}

strncmp函数:

还是一样的道理 这个也是指定了比较的元素的个数

0d669af8f81448889974108d4c1605ab.png

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
int my_strncmp(const char* rest, const char* tmp, unsigned int num)
{
  assert(rest && tmp);
  while (*rest == *tmp)
  {
    num--;
    if (!num ||(* rest == '\0'))break;
    rest++;
    tmp++;
  }
  return *rest - *tmp;
}
int main()
{
  char string1[] = "abczefg";
  char string2[] = "abcqqq";
  printf("%d",my_strncmp(string1, string2, 4));
}

这个是库函数的里的写法

int __cdecl strncmp
(
    const char *first,
    const char *last,
    size_t      count
)
{
    size_t x = 0;
    if (!count)
    {
        return 0;
    }
    /*
     * This explicit guard needed to deal correctly with boundary
     * cases: strings shorter than 4 bytes and strings longer than
     * UINT_MAX-4 bytes .
     */
    if( count >= 4 )
    {
        /* unroll by four */
        for (; x < count-4; x+=4)
        {
            first+=4;
            last +=4;
            if (*(first-4) == 0 || *(first-4) != *(last-4))
            {
                return(*(unsigned char *)(first-4) - *(unsigned char *)(last-4));
            }
            if (*(first-3) == 0 || *(first-3) != *(last-3))
            {
                return(*(unsigned char *)(first-3) - *(unsigned char *)(last-3));
            }
            if (*(first-2) == 0 || *(first-2) != *(last-2))
            {
                return(*(unsigned char *)(first-2) - *(unsigned char *)(last-2));
            }
            if (*(first-1) == 0 || *(first-1) != *(last-1))
            {
                return(*(unsigned char *)(first-1) - *(unsigned char *)(last-1));
            }
        }
    }
    /* residual loop */
    for (; x < count; x++)
    {
        if (*first == 0 || *first != *last)
        {
            return(*(unsigned char *)first - *(unsigned char *)last);
        }
        first+=1;
        last+=1;
    }
    return 0;
}

strstr函数:

这是一个在字符串中寻找目标字符串的函数 如果找到则返回被寻找字符串首元素在目标字符串的地址

52687bca27f24bb49d11090bbf459d0e.png

#include <stdio.h>
int main()
{
  char string1[]="abbcqwer";
  char string2[]="bbc"
  printf("%s",strstr(string1,string2));
  打印出来的就是 bbcqwer
}

 我们来理一下模拟这个函数的思路  首先 我们是要在目标字符串寻找 肯定需要几个指针来帮我们判断是不是我们要寻找的字符串

bfcde9ac55b5442ea7f814c1432cfe3d.png

#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* tmp, const char* ret)
{
  assert(tmp && ret);
  const char* suter = tmp;//被寻找字符串的枚举地址
  const char* cstr = tmp;//被寻找字符串的起始地址
  const char* sup = ret;
  if (*ret == '\0')
  {
    return tmp;
  }
  while (*cstr)
  {
    suter = cstr;
    sup = ret;
    while (*suter&&*suter == *sup)//当是这种"afbbc" "bbc" 最后'\0'和'\0'相同会一直循环随 
                                         会跳出但结果就会出问题
    {                              //所以suter和sup指向不能为'\0'
      suter++;
      sup++;
    }                       //上面那种循环我的if语句sup要放前面 我是找到了的而且两个都 
                                 是'\0'要把bbc打印出来才行
    if (*sup == '\0')      //像是这种"afbbcfgh" "bbc" 这时发现不相等我的sup会指向'\0'就 
                                  可以结束了
    {
      return (char*)cstr;
    }
    if (*suter == '\0')//"afbbbc" "bbcd"这种就是我往后寻找suter已经到'\0'了就可以结束了
    {                   //虽然没有也行 但是就要等到cstr到'\0'才停止 这样就可以早点结束
      return NULL;
    }
    cstr++;
  }
  return NULL;
}
int main()
{
  char arr1[] = "afbbbcdfgh";
  char arr2[] = "bbc";
  printf("%s",my_strstr(arr1, arr2));
}

我们把那个我所说的s1s2的赋值放在循环的前面 只要不相等我们跳出循环就会来到开始的位置 s1s2自然就恢复开始的位置了


strtok函数:

725df4d71e9443c5bf9982b022b95d70.png

这个函数的第二个参数我们这里简称 s2 是一个字符串 里面存储的是多个分隔符的集合

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

strtok函数找到s1中的下一个标记 并将其'\0'结尾  返回一个指向该标记的指针

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

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

不存在更多标记则返回NULL

#include <stdio.h>
int main()
{
   const char* p="@.";
   char arr[] = "luck++@8023.sg";
   char buf[] = { 0 };
   strcpy(arr,buf);  //因为我们的这个函数会改变原本字符串的内容
                       所以要先拷贝一份
   char* str=strtok(arr,p);//luck++
   printf("%s",str);
   str=strtok(arr,p);//8023
   printf("%s",str);
   str=strtok(arr,p);//sg
   printf("%s",str);
   //strtok 这里返回NULL
}

但是这种写法是不可取的 这样才是正确的用法

const char* p="@.";
char *arr="luck++@8023.sg";
for(char* str=strtok(arr,p);str!=NULL;str=strtok(NULL,p))
{
   printf("%s\n",str);
}

strerror函数:

这是一个错误信息的解释 报告函数 返回错误信息字符串的首地址

c语言中:

错误码-错误信息

   0     -“No error”

2c71dd48c0f94e07a24d6182ccee2550.png

其中errno一般与strerror配合着使用

当库函数使用的时候,发生错误会把errno这个全局的错误变量设置为本次执行库函数产生的错误码

errno是c语言提供的一个全局变量,可以直接使用,放在errno.h文件中


字符分类函数:

3b9ea676fa7a45afb03409647300f839.png


字符转换函数:

int tolower(int c);将字符转换成小写

int toupper(int c); 将字符转换成大写

到这里字符相关的函数就 弄完了 祝大家都能收到自己心仪的大厂的offer!!!!

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
2月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
92 10
|
3月前
|
存储 算法 C语言
C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项
本文深入探讨了C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项,并通过案例分析展示了实际应用,旨在帮助读者提高编程效率和代码质量。
181 4
|
4月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
175 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
4月前
|
PyTorch 算法框架/工具
Pytorch学习笔记(七):F.softmax()和F.log_softmax函数详解
本文介绍了PyTorch中的F.softmax()和F.log_softmax()函数的语法、参数和使用示例,解释了它们在进行归一化处理时的作用和区别。
622 1
Pytorch学习笔记(七):F.softmax()和F.log_softmax函数详解
|
4月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
84 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
4月前
|
C语言 C++
【C语言】解决不同场景字符串问题:巧妙运用字符串函数
【C语言】解决不同场景字符串问题:巧妙运用字符串函数
|
5月前
|
存储 C语言
【C语言基础考研向】10 字符数组初始化及传递和scanf 读取字符串
本文介绍了C语言中字符数组的初始化方法及其在函数间传递的注意事项。字符数组初始化有两种方式:逐个字符赋值或整体初始化字符串。实际工作中常用后者,如`char c[10]=&quot;hello&quot;`。示例代码展示了如何初始化及传递字符数组,并解释了为何未正确添加结束符`\0`会导致乱码。此外,还讨论了`scanf`函数读取字符串时忽略空格和回车的特点。
147 8
|
5月前
|
存储 Serverless C语言
【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数
本文介绍了C语言中的`gets`和`puts`函数,`gets`用于从标准输入读取字符串直至换行符,并自动添加字符串结束标志`\0`。`puts`则用于向标准输出打印字符串并自动换行。此外,文章还详细讲解了`str`系列字符串操作函数,包括统计字符串长度的`strlen`、复制字符串的`strcpy`、比较字符串的`strcmp`以及拼接字符串的`strcat`。通过示例代码展示了这些函数的具体应用及注意事项。
310 7
|
5月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
201 4
|
3月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
927 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板

热门文章

最新文章