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

字符串与字符指针——没有 string 类型的世界

C 语言没有 string 类型

这是很多初学者的误区。C 语言没有内置的 string 类型。字符串在 C 里就是char数组,末尾加一个\0(空字符)标记结束

char str[] = "hello"; // 内存布局:'h' 'e' 'l' 'l' 'o' '\0' // 共 6 字节,最后的 \0 是字符串结束标记

字符串的两种创建方式

方式 1:字符数组(可修改)

char str[] = "hello"; str[0] = 'H'; // OK,数组在栈上,可以修改 printf("%s\n", str); // "Hello"

char str[] = "hello"会把字符串复制到栈上的数组里。

方式 2:字符指针(不可修改)

char *str = "hello"; str[0] = 'H'; // 未定义行为!可能崩溃

char *str = "hello"str指向字符串常量所在的只读内存区。修改它就是写只读内存——未定义行为,通常段错误。

实际项目中:

  • 需要修改内容 →char str[]

  • 只读访问 →char *str(更省内存,多处共用同一份)

\0的重要性

char s1[] = {'h', 'e', 'l', 'l', 'o'}; // 没有 \0 char s2[] = {'h', 'e', 'l', 'l', 'o', '\0'}; // 有 \0 char s3[] = "hello"; // 自动加 \0

s1不是合法的字符串——没有\0结束标记。

所有字符串函数都依赖\0判断结束:

printf("%s", s1); // 一直读到碰到 \0 为止——越界,输出垃圾值 strlen(s1) // 一直数到碰到 \0 为止——越界,返回随机值 strcpy(dest, s1) // 一直复制到碰到 \0 为止——越界,可能覆盖别的数据

sizeof vs strlen

char s[] = "hello"; printf("%zu\n", sizeof(s)); // 6(整个数组,含 \0) printf("%zu\n", strlen(s)); // 5(实际字符数,不含 \0)
  • sizeof是编译时确定的,算整个数组大小

  • strlen是运行时计算的,遍历到\0为止

声明字符数组时要多留 1 字节给\0

char name[5]; // 能存 4 个字符 + 1 个 \0 char name[100]; // 能存 99 个字符 + 1 个 \0

字符串比较:不能用 ==

char s1[] = "hello"; char s2[] = "hello"; ​ if (s1 == s2) // 错!比较的是两个数组的地址,永远不等 if (strcmp(s1, s2) == 0) // 对!比较内容

s1s2是两个不同的数组,地址不同,==永远返回假。

strcmp 返回值

strcmp(s1, s2) == 0 // 相等 strcmp(s1, s2) < 0 // s1 在 s2 前面(字典序) strcmp(s1, s2) > 0 // s1 在 s2 后面

常用字符串函数

#include <string.h> ​ char s[] = "hello"; ​ strlen(s) // 5,字符串长度 strcpy(dest, src) // 复制 src 到 dest(不安全) strncpy(dest, src, n) // 最多复制 n 字节(安全) strcat(dest, src) // 拼接 src 到 dest 末尾 strcmp(s1, s2) // 比较内容

strcpy 的安全隐患

char small[5]; char big[] = "hello world"; strcpy(small, big); // 缓冲区溢出!small 只有 5 字节

strcpy不检查目标数组大小,超出的部分会覆盖相邻内存。实际项目中用strncpy

char dest[10]; strncpy(dest, src, sizeof(dest) - 1); // 最多复制 9 字节 dest[sizeof(dest) - 1] = '\0'; // 手动确保 \0 结尾

字符串遍历

char s[] = "hello"; ​ // 方式1:下标 for (int i = 0; s[i] != '\0'; i++) { printf("%c", s[i]); } ​ // 方式2:指针 for (char *p = s; *p != '\0'; p++) { printf("%c", *p); }

字符串数组

指针数组(灵活)

char *fruits[] = {"apple", "banana", "cherry"}; printf("%s\n", fruits[0]); // "apple" printf("%c\n", fruits[1][0]); // 'b'

字符串长度可以不同,每个char *指向各自的字符串常量。

二维数组(安全)

