=C入门=深入研究 字符串与字符数组

2024年C C++最全[C语言] 初始字符串 & 转义字符与注释_c语言原始字符串,C C++基础开发 所以,后面空间的内容是未知的。对于未知的内容,那我们打印的内容自然是不知道的从而打印出来了乱码。从这里我们打印的结果当中可以看出来是不一样的,第一种我们打印的时候只打印helloC,第二种的时候在打印的时候后面出现了乱码!这个情况又再次充分的证明了字符串的结束标志是反斜杠(\0),对于字符串来说它的结束标志是非常重要的,好好利用这一点可以让你的程序效果更上一层楼。不知道大家发现没有当我们是arr1数组的时候在最后当中是有反斜杠(\0),但是当我们在arr2数组的时候它是没有反斜杠(\0)的。 阅读详情

title: =C入门=深入研究 字符串与字符数组
date: 2023-11-08 21:11:51
tags: C语言 字符串 数组

原文见我的网站: www.supdriver.top

什么是字符串

初见字符串

我们最先遇到的字符串,一般是hello_world程序中用到的"hello world",也就是两个双引号括起来的一串字符,输出时的占位符是%s,可以直接拿去传值,代码如下

printf("%s","hello world");

声明字符串变量

有时我们想要先把字符串存起来,再进行操作,那么就使用字符数组,并在初始化的时候把字符串传给它,这样在创建数组时会编译器会自动分配内存给它,代码如下

char str[] = "abcdef";

此时我们也可以开启VS的调试,并打开内存和监视窗口观察字符串是如何在内存中储存的,如下图

通过观察可以发现,C语⾔字符串的字符串有个规定(特点),就是以字符\0结尾,无论是初始化数组时,还是在分配内存时,都有\0的位置。

strlen()函数

依据以\0为字符串结尾的规则,strlen函数就可以计算字符串的长度,它会从字符串的第一个字符向后扫描,直到遇到\0结束,且\0不进入计数,最后返回字符串的长度,代码如下

#include <string.h> //需要引对应的头文件

int len = strlen("abcdef");//len的值为6
int sz = sizeof("abcdef");//sz的大小为7(\0被计入总数)

验证字符串的结尾

正向验证

我们做在字符数组里插入一个\0,来看看函数printf和strlen找到的结尾在哪里,如下图

char str[] = {'a','b','c','\0','d','e','f','\0'};

可以看到字符数组似乎被“截断”了,printf只输出了\0前面的内容, strlen算出来的长度也只有3,可见插入的\0被作为了字符串的结尾,字符串提前中指,而没到达字符数组的结尾

反向验证

我们来反向验证一下,\0是字符串结尾的标志,如下图,我们声明一个没有\0结尾的字符数组,看看函数printf和strlen还找不找得到我们“认为”的结尾

char str[] = {'a','b','c','d','e','f'};

可以看到函数对字符串的判断出现了严重失误,所以字符数组里没有\0标记结尾是非常严重的问题,不光是找不到字符串的结尾,而且会越界访问!危险操作,写代码的时候一定要注意


从字符串到字符数组

虽然上面已经用到了字符数组,但主要还是为了方便讨论字符串,接下来着重研究字符数组。

先整清楚几个概念

什么是数组:数组是⼀组相同类型元素的集合,会在内存中开辟一段连续的空间,将元素储存在那段内存中

什么是数组元素:存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的⼤⼩和数组的元素类型。

所以字符数组是一组字符的集合,字符数组里的元素都是字符!,访问到的字符数组里的元素都是字符,像'a','b','c'这种的单个的字符,别和字符串混为一谈!

char str = "abc";
int sz = sizeof(str);//这里str代表了整个数组,所以包括\0
,sz的值为4

字符数组的声明

字符数组的声明和其他类型的数组差不多,有初始化,不完全初始化,声明长度,不声明长度

正确的声明代码如下

char str1[] = "abc";//初始化,不声明长度

char str2[] = {'a','b','c','\0'};//这也是初始化,且不声明长度

char str3[10] = { 0 };//初始化,用值0(等价于`\0`)填充

char str4[10] = "abc";//不完全初始化,存入字符串"abc",后面都用'\0'填充

char str5[10] = {'a','b','c','d'};//不完全初始化,从下标为0开始,依次往后填充字符 a,b,c,\0

错误的声明代码

char str1[3] = "abc";//数组声明短了,放不下结尾的\0,编译过不了

char str2[3] = {'a','b','c','d'};//同上,放不下

char str3[] = { 0 };//能声明,但是字符数组长度为1,这个数组大概率是用不了的/会被拿去错误使用的

来看看这些声明方式在内存中的表现

不初始化的声明(极度不推荐)
char str[];//这个不加长度,直接编译失败(如下图)

