C语言——常见的字符串函数+内存操作函数的介绍及实现


前言

最近在刷题的时候,经常遇到需要用到字符串函数的问题,因此发现对这方面函数使用的一些不足,遂写一篇博客(笔记),巩固自身也便复习。


一、字符串函数

1.求字符串长度 strlen

函数定义:

size_t strlen ( const char * str );

注意点:

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

2.长度不受限制的字符串函数strcpy、strcat、strcmp

字符串拷贝 strcpy

函数定义:

char* strcpy(char * destination, const char * source );

注意点:

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。

Strcpy的作用是将一个数组的字符串以覆盖的方式复制到另一个数组,由于‘\0’也被复制,所以相当于完全拷贝。strcpy会返回一个char型指针,该指针指向被覆盖的目标字符串的第一个字符的地址。

例如:

#include<stdio.h>
#include<string.h>
//strcpy的作用以及用法
int main(){
	char a[32]="America";
	char b[32]="China";
	strcpy(a,b);            // 将b的内容覆盖复制到a
	printf("%s\n%s",a,b);
	return 0;
}

以上代码的结果为:

China
China

字符串追加拷贝 strcat

函数定义:

char * strcat ( char * destination, const char * source );

注意点:

  • 源字符串必须以 ‘\0’ 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。

Strcat的用法与strcpy相似,作用是以拼接的方式,将源字符串的内容追加拷贝到目标字符串后面。

例如:

#include<stdio.h>
#include<string.h>
int main(viod){
	char c[32]="America";
	char d[32]="China";
	strcat(c,d);
	printf("%s\n",c);
	return 0;
}

以上代码的结果为:

AmericaChina

字符串比较 strcmp

函数定义:

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

注意点:

  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字

strcmp函数按照ASCII码来比较两字符串每一位字符的的大小,直到出现不同的字符or遇到‘\0’为止。当某一个字符串提前结束(遇到‘\0’),那么就算做另一个字符串比较‘大’。

3.长度受限制的字符串函数strncpy、strncat、strncmp

strncpy、strncat、strncmp三个函数的作用与strcpy、strcat、strcmp几乎完全一样,唯一不同的是他们多了一个参数,所以这里只给出其函数定义及注意点:

字符串拷贝 strncpy

函数定义

char * strncpy ( char * destination, const char * source, size_t num );

注意点:

  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个

字符串追加拷贝 strncat

函数定义

char * strncat ( char * destination, const char * source, size_t num );

注意点:

  • 同strncpy

字符串比较 strncmp

函数定义

int strncmp ( const char * str1, const char * str2, size_t num);

注意点:

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

4.判断字符串匹配问题 strstr

函数定义

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

strstr(str1,str2)函数用于判断字符串str2是否是str1的子串。如果是、则返回str1字符串从str2第一次出现的位置到str1结尾的字符串,否则返回NULL。可以用来1.分割字符串;2.通过查找子串进行删除,修改等一系列操作。

5.字符操作

字符分类函数

函数如果他的参数符合下列条件就返回真
iscntrl任何控制字符
isprint任何可打印字符,包括图形字符和空白字符
isspace空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isgraph任何图形字符
isdigit十进制数字 0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母a~f,大写字母
islower小写字母a~z
isupper大写字母A~Z
isalpha字母az或AZ
isalnum字母或者数字,az,AZ,0~9
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)

字符转换函数

int tolower ( int c );//转换成小写 
int toupper ( int c );//转换成大写

二、内存操作函数

1.memcpy

函数定义

void * memcpy ( void * destination, const void * source, size_t num );

注意点:

  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到 ‘\0’ 的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的(存在内存重叠)。

memcpy与strcpy的区别

  1. 复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
  2. 用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。
  3. 复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。

2.memmove

函数定义

void * memmove ( void * destination, const void * source, size_t num );

注意点:

  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

三、库函数模拟实现

1.strlen

int my_strlen(char *s) 
{ 
 char *p = s; 
 while(*p != ‘\0) 
 p++; 
 return p-s; 
}

2.strcpy

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

3.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; 
}

4.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 ); 
}

5.memcpy

void * memcpy ( void * dst, const void * src, size_t count) 
{ 
 void * ret = dst; 
 assert(dst); 
 assert(src); 
//从低地址向高地址拷贝
 while (count--) { 
 *(char *)dst = *(char *)src; 
 dst = (char *)dst + 1; 
 src = (char *)src + 1; 
 } 
 return(ret); 
}

