当前位置: 首页 > news >正文

C语言进阶之字符函数和字符串函数

重点介绍处理字符和字符串的库函数的使用和注意事项

求字符串长度

strlen

size_t strlen ( const char * str );
  • 字符串已经’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包 含’\0’)。
  • 参数指向的字符串必须要以’\0’结束。
  • 注意函数的返回值为size_t,是无符号的(易错)
  • 学会strlen函数的模拟实现

案例:

 #include <stdio.h>
 int main()
 {
	 const char*str1 = "abcdef";
	 const char*str2 = "bbb";
	 if(strlen(str2)-strlen(str1)>0)
	 {
		 printf("str2>str1\n");
	 } 
	 else
	 {
	 	printf("srt1>str2\n");
	 }
	 return 0;
 }

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

strcpy

char* strcpy(char * destination, const char * source );
  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。
  • 学会模拟实现。

strcat

char * strcat ( char * destination, const char * source );
  • 源字符串必须以 ‘\0’ 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • 字符串自己给自己追加,如何?

strcmp

int strcmp ( const char * str1, const char * str2 );

标准规定:

  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字
  • 那么如何判断两个字符串?

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

strncpy

char * strncpy ( char * destination, const char * source, size_t num );
  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

strncat

案例:

 /* strncat example */
 #include <stdio.h>
 #include <string.h>
 int main ()
 {
	 char str1[20];
	 char str2[20];
	 strcpy (str1,"To be ");
	 strcpy (str2,"or not to be");
	 strncat (str1, str2, 6);
	 puts (str1);
	 return 0;
 }

strncmp
案例:

/* strncmp example */
 #include <stdio.h>
 #include <string.h>
 int main ()
 {
	 char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
	 int n;
	 puts ("Looking for R2 astromech droids...");
	 for (n=0 ; n<3 ; n++)
	 if (strncmp (str[n],"R2xx",2) == 0)
	 {
	 printf ("found %s\n",str[n]);
	 }
	 return 0;
 }

字符串查找

strstr

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

案例:

#include <stdio.h>
#include <string.h>

int main ()
{
    char str[] = "This is a simple string";
    char * pch;

    pch = strstr(str, "simple");  // 查找子串 "simple"
    strncpy(pch, "sample", 6);     // 用 "sample" 替换 "simple"
    
    puts(str);                     // 输出修改后的字符串
    return 0;
}

strtok

char * strtok ( char * str, const char * sep );
  • sep参数是个字符串,定义了用作分隔符的字符集合
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
  • strtok函数找到str中的下一个标记,并将其用\0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记
  • 如果字符串中不存在更多的标记,则返回NULL 指针。

案例:

 /* strtok example */
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "- This, a sample string."; // 定义一个输入字符串
    char *pch; // 指针,用于保存分割后每个词的地址

    // 打印原始字符串
    printf("Splitting string \"%s\" into tokens:\n", str);
    
    // 使用 strtok 函数,第一参数为待分割字符串,第二参数为分隔符
    pch = strtok(str, " ,.-");

    // 循环,直到 pch 为空
    while (pch != NULL) {
        printf("%s\n", pch); // 打印当前的词
        pch = strtok(NULL, " ,.-"); // 获取下一个词
    }

    return 0; // 返回 0,表示程序正常结束
}

错误信息报告

strerror

char * strerror ( int errnum );

返回错误码,所对应的错误信息。

/* strerror example : error list */
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>//必须包含的头文件
int main ()
 {
	 FILE * pFile;
	 pFile = fopen ("unexist.ent","r");
	 if (pFile == NULL)
	 	printf ("Error opening file unexist.ent: %s\n",strerror(errno));
	 //errno: Last error number
	 return 0;
 }

字符操作

在这里插入图片描述
案例:
/* isupper example */
#include <stdio.h>

#include <ctype.h> // 引入ctype.h库以使用字符处理函数
#include <stdio.h> // 引入stdio.h库以使用输入输出功能

int main ()
{
    int i = 0; // 初始化索引变量
    char str[] = "Test String.\n"; // 定义一个字符串
    char c; // 声明字符变量

    // 循环遍历字符串,直到遇到字符串结束符'\0'
    while (str[i]) 
    {
        c = str[i]; // 获取当前字符
        if (isupper(c)) // 检查当前字符是否为大写字母
            c = tolower(c); // 如果是,则转换为小写字母

        putchar(c); // 输出当前字符
        i++; // 移动到下一个字符
    }
    return 0; // 返回0表示程序正常结束
}

内存操作函数

memcpy

void * memcpy ( void * destination, const void * source, size_t num );
  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到 '\0’的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果是未定义。
    案例:
/* memcpy example */
 #include <stdio.h>
 #include <string.h>
 struct {
	 char name[40];
	 int age;
 } person, person_copy;
 int main ()
 {
	 char myname[] = "Pierre de Fermat";
	 /* using memcpy to copy string: */
	 memcpy ( person.name, myname, strlen(myname)+1 );//myname 的内容复制到 person.name 中。strlen(myname) + 1 计算出字符串的长度并加上1,用于包括字符串结束符 \0。
	 person.age = 46;
	  /* using memcpy to copy structure: */
	 memcpy ( &person_copy, &person, sizeof(person) );//person 的内容复制到 person_copy 中。sizeof(person) 返回结构体的大小,
	 printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
	 return 0;
 }

memmove

 void * memmove ( void * destination, const void * source, size_t num );
  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

案例:

/* memmove example */
 #include <stdio.h>
 #include <string.h>
 int main ()
 {
	 char str[] = "memmove can be very useful......";
	 memmove (str+20,str+15,11);
	 puts (str);
	 return 0;
 }

memset

 int memcmp ( const void * ptr1, const void * ptr2, size_t num );
  • 比较从ptr1和ptr2指针开始的num个字节