char str[10];//语法没有问题,来看看此时数组里存了什么


可以看到全都存了-52,对应的中文字符是烫,这样不好,请在声明字符数组的时候初始化数组

不声明长度的数组声明
char str1[] = "abc";

char str2[] = {'a','b','c','\0'};

如上图,不声明长度时,编译器自动给字符数组分配内存,既不给多,也不给少,初始化给的字符串或者{...}多长,创建的数组就多长。

注意红框,再强调一遍,字符串以\0结尾,看到双引号括起来的字符串,要记得最后隐藏了一个\0,用字符数组储存的时候一定要留足空间

声明长度的数组声明
char str3[10] = { 0 };

char str4[10] = "abc";

char str5[10] = {'a','b','c','d'};

可以看到,在声明的长度足够长时,你初始化的时候给它多少字符,它就从下标0处开始按顺序存进去多少,剩下的部分自动用'\0'填充,

所以实际上上面代码中的str5因为长度10>初始化给的4个字符,后面六个元素用\0填充了,所以str5里存了有结尾的完整字符串

错误声明
char str1[3] = "abc";
char str2[3] = { 'a','b','c','d' };

可以看到上面两种错误的声明方式,甚至直接编译失败,所以声明字符数组的时候一定要留足空间

char str3[] = { 0 };

如上图,可以看到这样写还是编译成功了,但是在监视查看数组长度的时候,发现长度为1,里面存了一个\0,这么短的数组能用吗?只能用一点点,甚至还不如直接声明一个char类型的字符变量

当字符数组加上const

const char str[5] = "abc";

一些性质

可以看到,声明时加了const之后,字符数组str在声明时的初始化之后便不可更改了,只能访问其元素,而不能通过访问元素来改变数组内容

那么scanf还能写入内容吗?答案是可以!(如下图)

那它能拿来初始化别的数组吗?很遗憾,不能

对应的指针类型

可以看到,这里得用const char*来储存字符数组的地址,而使用char*就会报错

那么用双引号括起来的字符串,是否也有地址,能用指针储存它的地址呢?

如图,可以看到,字符串"abc"是属于const char类型的数组,对应的指针是const char*,不能通过访问元素来改变内部的值,也不能用char*来储存地址

在内存中的表现

可以看到哪怕是字符串"abc",也是在内存中开辟了一段空间,并把字符储存在内存中了的

但是,不要试图用scanf去改变字符串的值


如何向字符数组里添加内容

添加的方法多种多样,搞不好可能还会出错,所以把字符数组学明白很重要!

以下使用的数组样例声明如下

char str[10] = { 0 };

初始化

在初始化的时候就把值传进去,有哪些初始化方式上面已经介绍过了,这里不多赘述

访问数组元素

通过[]可以访问数组元素,并对没有const修饰的数组,修改其元素,例如:

str[0] = 'A';//将数组的第一个元素改成字符A

我们也可以通过循环的方式,将数组的所有元素填充为某个字符

char place_holder = 'A';
for(int i = 0; i < 10 ; i++)//这里使用左闭右开区间,10为数组的大小
{
    str[i] = place_holder;
}

使用scanf函数

由上面的探究已知:对于已声明的字符数组,无论有没有const修饰,都可已用scanf修改内容,那么scanf怎么用,又具体怎么工作的,我们接着往下探究

使用示例
char str[10] = { 0 };
scanf("%s",str);//占位符是 %s ,右边的参数是 str ,也就是数组名
//或者 scanf("%s",&str)

注意!这边的数组名str储存的是数组首元素的地址,而&str储存的是整个数组的地址,值是一样的,两者皆可用于传参,但指针类型不一样,要做好区分

scanf都做了什么

先来看看它分别对用{ 0 }初始化和不初始化的数组做了什么

char str1[10] = { 0 };
scanf("%s",str1);
char str2[10];
scanf("%s",str2);

两个数组的输入均为abc

可以看到,对str1,字符非常正常地填充进去了,因为整个数组原本是用\0填充的,看不出什么端倪

而对于str2,观察发现,除了输入进去的字符a,b,c,它还自动在结尾补了一个\0,使str2里储存了一个完整的字符串。但是,剩下的部分还是用值-52填充,即未初始化的状态,所以依然不提倡声明的时候没有初始化

然后是在字符数组内已有内容的情况下,再次使用scanf的情况

char str1[5] = "abc";
char str2[5] = "abc";

scanf("%s %s",str1,str2);

如图,scanf做的是把输入的字符串覆盖式存入字符数组,比原来长,就完全覆盖,比原来短,就部分覆盖,未覆盖的部分无改动

关于scanf的危险操作

由于scanf无法预测字符数组能否存下输入的字符串,如果字符数组声明的长度不够,就可能出现越界访问,随之而来的便是奇奇怪怪的bug

