C语言字符串处理相关函数详解
C语言字符串处理相关函数详解
- 相关函数详解
- 1. **字符串拷贝**:
- `strcpy` 和 `strncpy`
- 2. **字符串连接**:
- `strcat` 和 `strncat`
- 3. **字符串比较**:
- `strcmp` 和 `strncmp`
- 4. **字符串长度**:
- `strlen`
- 5. **字符串查找**:
- `strchr` 和 `strrchr`
- `strstr`
- 6. **字符串切分**:
- `strtok`
- 7. **内存操作**(与字符串相关):
- `memset`, `memcpy`, `memmove`
- 8. **其他函数**:
- `strdup`(非标准函数)
- `strcasecmp` 和 `strncasecmp`(扩展函数)
- 在C语言中,如何安全地使用字符串处理函数来避免缓冲区溢出等常见安全问题?
- **1. 确保目标缓冲区大小足够**
- **解决方案:使用长度限制的函数**
- 示例:
- **2. 正确终止字符串**
- **解决方案:手动添加终止符**
- 示例:
- **3. 避免目标缓冲区内存不足**
- **解决方案:始终检查缓冲区大小**
- 示例:
- **4. 使用更安全的函数**
- **5. 使用动态分配内存**
- 示例:
- **6. 避免使用不安全的函数**
- 示例:
- **7. 小心使用 `strtok` (非线程安全)**
- 示例:
- **8. 输入验证和边界检查**
- 示例:
- **9. 使用静态分析工具**
- 管理缓冲区溢出的步骤总结:
相关函数详解
在 C 语言中,字符串其实是以 \0(空字符)结尾的字符数组。C 标准库提供了许多内置函数来处理字符串,下面是常用的字符串处理相关函数的详细说明。这些函数都定义在 <string.h> 头文件中。
1. 字符串拷贝:
strcpy 和 strncpy
-
char *strcpy(char *destination, const char *source);- 功能:将源字符串
source拷贝到目标字符串destination。 - 使用注意:
destination必须有足够的空间容纳source字符串及其终止空字符(\0)。 - 示例:
char src[] = "Hello"; char dest[10]; strcpy(dest, src); // dest now contains "Hello"
- 功能:将源字符串
-
char *strncpy(char *destination, const char *source, size_t n);- 功能:最多拷贝
n个字符到destination。 - 特点:如果
source长度小于n,会填充剩余部分为\0;如果source长度大于n,不会添加空字符,destination可能不以\0结尾。 - 示例:
char src[] = "Hello"; char dest[10]; strncpy(dest, src, 3); // dest contains "Hel"
- 功能:最多拷贝
2. 字符串连接:
strcat 和 strncat
-
char *strcat(char *destination, const char *source);- 功能:将
source连接到destination的末尾,并自动在末尾加上\0。 - 使用注意:
destination必须有足够的空间容纳结果字符串。 - 示例:
char str1[20] = "Hello "; char str2[] = "World!"; strcat(str1, str2); // str1 now contains "Hello World!"
- 功能:将
-
char *strncat(char *destination, const char *source, size_t n);- 功能:从
source连接最多n个字符到destination,并自动在末尾添加\0。 - 示例:
char str1[20] = "Hello "; char str2[] = "World!"; strncat(str1, str2, 3); // str1 now contains "Hello Wor"
- 功能:从
3. 字符串比较:
strcmp 和 strncmp
-
int strcmp(const char *str1, const char *str2);- 功能:比较两个字符串
str1和str2的大小。 - 返回值:
< 0:str1 < str20:str1 == str2> 0:str1 > str2
- 示例:
strcmp("abc", "abc"); // returns 0 strcmp("abc", "abd"); // returns -1 strcmp("abd", "abc"); // returns 1
- 功能:比较两个字符串
-
int strncmp(const char *str1, const char *str2, size_t n);- 功能:比较两个字符串的前
n个字符。 - 示例:
strncmp("abcdef", "abcxyz", 3); // returns 0 strncmp("abcdef", "abcxyz", 4); // returns -1
- 功能:比较两个字符串的前
4. 字符串长度:
strlen
size_t strlen(const char *str);- 功能:返回字符串
str的长度(不包括\0)。 - 示例:
char str[] = "Hello"; size_t len = strlen(str); // len is 5
- 功能:返回字符串
5. 字符串查找:
strchr 和 strrchr
-
char *strchr(const char *str, int c);- 功能:查找字符串
str中第一次出现字符c的位置。 - 返回值:
- 如果找到,返回指向字符
c的指针。 - 如果未找到,返回
NULL。
- 如果找到,返回指向字符
- 示例:
char str[] = "Hello"; char *pos = strchr(str, 'l'); // pos points to the first 'l' in "Hello"
- 功能:查找字符串
-
char *strrchr(const char *str, int c);- 功能:查找字符串
str中最后一次出现字符c的位置。 - 示例:
char str[] = "Hello"; char *pos = strrchr(str, 'l'); // pos points to the last 'l' in "Hello"
- 功能:查找字符串
strstr
char *strstr(const char *haystack, const char *needle);- 功能:查找子字符串
needle在字符串haystack中第一次出现的位置。 - 返回值:
- 如果找到,返回指向子字符串的指针。
- 如果未找到,返回
NULL。
- 示例:
char str[] = "Hello World!"; char *pos = strstr(str, "World"); // pos points to "World!"
- 功能:查找子字符串
6. 字符串切分:
strtok
char *strtok(char *str, const char *delim);- 功能:将字符串
str根据分隔符delim切分成多个子字符串。 - 特点:此函数内部使用静态变量保存状态,所以多次调用同一个字符串时必须依赖它的状态。
- 示例:
char str[] = "Hello,World,2023"; char *token = strtok(str, ","); while (token != NULL) {printf("%s\n", token); // Output: Hello\n World\n 2023token = strtok(NULL, ","); }
- 功能:将字符串
7. 内存操作(与字符串相关):
memset, memcpy, memmove
-
void *memset(void *ptr, int value, size_t num);- 功能:将内存块
ptr开头的num个字节设置为value(以字节为单位)。 - 示例:
char str[10]; memset(str, 'A', 10); // str contains "AAAAAAAAAA"
- 功能:将内存块
-
void *memcpy(void *destination, const void *source, size_t num);- 功能:将
source开头的num个字节拷贝到destination。 - 使用注意:
source和destination不能重叠。 - 示例:
char src[] = "12345"; char dest[10]; memcpy(dest, src, 5); // dest contains "12345"
- 功能:将
-
void *memmove(void *destination, const void *source, size_t num);- 功能:同
memcpy,但支持source和destination可能重叠的情况。 - 示例:
char str[] = "12345"; memmove(str + 1, str, 4); // str contains "11234"
- 功能:同
8. 其他函数:
strdup(非标准函数)
char *strdup(const char *str);- 功能:分配内存并复制字符串
str。 - 注意:返回的指针需要用
free释放。 - 示例:
char str[] = "Hello"; char *copy = strdup(str); // copy contains "Hello" free(copy);
- 功能:分配内存并复制字符串
strcasecmp 和 strncasecmp(扩展函数)
- 类似于
strcmp和strncmp,但忽略大小写比较。
以上是 C 语言中常用的字符串处理函数,使用时需要注意内存安全,特别是函数涉及目标字符串的大小,避免缓冲区溢出。同时,记得字符串必须以 \0 结尾作为结束标志。
在C语言中,如何安全地使用字符串处理函数来避免缓冲区溢出等常见安全问题?
在 C 语言中,因为字符串实际上是以空字符 \0 结尾的字符数组,错误处理字符串的方式可能会导致缓冲区溢出(Buffer Overflow)以及未定义行为等问题,从而引发安全风险。以下是一些注意事项和安全实践,帮助您在使用字符串处理函数时避免这些常见的问题:
1. 确保目标缓冲区大小足够
缓冲区溢出常发生在目标缓冲区(destination)的大小不足以容纳输入内容时,如 strcpy 或 strcat 等函数会将整个源字符串拷贝到目标缓冲区而不进行边界检查。
解决方案:使用长度限制的函数
- 使用有长度限制的函数,例如:
strncpy替代strcpystrncat替代strcat
- 始终显式声明并检查目标缓冲区的大小,确保总长度不会超过缓冲区。
示例:
#include <string.h>
#include <stdio.h>void safe_copy() {char src[] = "Hello, World!";char dest[10]; // 缓冲区只有10个字符(不够容纳src)// 使用 strncpy 替代 strcpy,最多拷贝 9 个字符,留出一个位置给 '\0'strncpy(dest, src, sizeof(dest) - 1);dest[sizeof(dest) - 1] = '\0'; // 手动添加字符串结束符printf("Copied string: %s\n", dest); // 输出结果 "Hello, Wo"
}
2. 正确终止字符串
有些字符串函数(如 strncpy)不会自动在字符串结尾添加 NUL 字符 \0,这可能导致未终止的字符串引发未定义行为。
解决方案:手动添加终止符
确保显式添加空字符 \0,尤其是在长度限制的拷贝操作中。
示例:
char src[] = "Hello";
char dest[10];
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // 确保字符串以 '\0' 结尾
3. 避免目标缓冲区内存不足
一些函数(例如 strcat 和 strcpy)假定目标缓冲区有足够的空间。如果目标缓冲区不足以容纳拼接或拷贝的内容,会导致缓冲区溢出。
解决方案:始终检查缓冲区大小
在执行操作之前,计算源字符串与目标缓冲区的大小关系,以确保不会发生溢出。
示例:
#include <string.h>
#include <stdio.h>void safe_concat() {char src[] = "World!";char dest[20] = "Hello, ";// 检查 dest 是否足够大if (strlen(dest) + strlen(src) + 1 <= sizeof(dest)) {strcat(dest, src); // 安全拼接printf("Concatenated string: %s\n", dest);} else {printf("Buffer overflow risk avoided!\n");}
}
4. 使用更安全的函数
许多 C 标准库函数(如 strcpy, strcat)存在已知问题,现代 C 标准库或第三方库提供了更安全的替代函数,例如:
- POSIX扩展函数(如
strlcpy,strlcat):strlcpy和strlcat是更安全的拷贝和拼接函数,它们始终保证目标字符串是以\0结尾的,并不会导致缓冲区溢出。- 示例:
#include <string.h> // POSIX 标准char src[] = "Hello, World!"; char dest[10];// strlcpy: 拷贝最多 sizeof(dest) - 1 个字符,并确保以 '\0' 结尾 strlcpy(dest, src, sizeof(dest)); printf("Destination: %s\n", dest);
5. 使用动态分配内存
如果目标缓冲区的大小是未知且不可固定的,采用动态内存分配(如 malloc 和 free)可以避免缓冲区溢出的问题。
示例:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>void dynamic_allocation() {char src[] = "Hello, dynamically allocated world!";char *dest = malloc(strlen(src) + 1); // 动态分配精确大小if (dest == NULL) {fprintf(stderr, "Memory allocation failed.\n");return;}strcpy(dest, src); // 安全拷贝printf("Copied string: %s\n", dest);free(dest); // 释放内存
}
6. 避免使用不安全的函数
一些函数完全不应该使用,特别是在处理未受信任的数据时。例如:
gets(已废弃 in C11):因为它完全不限制输入的大小,极易引发缓冲区溢出。- 替代:使用
fgets。
示例:
#include <stdio.h>void read_input() {char buffer[20];// fgets 会限制输入大小,避免缓冲区溢出printf("Enter a string: ");if (fgets(buffer, sizeof(buffer), stdin) != NULL) {printf("You entered: %s\n", buffer);}
}
7. 小心使用 strtok (非线程安全)
strtok 全局维护状态,无法在多线程中安全使用。使用 strtok_r 它的线程安全版本(POSIX 提供)。
示例:
#include <stdio.h>
#include <string.h>void tokenize() {char str[] = "Hello,World,2023";char *saveptr;char *token = strtok_r(str, ",", &saveptr); // 使用 strtok_r 替代 strtokwhile (token != NULL) {printf("Token: %s\n", token);token = strtok_r(NULL, ",", &saveptr);}
}
8. 输入验证和边界检查
用户输入的内容可能过长或恶意,必须在读取数据时验证边界,避免安全问题。
示例:
#include <stdio.h>
#include <string.h>void read_and_validate() {char buffer[50];// 读取用户输入,但限制长度为 sizeof(buffer) - 1printf("Enter input: ");if (fgets(buffer, sizeof(buffer), stdin) != NULL) {// 检查并去除末尾换行符size_t len = strlen(buffer);if (len > 0 && buffer[len - 1] == '\n') {buffer[len - 1] = '\0';}printf("Validated input: %s\n", buffer);}
}
9. 使用静态分析工具
使用代码分析工具可以帮助您检测潜在的字符串处理问题,例如:
- Valgrind:检测内存泄漏以及溢出问题。
- Lint:静态分析工具,可发现潜在的代码问题。
管理缓冲区溢出的步骤总结:
- 始终显式定义缓冲区大小。
- 使用长度限制的函数(如
strncpy,snprintf)替代没有边界检查的函数。 - 确保目标字符串以
\0(空字符)结尾。 - 在操作之前检查缓冲区的大小是否足够。
- 使用动态内存分配处理长字符串。
- 避免使用危险、不安全的函数(如
gets)。 - 如果可用,首选更安全的替代函数(例如
strlcpy,strlcat)。
通过这些方法,可以减少甚至完全避免由于字符串处理引起的缓冲区溢出问题,提高代码的安全性和鲁棒性。
相关文章:
C语言字符串处理相关函数详解
C语言字符串处理相关函数详解 相关函数详解1. **字符串拷贝**:strcpy 和 strncpy 2. **字符串连接**:strcat 和 strncat 3. **字符串比较**:strcmp 和 strncmp 4. **字符串长度**:strlen 5. **字符串查找**:strchr 和 …...
【深度学习新浪潮】图像修复(Image Inpainting)技术综述:定义、进展与应用展望
本文为精简版,完整技术细节与参考文献可与作者讨论。 1. 图像修复的定义与核心目标 图像修复(Image Inpainting)是一种通过算法手段填补图像中缺失区域或移除不需要对象的技术,其核心目标是利用图像上下文信息生成与周围像素一致且视觉自然的内容。该技术通过计算机视觉和…...
贪心算法(14)(java)无重叠区间
题目:给定一个区间的集合 intervals ,其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。 注意 只在一点上接触的区间是 不重叠的。例如 [1, 2] 和 [2, 3] 是不重叠的。 示例 1: 输入: intervals [[…...
Linux编译安装mysql5.7.44 笔记250330
Linux编译安装mysql5.7.44 以下是在Linux系统上通过编译源码安装MySQL 5.7.44的详细步骤: 准备工作 1. 安装依赖库 Debian/Ubuntu # Debian/Ubuntu sudo apt update sudo apt install -y gcc g cmake make libncurses5-dev libssl-dev libboost-dev \bis…...
计算机视觉——传统数字图像处理中图像去噪原理与代码实现细节
1. 概述 在现实世界中捕获的图像常常受到噪声的影响,这些噪声可能来源于环境因素、信号不稳定、相机传感器问题、照明条件差、电损失等多种因素。为了进一步处理这些图像并对结果进行准确解释,拥有尽可能低噪声的图像至关重要。图像去噪是数字图像处理中…...
【STM32】最后一刷-江科大Flash闪存-学习笔记
FLASH简介 STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程,(系统存储器用于存储原厂写入的BootLoader程序,用于串口…...
JS实现动态点图酷炫效果
实现目标 分析问题 整个图主要是用canvas实现,其中难点是将线的长度控制在一定范围内、并且透明度随长度变化。 前置知识 canvas绘制点、线、三角形、弧形 // 点ctx.moveTo(this.x, this.y);ctx.arc(this.x, this.y, this.r,0, 2 * Math.PI, false);ctx.fillStyle …...
【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【思路篇】A题解题全流程(持续更新)
【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】A题解题全流程-思路(持续更新) 写在前面: 1、A题、C题将会持续更新,陆续更新发布文章 2、赛题交流咨询Q群:1037590285 3、全家桶依旧包含: 代码、…...
爱普生晶体单元FC2012AN在5G RedCap中的应用
在 5G 技术向物联网领域深度渗透的今天,RedCap(5G 轻量化)作为衔接中高速物联网场景的关键技术,正加速推动工业、医疗、可穿戴等领域的智能化升级。爱普生 FC2012AN 低 ESR 晶体单元凭借其突破性的小尺寸、低功耗与高稳定性设计&a…...
vue 两种路由模式
一、两种模式比较 在vue.js中,路由模式分为两种:hash 模式和 history 模式。这两种模式决定了URL的结构和浏览器历史记录的管理方式。 1. hash 模式带 #,#后面的地址变化不会引起页面的刷新。换句话说,hash模式不会将#后面的地址…...
Java-servlet(十)使用过滤器,请求调度程序和Servlet线程(附带图谱表格更好对比理解)
Java-servlet(十)使用过滤器,请求调度程序和Servlet线程 前言一、Servlet 间通信(了解即可)二、Servlet 请求处理:getAttribute 和 getParameter 的区别与应用1.getAttribute 方法2.getParameter 方法 三、…...
ue5 学习笔记 FPS游戏制作35 GameMode与GameInstance
文章目录 相似GameMode介绍声明设置生效调用 GameInstance介绍声明设置生效调用 相似 两者都用来保存公共的数据和方法 数据都在内存里,关闭程序后数据消失 GameMode 介绍 生命周期跟随关卡,关卡销毁GameMode也跟随销毁 内部可以定义属性和方法 声明…...
rocky9.4 升级SSH 9.9p2
echo "##################################开始升级Openssh##################################################################################" ##ssh变量---------------------------------------- sshnumber9.9p2 sshnumber1ssh -V 2>&1 | cut -d, -f…...
基于WebSocket的金融数据实时推送系统架构设计对接多国金融数据API
基于WebSocket的金融数据实时推送系统架构设计 ——高可用、低延迟与全球化数据支持的技术实践 一、实时数据推送的技术演进 在证券交易、外汇监控、量化策略等场景中,毫秒级延迟可能带来完全不同的业务结果。早期基于HTTP轮询的方案存在三大核心问题:…...
山洪预警秒级响应-AI本地化部署在极端降雨短临预测中的技术突破。AI智能体开发与大语言模型的本地化部署、优化技术
极端降雨预测的技术痛点与边缘破局 1. 传统预警系统的三重瓶颈 延迟致命:WRF模式在1km分辨率下3小时预报耗时>45分钟,错过山洪黄金响应期 地形干扰大:复杂地形区(如横断山脉)降水预测误差超50% 数…...
矿山自动化监测解决方案
1.行业现状 为贯彻落实《中共中央国务院关于推进安全生产领域改革发展的意见》《“十四五”矿山安全生产规划》(应急〔2022〕64号)、《国务院安委会办公室关于加强矿山安全生产工作的紧急通知》(安委办〔2021〕3号)等有关工作部署…...
pytorch学习(b站小土堆学习)
1 环境配置 参考链接 2. dir 和 help函数 dir():用于查看某一模块函数的方法 help(): 用于查看某方法的使用方法 3. dataset类实战 利用Image对象打开图片,利用os模块的地址拼接组成图片路径 当我们用方括号访问元素对象时,…...
微信小程序:解决tabbar切换时,页面不刷新问题
在微信小程序中,默认情况下切换 tabBar 页面时,页面不会重新加载或刷新(而是保持之前的状态)。如果你需要在切换 tabBar 时触发数据刷新或重新执行某些逻辑,可以通过以下方法解决: 方法 1:…...
【最新】探索CFD的未来:从OpenFOAM到深度学习,全面解析计算流体力学的顶级资源与前沿技术
计算流体力学(CFD)作为现代工程与科学研究的核心工具,正以前所未有的速度迈向智能化与多物理场耦合的新时代。本文全面梳理了在线学习CFD的顶级资源,涵盖了从传统数值模拟到深度学习驱动的物理信息模型的广泛领域,旨在为研究者、工程师和学生提供一站式参考指南。内容分为…...
算法专题一:双指针算法(下)
书接上回 5.有效三角形个数 力扣: 有效三角形的个数 在做这道题前我们先讲一个数学知识:已知 a < b < c ,此时 ab>c 可以得出 有效三角形。 所以,我们做这道题时,可以不使用暴力算法。 可以优化为先排序ÿ…...
数据库部署在服务器表不存在解决方案
MySQL 数据库表不存在错误解决方案 MySqlException (0x80004005): Table store.SysLogOperate doesnt exist 服务器用的mysql5.6 用这个表syslogoperate只是全是小写 看起来你在使用 Pomelo.EntityFrameworkCore.MySql 作为 MySQL 数据库的提供程序,并且在初始化…...
咪咕MG101_晨星MSO9380芯片_安卓5.1.1_免拆卡刷固件包
咪咕MG101_晨星MSO9380芯片_安卓5.1.1_免拆卡刷固件包(内有教程) 刷机教程简单说明: 1、把下载好的刷机包,U盘里建立一个upgrade文件夹,固件放入此文件夹里,放入U盘中,注意升级包为压缩包不要对…...
cJSON类型及type值详解
cJSON的核心结构体 cJSON的核心结构体就是一个cJSON,理解了这个结构体,基本上对cJSON的使用就有了个基本概念了。该结构体具体定义如下: typedef struct cJSON { struct cJSON*next,*prev; /* 遍历数组或对象链的前向或后向链表指…...
T11 TensorFlow入门实战——优化器对比实验
🍨 本文為🔗365天深度學習訓練營 中的學習紀錄博客🍖 原作者:K同学啊 | 接輔導、項目定制 一、前期准备 1. 导入数据 # Import the required libraries import pathlib import matplotlib.pyplot as plt import tensorflow as t…...
2023年3月全国计算机等级考试真题(二级C语言)
😀 第1题 下列叙述中错误的是 A. 向量是线性结构 B. 非空线性结构中只有一个结点没有前件 C. 非空线性结构中只有一个结点没有后件 D. 只有一个根结点和一个叶子结点的结构必定是线性结构 概念澄清 首先,我们需要明确几个关键概念…...
在MFC中使用Qt(四):使用属性表(Property Sheet)实现自动化Qt编译流程
前言 首先回顾下前面文章介绍的: 在MFC中使用Qt(一):玩腻了MFC,试试在MFC中使用Qt!(手动配置编译Qt) 在MFC中使用Qt(二):实现Qt文件的自动编译流…...
Python-八股总结
目录 1 python 垃圾处理机制2 yield3 python 多继承,两个父类有同名方法怎么办?4 python 多线程/多进程/协程4.1 多线程与GIL全局解释器锁4.2 多进程4.3 协程 5 乐观锁/悲观锁6 基本数据结构**1. 列表(List)****2. 元组࿰…...
局域网数据同步软件,局域网数据备份的方法
局域网数据备份的方法: 局域网数据备份是确保数据安全性的重要措施,以下是一些常用的局域网数据备份方法: 1.使用NAS设备备份 特点:网络附加存储(NAS)设备提供了一种便捷的备份方式。 操作:…...
ngx_http_core_init_main_conf
定义在 src\http\ngx_http_core_module.c static char * ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf) {ngx_http_core_main_conf_t *cmcf conf;ngx_conf_init_uint_value(cmcf->server_names_hash_max_size, 512);ngx_conf_init_uint_value(cmcf->serv…...
座舱与智驾“双轮驱动”,芯擎科技打造智能汽车“芯”标杆
在比亚迪、吉利、奇瑞等各大主机厂打响“全民智驾”的关键时期,以芯擎科技为代表中国芯片厂商开始“放大招”。 2025年3月27日,芯擎科技在南京举办了“擎随芯动、智融万象”生态科技日,重磅发布了“星辰一号”、“星辰一号Lite”,…...