案例:

/* memcmp example */
 #include <stdio.h>
 #include <string.h>
 int main ()
 {
	 char buffer1[] = "DWgaOtP12df0";
	 char buffer2[] = "DWGAOTP12DF0";
	 int n;
	 n=memcmp ( buffer1, buffer2, sizeof(buffer1) );
	  if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
	 else if (n<0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2);
	 else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
	 return 0;
 }

memcmp

库函数的模拟实现

模拟实现strlen

三种方式: 方式1:

//计数器方式
int my_strlen(const char * str)
 {
	 int count = 0;
	 while(*str)
	 {
		 count++;
		 str++;
	 }
	 return count;
 }

方式2:

//不能创建临时变量计数器
int my_strlen(const char * str)
 {
	 if(*str == '\0')
	   return 0;
	 else
	   return 1+my_strlen(str+1);
 }

方式3:

//指针-指针的方式
int my_strlen(char *s)
 {
	 char *p = s;
	 while(*p != ‘\0)
	 p++;
	 return p-s;
 }

模拟实现strcpy

参考代码:
//1.参数顺序
//2.函数的功能,停止条件
//3.assert
//4.const修饰指针
//5.函数返回值
//6.题目出自《高质量C/C++编程》书籍最后的试题部分

char *my_strcpy(char *dest, const char*src)
 {   
		char *ret = dest;
	    assert(dest != NULL);
	    assert(src != NULL);
	
	    
	    while((*dest++ = *src++))
	    {
	        ;
	    }
	    return ret;
 }

模拟实现strcat

参考代码:

 char *my_strcat(char *dest, const char*src)
 {
    char *ret = dest;
    assert(dest != NULL);
    assert(src != NULL);
    while(*dest)
    {
        dest++;
    }
    while((*dest++ = *src++))
    {
        ;
    }
    return ret;
 }

模拟实现strstr

#include <assert.h>

char *my_strstr(const char* str1, const char* str2) {
    assert(str1);
    assert(str2);
    
    // 如果子字符串为空,返回原字符串的起始地址
    if (*str2 == '\0') {
        return (char*)str1;  // 返回 str1 的起始地址
    }
    
    const char *cp = str1;  // 主字符串指针
    const char *substr;     // 子字符串指针
    const char *s1;         // 用于比较的指针
    
    while (*cp) {
        s1 = cp;            // s1 指向主字符串的当前字符
        substr = str2;     // substr 指向子字符串的起始字符
        
        // 比较 s1 和 substr 的字符
        while (*s1 && *substr && (*s1 == *substr)) {
            s1++;
            substr++;
        }
        
        // 如果子字符串的所有字符都匹配
        if (*substr == '\0') {
            return (char*)cp; // 返回子字符串在主字符串中的起始地址
        }
        
        cp++; // 主字符串指针向前移动一位
    }
    
    return NULL; // 如果未找到子字符串,返回 NULL
}

模拟实现strcmp

参考代码:

 int my_strcmp (const char * src, const char * dst)
 {
        int ret = 0 ;
        assert(src != NULL);
        assert(dest != NULL);
        while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
                ++src, ++dst;
 
        if ( ret < 0 )
                ret = -1 ;
        else if ( ret > 0 )
                ret = 1 ;
 
        return( ret );
 }

模拟实现memcpy

参考代码:

void * memcpy ( void * dst, const void * src, size_t count)
 {
        void * ret = dst;
        assert(dst);
        assert(src);
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }
 
        return(ret);
 }

模拟实现memmove

参考代码:

 void * memmove ( void * dst, const void * src, size_t count)
{
        void * ret = dst;
 
        if (dst <= src || (char *)dst >= ((char *)src + count)) {
                /*
                 * Non-Overlapping Buffers
                 * copy from lower addresses to higher addresses
                 */
                while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst + 1;
                        src = (char *)src + 1;
                }
        }
        else {
                /*
                 * Overlapping Buffers
                 * copy from higher addresses to lower addresses
                 */
                dst = (char *)dst + count - 1;
                src = (char *)src + count - 1;
 
                while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst - 1;
                        src = (char *)src - 1;
                }
        }
 
        return(ret);
 }

相关文章:

  • AcWing 5972. 科学记数法
  • 【游戏安全】强制交互类风险
  • Magnet 库的技术架构与核心机制解析
  • Docker部署SpringBoot项目(完整版)
  • 重载“<<”操作符
  • 基于多通道降压稳压器的机器人关节供电系统设计
  • 人工智能day03
  • 设计模式总章
  • UE5 添加随机弹道
  • 【linux知识】web服务环境搭建(一):用户以及开发环境初始化
  • 有一个服务器能做什么?
  • 程序化广告行业(82/89):解锁行业术语,开启专业交流之门
  • 格瑞普Tattu正式成为2025年中国无人机竞速联赛官方赞助商!
  • 【家政平台开发(42)】筑牢家政平台安全防线:安全测试与漏洞修复指南
  • 【ROS】分布式通信架构
  • 文件包含(CTFshow 刷题记录)持续更新
  • 【漏洞复现】Vite 任意文件读取漏洞 CVE-2025-30208/CVE-2025-31125/CVE-2025-31486/CVE-2025-32395
  • scikit-learn 开源框架在机器学习中的应用
  • vue入门:计算属性computer监听器watch
  • 智慧农业整体解决方案
  • 上海网站建设 知名做/足球世界排名
  • 手机网站制作套餐/建个网站需要多少钱
  • 网站建设 广州/宁波seo费用
  • 重庆移动网站建设/seo文章是什么
  • 免费行情软件网站下载大全安全吗/百度地图导航手机版免费下载
  • wordpress建站访问不了/百度秒收录蜘蛛池