char str[4] = { 0 };//先声明一个长度为4的数组
scanf("%s",str);//这次输入abcdef试试

可以看到,确实越界访问了,所以声明字符数组的时候,建议比预计最大输入,在多些长度,防止越界访问。

法预测字符数组能否存下输入的字符串,如果字符数组声明的长度不够,就可能出现越界访问,随之而来的便是奇奇怪怪的bug

char str[4] = { 0 };//先声明一个长度为4的数组
scanf("%s",str);//这次输入abcdef试试

[外链图片转存中…(img-XofIq1Or-1747377601782)]

可以看到,确实越界访问了,所以声明字符数组的时候,建议比预计最大输入,在多些长度,防止越界访问。

『n8n』初识界面 在首页(Overview),我们和 n8n 最常打交道的是“Workflows”、“Credentials”、“Executions”这几个面板(其实后面2个也会用到,但初学阶段可以先不管)。Workflows 面板可以看到我们创建的所有工作流,所以要给工作流起一个一眼看上去就知道是干嘛的名字。 阅读详情

相关推荐

解决turmex安装kali报错问题

在手机上安装好turmex后,都喜欢安装一个Linux系统,我当时安装的时kali,但是安装过程中,报错不断。 2019.8.24更新 1,出现问题首先看下载kali源文件是否完整 安装步骤中,会显示[解压中.....] ,可以看到解压的大小。 如图所示,完整源文件不小于81M。 如果源文件过小,则说明下载错误,而且在remove kali这个命令下,是不会删除源文件的,下一次安装只...

WeiLuckyStrike的博客 1万+

字符串指针与字符数组

很多刚从C转C++的人都不明白,在C中这样的代码char *pChar="hELLO!"; //定义字符指针pChar,指向一个字符数组首元素即h*pChar=H; //问题所在行到了C++中怎么就不行了?你翻遍参考书,都会说,pChar指向的是常量,怎么能允许改变呢?你又问了,怎么我在C中运行的好好的?没人回答你。于是,你只好自我安慰,这就是C++的保护机制吧。我来做个总结吧,发现这个问题如

eddy3的专栏 1453

AI人工智能全模态大模型架构:推动智能交通发展的架构设计

本文旨在阐述全模态大模型在智能交通领域的架构设计原理和应用方法。我们将探讨如何利用多模态AI技术解决交通流量预测、事故预警、路线优化等关键问题。文章将从基础概念入手,逐步深入技术细节,最后探讨实际应用和未来发展方向。全模态大模型:能够处理和理解多种数据模态(如图像、文本、语音等)的大型AI模型智能交通系统(ITS):利用先进技术优化交通流量和安全性的综合系统多模态融合:将不同数据源的信息整合处理的技术核心概念回顾全模态大模型是能够处理多种数据类型的强大AI系统。

AGI×大数据,开启智能时代的认知跃迁;解码AGI,赋能数据驱动的智能革命。 834

【C语言】常见字符串函数及其易错使用(strlen、strcpy、strcat的简单与深入研究)

计数器方法我们当然要定义一个变量count当作计数器,从代码中我们不难看出str是char*类型的指针,指向arr数组中的第一个元素的地址,str是char*类型的指针,指向arr数组中的第一个元素的地址,基础的数组传参要记清楚,往下走,在while循环中对str指针进行解应用,当这个指针指向的地址中的元素不为'\0'的时候,那就给count++;我们还是拿上面的代码举例啊。和上面的一样,函数的返回类型是char*,要把后面的内容加到前面去,所以后面的内容不用改变,要用const修饰。

wangduduniubi的博客 975

GitLab中国区注册终极解决方案:绕过+86手机验证的实战技巧(2023最新)

本文详细解析了GitLab中国区注册时绕过+86手机验证的三种实战技巧,包括开发者工具调试方案、使用国际号码的变通方案以及本地化部署替代方案。通过技术分析和实践验证,帮助开发者顺利注册GitLab账号,提升团队协作效率。

rl6adventurer的博客 1493

从冰棍到铸钢:手把手用Fluent融化凝固模型模拟3个不同场景(含案例设置对比)

本文深入探讨了Fluent融化凝固模型在冰棍融化、巧克力涂层凝固和钢铁连铸三个不同场景中的应用。通过详细的参数设置和案例对比,帮助工程师掌握相变模拟的核心技巧,提升工业级CFD分析的精度和效率。

weixin_42522953的博客 471

字符串指针与字符数组 (转)

字符串指针与字符数组 (转)[@more@]很多刚从C转C++的人都不明白,在C中这样的代码 char *pChar="hELLO!"; //定义字符指针pChar,指向一个字符数组首元素即hXML:namespace p...

csd3176的博客 219

C++ 类