6.memmove

void * memmove ( void * dst, const void * src, size_t count) 
{ 
 void * ret = dst; 
 //如果条件成立,表明向前拷贝不会出现内存重叠现象,采用memcpy相同方法拷贝,反之采用高地址向低地址拷贝
 if (dst <= src || (char *)dst >= ((char *)src + count)) { 
 while (count--) { 
 *(char *)dst = *(char *)src; 
 dst = (char *)dst + 1; 
 src = (char *)src + 1; 
 } 
 } 
 else { 
 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); 
}
<think>好的,我现在需要帮助用户解决关于Dify循环实现的问题。首先,我需要明确用户的具体需求。他们提到“dify 循环实现”或“dify 如何处理循环”,但Dify本身可能没有直接称为“循环”的功能,所以需要结合现有文档中的信息来推断可能的解决方案。 根据用户提供的引用内容,Dify工作流中有迭代节点[^1]。这可能类似于编程中的循环结构,用于重复执行某个任务。例如,在处理列表数据或需要多次执行同一操作时,迭代节点可以派上用场。我需要详细解释迭代节点的配置和使用步骤,确保用户能够理解如何设置循环次数或遍历数据集。 另外,用户可能对如何处理循环中的错误或性能问题感兴趣。引用[2]提到在Dify中处理PEM文件的问题,这可能涉及在循环中正确处理数据格式,避免错误积累。需要提醒用户在循环中注意错误处理和资源管理,确保每次迭代的稳定性。 引用[3]中的例子展示了如何结合FastAPI和Selenium进行实时监控并生成GIF,这可能涉及循环截取浏览器内容。虽然Dify本身可能不直接控制这类循环,但可以通过外部脚本或定时任务触发工作流,模拟循环执行。这部分需要说明如何将外部循环机制与Dify结合使用。 接下来,我需要组织回答结构。首先介绍迭代节点的基本概念和配置步骤,然后讨论循环中的数据处理和错误处理,最后补充外部触发循环的方法。同时,生成相关问题以帮助用户进一步探索,比如优化循环性能或处理复杂数据结构。 需要确保回答符合格式要求,使用正确的中文表达,行内公式用$...$,独立公式用$$...$$,但当前问题不涉及数学公式,所以可能不需要使用。同时,引用标识要自然地添加到相关段落末尾,如、[^2]、[^3]。 最后,检查是否有遗漏点,比如Dify的其他循环相关功能或用户可能遇到的常见问题,确保回答全面且易于理解。</think>在Dify中处理循环逻辑主要通过**迭代节点**实现,以下是具体实现方式和应用场景的解析: ### 一、Dify循环实现机制 Dify通过**工作流设计器**中的迭代节点处理循环需求,其核心原理类似编程中的`for循环`。迭代节点可遍历以下数据类型: - 数组列表:`["A","B","C"]` - 字典集合:`{"key1":"value1", "key2":"value2"}` - 数值范围:通过`range()`函数生成序列 配置示例: ```python # 模拟迭代节点的数据输入 input_data = { "dataset": [1,2,3,4,5], "process_logic": "item * 2" # 对每个元素执行乘以2的操作 } ``` ### 二、迭代节点的关键配置步骤 1. **数据源绑定**:将数组/字典类型变量连接到迭代节点的输入端口 2. **循环变量命名**:设定当前元素的变量名(默认为`item`) 3. **子流程设计**:在迭代节点内部构建需要重复执行的逻辑模块 4. **结果聚合**:通过`outputs`收集所有迭代结果,支持数组或对象格式 $$ \text{总耗时} = \sum_{i=1}^{n}(单次迭代时间_i) + 系统开销 $$ ### 三、循环中的特殊处理 1. **错误中断控制**: - 启用`continueOnError`参数可跳过失败迭代 - 通过`try-catch`模块包裹敏感操作 2. **并行优化**: ```python # 伪代码示例 Parallel.forEach(dataset, lambda item: process(item)) ``` 3. **结果过滤**: ```python filtered = filter(lambda x: x%2==0, processed_results) ``` ### 四、应用场景案例 1. **批量文件处理**:遍历存储桶中的文件列表进行格式转换 2. **数据清洗**:对数据库查询结果集进行逐条校验 3. **API轮询**:定时循环调用第三方接口直到满足特定条件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值