char fruits[3][10] = {"apple", "banana", "cherry"};

内存连续,不指向只读区,但每行长度固定,浪费空间。

main 的命令行参数

int main(int argc, char *argv[]) { for (int i = 0; i < argc; i++) { printf("%s\n", argv[i]); } return 0; }

argv就是指针数组,argv[0]是程序名,后续是参数。

常见误区速查

误区正确理解
C 有 string 类型没有,就是 char 数组加\0
char *s = "hello"; s[0] = 'H'未定义行为,只读区不能改
==比较字符串比较的是地址,用strcmp
strlen包含\0不包含
strcpy安全不安全,可能溢出,用strncpy
char s[5] = "hello"能存 5 字节但需要 6 字节(含\0),溢出

总结

  • C 语言没有 string 类型,字符串是\0结尾的 char 数组

  • char str[]可修改(栈上副本),char *str不可修改(只读区)

  • sizeof算整个数组含\0strlen不含\0

  • 字符串比较用strcmp==比较的是地址

  • strcpy不安全,实际项目用strncpy

  • 声明字符数组时多留 1 字节给\0

http://www.gsyq.cn/news/1579036.html

相关文章:

  • 原来公墓陵园设计还有好用的老牌服务商?究竟好在哪?
  • 呼和浩特新城区今日黄金回收行情与靠谱机构全解析 - 全城黄金专业上门回收
  • 呼和浩特玉泉区黄金上门回收六店一览即时变现 - 全城黄金专业上门回收
  • Win11 原生连 iPhone 教程!电脑接打电话、同步通知,但有两个巨大短板要提前知道
  • AdGuard浏览器扩展:3分钟打造无广告、高隐私的纯净上网体验
  • LibreDWG终极指南:解决AutoCAD 2022 DWG文件读取错误的技术深度解析
  • AI时代程序员的不可替代性:从搬砖码农到架构师的四阶跃迁
  • 2026年广告行业管理软件深度测评:如何为你的广告企业匹配最佳方案? - 资讯速览
  • AI 写代码又快又好?你可能少了最关键的一步
  • 兰州汽车贴膜实测排名:哪家玻璃膜技术最靠谱?
  • 南宁全城黄金回收门店盘点 今日金价938元 覆盖测评 - 余生黄金回收
  • 告别“在我的机器上能跑”:Python环境管理避坑指南
  • 第17篇:指针3 指针的“高阶形态”:从指向数据到指向函数
  • 东莞淘宝培训哪家值得信赖
  • LangSmith深度解析:打造LLM应用可观测性闭环,从入门到实战全攻略!
  • 2026保姆级教程:txt转PDF免费无需软件,Windows/Mac自带工具、在线网站全攻略 - 软件小管家
  • 减性混合模型:一种高效贝叶斯近似推断方法及其方差控制
  • AI超算一体机选择指南
  • RAG不是插件而是知识信任链:检索增强生成原理与生产落地
  • Nucleus Co-Op:免费快速开启单机多人分屏游戏的终极解决方案
  • 吉林龙潭区黄金回收上门六店快速变现联系 - 全城黄金专业上门回收
  • Blender+AI 科研绘图智能体详细介绍
  • 微信客户跟进如何摆脱“随缘模式”?从 WecomApi 看自动化 SOP 与全生命周期运营架构
  • (2026新)辽阳正规防水补漏公司口碑榜TOP5权威推荐!卫生间/厨房/阳台/屋顶/天花板/地下室渗漏水检测维修攻略-靠谱漏水检测维修师傅推荐 - 安佳防水
  • 海口出手黄金避坑全指南,3种暗扣猫腻,看完直接多卖钱 - 奢侈品回收测评
  • C++内存管理核心:malloc/new混用的原理、风险与工程实践
  • Neo4j驱动连接失败:Bolt协议版本不兼容排查指南
  • WorkshopDL:无需Steam账号,轻松下载创意工坊模组的终极解决方案
  • 2026年AI编程工具实测:四维穿透式生产力损耗诊断
  • WechatDecrypt终极指南:3分钟快速解密微信数据库的完整方案