本文介绍了C++中类的核心概念和使用方法。

weixin_54859557的博客 1016

关于字符串和字符数组的再讨论

字符串指针与字符数组(转载) 选择自 happycock 的 Blog很多刚从C转C++的人都不明白,在C中这样的代码char *pChar="hELLO!"; //定义字符指针pChar,指向一个字符数组首元素即h*pChar='H'; //问题所在行到了C++中怎么就不行了?你翻遍参考书,都会说,pChar指向的是常量,怎么能允许改变呢?你又问了,怎么我在C中运行的好好的?没人回答你...

weixin_34417814的博客 79

使用MATLAB进行灰色预测 GM(1,1)

使用MATLAB进行灰色预测 GM(1,1)

Hou_____的博客 997

破晓之光:GTK#框架让C# WinForm程序跨平台运行的终极指南

GTK#框架的出现,彻底打破了C# WinForm只能在Windows上运行的桎梏。

墨夶的博客 605

2024年C C++字符串基础,类型,使用方法大全(字符,字符串(1),2024年最新掌握这个提升路径

/已经完成定义(包括编译器默认的初始化)//错误str="abc";//错误str={0};//错误错误的原因是字符数组名代表字符数组的收地址,不可修改,不能作为左值。左值的概念见博客:认识左值与常引用。

2401_84975342的博客 571

Q3D提取PCB走线RLCG参数

介绍一种提取PCB走线寄生电容和寄生电感的方法

sinat_15150363的博客 2917

【c语言】strcpy()和strncpy():字符串复制详解

通过深入理解这两个函数的特性,我们可以更有效地使用它们,提高代码的质量和可维护性。

m0_74195174的博客 5794

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

深入C语言3——字符串函数

今天我们将再深入研究一个老朋友了,字符串

weixin_55805679的博客 4496

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

2024年C C++最全C C++字符串基础,类型,使用方法大全(字符,字符串(2),离开小厂进大厂的第一周

/已经完成定义(包括编译器默认的初始化)//错误str="abc";//错误str={0};//错误错误的原因是字符数组名代表字符数组的收地址,不可修改,不能作为左值。左值的概念见博客:认识左值与常引用。//已经完成定义(包括编译器默认的初始化)//错误str="abc";//错误str={0};//错误错误的原因是字符数组名代表字符数组的收地址,不可修改,不能作为左值。左值的概念见博客:认识左值与常引用。

2401_84975828的博客 446

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

c substring截取字符串_灵魂拷问:Java 的 substring() 是如何工作的?

在逛 programcreek 的时候,我发现了一些小而精悍的主题。比如说:Java 的 substring() 方法是如何工作的?像这类灵魂拷问的主题,非常值得深入地研究一下。另外,我想要告诉大家的是,研究的过程非常的有趣,就好像在迷宫里探宝一样,起初有些不知所措,但经过一番用心的摸索后,不但会找到宝藏,还会有一种茅塞顿开的感觉,非常棒。对于绝大多数的初级程序员或者说不重视“内功”的老鸟来说,往...

weixin_31758889的博客 264

2024年Go最新C C++字符串基础,类型,使用方法大全(字符,字符串,Golang开发零基础教学

/已经完成定义(包括编译器默认的初始化)//错误str="abc";//错误str={0};//错误错误的原因是字符数组名代表字符数组的收地址,不可修改,不能作为左值。左值的概念见博客:认识左值与常引用。

2401_84904964的博客 1036

C语言入门教程,C语言学习教程(非常详细)第六章 C语言数组

我们知道,要想把数据放入内存,必须先要分配内存空间。放入4个整数,就得分配4个int类型的内存空间:int a[4];这样,就在内存中分配了4个int类型的内存空间,共 4×4=16 个字节,并为它们起了一个名字,叫a。我们把这样的一组数据的集合称为数组(Array),它所包含的每一个数据叫做数组元素(Element),所包含的数据的个数称为数组长度(Length),例如int a[4];就定义了一个长度为4的整型数组,名字是a。

weixin_74774974的博客 1019

字符串指针和字符数组

原作:happycock@优快云       很多刚从C 转C++ 的人都不明白,在C 中这样的代码       char *pChar="hELLO!" ; // 定义字符指针pChar ,指向一个字符数组首 元素即h       *pChar='H'; // 问题所在行       到了C++ 中怎么就不行了?你翻遍参考书,都会说,pChar

xiaohai 405

2024年最新字符串函数讲解(C语言笔记,建议收藏!!!,2024年最新精选C C++面试真题集锦

作用是将一个字符串(以‘\0’结束的字符序列)输出到终端。

2401_84978645的博客 613
上一篇: 如何在VS里使用scanf
下一篇: 堆排序实现详解
supdriver
博客等级 码龄3年 192粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值