【C语言督学训练营 第五天】数组字符串相关知识
文章目录
- 前言
- 一、数组的定义
- 1.一维数组
- ①.如何定义
- ②.声明规则
- ③.内存分布
- ④.初始化方法
- 2.二维数组
- 3.高维数组
- 二、访问数组元素相关问题
- 1.访问越界
- 2.数组的传递
- 三、Scanf与字符数组
- 1.字符数组初始化
- 2.scanf读取字符
- 四、字符数组相关函数
前言
今天的C语言训练营没有安排高维数组的讲解,因为考试中常考的是一维数组,老师根据一维数组分析了数组越界、数组在内存中的分布、缓冲区与字符数组等相关问题。
一、数组的定义
先看一个案例:
为了存放鞋子,假设你把衣柜最下面的一层分成了 10 个连续的格子。此时,让他人帮你拿鞋子就会很方便,例如你可直接告诉他拿衣柜最下面一层第三个格子中的鞋子。同样假设现在我们有 10 个整数存储在内存中,为方便存取,我们可以借助 C 语言提供的数组,通过一个符号来访问多个元素。
也就是在我们使用的时候,如果需要用到多个类型相同的变量,我们大可以选数组,来简化我们的操作。
1.一维数组
①.如何定义
一维数组的定义格式为
类型说明符 数组名 [常量表达式]
例如:定义一个整型数组,数组名为 a,它有 10 个元素
int a[10];
②.声明规则
注意:声明数组时要遵循以下规则:
- (1)数组名的命名规则和变量名的相同,即遵循标识符命名规则。
- (2)在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。
- (3)常量表达式中可以包含常量和符号常量,但不能包含变量。也就是说,C 语言不允许对数组的大小做动态定义,即数组的大小不依赖于程序运行过程中变量的值。
- 能不用高维数组就不用高维数组(多一个维度多一点复杂,除非自己特别了解数组)
以下是错误的声明示例(最新的 C 标准支持,但是最好不要这么写):
int n;
scanf(“%d”, &n); /* 在程序中临时输入数组的大小 */
int a[n];
数组声明的其他常见错误如下:
① float a[0]; /* 数组大小为 0 没有意义 /
② int b(2)(3); / 不能使用圆括号 /
③ int k=3, a[k]; / 不能用变量说明数组大小*/
③.内存分布
数组元素在内存中是连续分布的,并且遵循小下标位于低地址的原则。数组中每一个元素占有的空间跟数组类型有关。
④.初始化方法
(1)在定义数组时对数组元素赋初值。例如,
int a[10]={0,1,2,3,4,5,6,7,8,9};
不能写成
int a[10];a[10]={0,1,2,3,4,5,6,7,8,9}
(2)可以只给一部分元素赋值。例如,
int a[10]={0,1,2,3,4};
定义 a 数组有 10 个元素,但花括号内只提供 5 个初值,这表示只给前 5 个元素赋初值,后 5 个
元素的值为 0。
(3)如果要使一个数组中全部元素的值为 0,那么可以写为
int a[10]={0,0,0,0,0,0,0,0,0,0};
或
int a[10]={0};
(4)在对全部数组元素赋初值时,由于数据的个数已经确定,因此可以不指定数组的长度。
例如,
int a[]={1,2,3,4,5};
2.二维数组
除了使用一维数组,还可以使用二维数组,二维数组定义方法与一维数组大致相同。
类型说明符 数组名 [常量表达式][常量表达式]
例如:定义一个整型数组,数组名为 a,它有 100 个元素
int a[10][10];
3.高维数组
C语言支持3维及以上维度的数组,不过我们一般用不到,所以不必深究,只需了解即可。使用数组的时候一定要避免数组越界这个问题,我会在下面介绍到。
先看看高维数组的使用:
//
// Created by Zhu Shichong on 2023/1/9.
//
#include<stdio.h>
main()
{int a[1][1][1];int b[1][1][1][1];int c[2][2][2][2][2];a[0][0][0]=1;b[0][0][0][0]=2;c[1][1][1][1][1]=3;printf("%d %d %d",a[0][0][0],b[0][0][0][0],c[1][1][1][1][1]);return 0;
}
数组元素的个数=定义时各维度下标大小连乘
二、访问数组元素相关问题
1.访问越界
前面介绍过数组定义之后在内存中是连续分布的,并且100个元素的数组最大数组下标为99,那么我们访问下标为100的元素会有什么问题呢?大致有以下两种情况:
- 数组内存中接下来的空间被其余变量占用:会直接导致程序异常。
- 数组内存中接下来的空间没有被其余变量占用:会读出内存中的脏值(也就是乱码。内存中有什么将会读什么),最终亦会导致程序异常。
由此可见,数组越界对我们的程序影响之大。
可能文字不如图片给的感觉强烈,下面给出一个案例:大家可以自行尝试
//
// Created by Zhu Shichong on 2023/1/9.
//
#include <stdio.h>
//数组越界
int main()
{int a[5]={1,2,3,4,5}; //定义数组时,数组长度必须固定int j=20;int i=10;a[5]=6; //越界访问a[6]=7; //越界访问会造成数据异常printf("i=%d\n",i); //i 发生改变return 0;
}
有这种情况的原因是:
编译器并不检查程序对数组下标的引用是否在数组的合法范围内。这种不加检查的行为有好处也有坏处,好处是不需要浪费时间对有些已知正确的数组下标进行检查,坏处是这样做将无法检测出无效的下标引用。
一个良好的经验法则是:
如果下标值是通过那些已知正确的值计算得来的,那么就无须检查;如果下标值是由用户输入的数据产生的,那么在使用它们之前就必须进行检查,以确保它们位于有效范围内。
2.数组的传递
先看一个案例:
//
// Created by Zhu Shichong on 2023/1/9.
//
#include <stdio.h>
#include<string.h>
//一维数组的传递,数组长度无法传递给子函数
//C 语言的函数调用方式是值传递(将地址的值传递过去)
void print(int b[],int len)
{int i;for(i=0;i<len;i++){printf("%3d",b[i]);}b[4]=20; //在子函数中修改数组元素printf("\n");
}
//数组越界
//一维数组的传递
#define N 5
int main()
{int a[5]={1,2,3,4,5}; //定义数组时,数组长度必须固定print(a,5);printf("a[4]=%d\n",a[4]); //a[4]发生改变return 0;
}
如果在print数组时不传递len过去,将会导致无法获取数组的长度,从而无法访问到数组中所有的元素,想要在函数中访问数组中的所有元素,必要的一点就是将数组的长度通过参数的方式传进去。
原因如下:
这是因为一维数组在传递时,其长度是传递不过去的,所以我们通过 len来传递数组中的元素个数。实际数组名中存储的是数组的首地址,在调用函数传递时,是将数组的首地址给了变量 b(其实变量 b 是指针类型,具体原理会在指针节讲解),在 b[]的方括号中填写任何数字都是没有意义的。这时我们在 print 函数内修改元素 b[4]=20,可以看到数组 b 的起始地址和 main 函数中数组 a 的起始地址相同,即二者在内存中位于同一位置,当函数执行结束时,数组 a 中的元素 a[4]就得到了修改。
三、Scanf与字符数组
1.字符数组初始化
字符数组的定义方法与前面介绍的一维数组类似。例如,
char c[10];
字符数组的初始化可以采用以下方式。
(1)对每个字符单独赋值进行初始化。例如,
c[0]=‘I’;c[1]=’ ‘;c[2]=‘a’;c[3]=‘m’;c[4]=’';c[5]=‘h’;c[6]=‘a’;c[7]=‘p’;c[8]=‘p’;c[9]=‘y’;
(2)对整个数组进行初始化。例如,
char c[10]={‘I’,‘a’,‘m’,‘h’,‘a’,‘p’,‘p’,‘y’}
工作中一般不用以上两种初始化方式,因为字符数组一般用来存取字符串。通常采用的初始化方式是 char c[10]= “hello”。因为 C 语言规定字符串的结束标志为’\0’,而系统会对字符串常量自动加一个’\0’,为了保证处理方法一致,一般会人为地在字符数组中添加’\0’,所以字符数
组存储的字符串长度必须比字符数组少 1 字节。例如,char c[10]最长存储 9 个字符,剩余的 1 个字符用来存储’\0’。如果末尾没有存储\0将会可能导致程序出现以下错误(一直沿着字符数组打印,直到内存中存储\0为止)
。
2.scanf读取字符
最明显的就是scanf碰见空白字符会直接阻断
,导致一句话有空格时没办法直接用scanf把那句话读进字符数组。可以通过对下面一个小程序输入 how are you 体会体会。
//
// Created by Zhu Shichong on 2023/1/9.
//
#include <stdio.h>
//scanf 读取字符串时使用%s
int main()
{char c[10];char d[10];scanf("%s",c);printf("%s\n",c);scanf("%s%s",c,d);printf("c=%s,d=%s\n",c,d);return 0;
}
最好的解决方法就是使用gets,puts函数
gets 函数类似于 scanf 函数,用于读取标准输入。前面我们已经知道 scanf 函数在读取字符串时遇到空格就认为读取结束,所以当输入的字符串存在空格时,我们需要使用 gets 函数进行读取。
gets 函数的格式如下:
char *gets(char *str);
gets 函数从 STDIN(标准输入)读取字符并把它们加载到 str(字符串)中,直到遇到换行符(\n)。如下例所示,执行后,我们输入"how are you",共 11 个字符,可以看到 gets 会读取空格,同时可以看到我们并未给数组进行初始化赋值,但是最后有’\0’,这是因为 gets 遇
到\n 后,不会存储\n,而是将其翻译为空字符’\0’。
puts 函数类似于 printf 函数,用于输出标准输出。puts 函数的格式如下:
int puts(char *str);
函数 puts 把 str(字符串)写入 STDOU(标准输出)。puts 会将数组 c 中存储的"how are you"字符串打印到屏幕上,同时打印换行,相对于 printf 函数,puts 只能用于输出字符串,同时多打印一个换行符,等价于 printf(“%s\n”,c)
四、字符数组相关函数
str 系列字符串操作函数主要包括 strlen、strcpy、strcmp、strcat 等。strlen 函数用于统计字符串长度,strcpy 函数用于将某个字符串复制到字符数组中,strcmp 函数用于比较两个字符串的大小,strcat 函数用于将两个字符串连接到一起。
函数原型如下:
头文件 #include <string.h>
size_t strlen(char *str);
char *strcpy(char *to, const char *from);
int strcmp(const char *str1, const char *str2);
char *strcat(char *str1, const char *str2);
对于传参类型 char*,直接放入字符数组的数组名即可。
注意以下几点:
- strlen 函数的计算原理是通过判断结束符来确定字符串的长度。
- strcpy 函数用来将字符串中的字符逐个地赋值给目标字符数组。例中我们将 c 复制给 d,就是将 c 中的每个字符依次赋值给 d,也会将结束符赋值给 d。注意,
目标数组一定要大于字符串大小,即 sizeof(d)>strlen(c),否则会造成访问越界
- strcmp 函数用来比较两个字符串的大小(
首先比较首字母ASCII值,第一个相同比较第二个依次类推
),由于字符数组 c 中的字符串与 d 相等,所以这里的返回值为 0。如果 c 中的字符串大于 d,那么返回值为c与d中不同位字符相减即 c-d(正值);如果 c 中的字符串小于 d,那么返回值依旧为c-d(负值)。如何比较两个字符串的大小呢?具体操作是从头开始,比较相同位置字符的 ASCII码值,若发现不相等则直接返回,否则接着往后比较。例如,strcmp(“hello”,“how”)的返回值是−1,即"hello"小于"how",因为第一个字符 h 相等,接着比较第二个位置的字符,e 的 ASCII 码值小于 o 的,然后返回e-o。不同的标准中有可能返回值不同
,但一定是两字符串相同返回0,前面小后面大返回负值,否则返回正值。 - strcat 函数用来将一个字符串接到另外一个字符串的末尾。例中字符数组 c 中存储的是"hello",我们将 d 中的"world"与 c 拼接,最终结果为"helloworld"。注意,
目标数组必须大于拼接后的字符串大小,即 sizeof(c)>strlen(“helloworld”)
。
今天的分享到此结束!!!
相关文章:

【C语言督学训练营 第五天】数组字符串相关知识
文章目录前言一、数组的定义1.一维数组①.如何定义②.声明规则③.内存分布④.初始化方法2.二维数组3.高维数组二、访问数组元素相关问题1.访问越界2.数组的传递三、Scanf与字符数组1.字符数组初始化2.scanf读取字符四、字符数组相关函数前言 今天的C语言训练营没有安排高维数组…...

GPT-4 免费体验方法
POE 在Quora上非常受欢迎的手机聊天机器人Poe App已经集成ChatGPT助手!除了最初集成的三个聊天机器人Sage、Claude和Dragonfly外,Poe现在还加入了第四位ChatGPT。由于使用了ChatGPT API,因此Poe拥有真正的ChatGPT。 现在更是第一批集成了GP…...
中断-屏蔽位
1.中断控制器(PIC:适用于单处理器、APIC) 1.定义 中断控制器可以看作是中断服务的代理,外设五花八门,如果没有一个中断的代理,外设想要给cpu发送中断信号来处理中断。那么只能是外设连接在cpu引脚上,由于cpu引脚很宝贵,所以不可能拿出那么多引脚来供外设连接,所以就有…...
【洛谷P1636】 Einstein学画画
题目描述:Einstein 学起了画画。此人比较懒~~,他希望用最少的笔画画出一张画……给定一个无向图,包含 n 个顶点(编号 1∼n),m 条边,求最少用多少笔可以画出图中所有的边。输入格式第一行两个整数…...
户外LED显示屏钢结构制作原则
户外LED显示屏在施工安装时是必须要制作固定钢结构的,因为户外LED显示屏工作环境相对比较恶劣,制作钢结构一是为了安全,二是为了提高防护等级。那么户外LED显示屏钢结构制作原则是什么呢?迈普光彩小编总结了一些分享个大家。 户外…...
【内网穿透】使用Haproxy反向代理搭建企业私有云:神卓互联教程
神卓互联是一款强大的内网穿透工具,可以帮助企业搭建私有云,实现对内部资源的远程访问。在搭建私有云的过程中,使用HAProxy反向代理可以提高系统的性能和可靠性。本文将介绍如何使用神卓互联和HAProxy反向代理搭建私有云。 步骤如下…...
spring boot项目:实现与数据库的连接
步骤【写在前面】定义数据库连接信息:引入数据库驱动:创建数据源:创建JdbcTemplate:编写DAO层:使用Service注解标注Service层:使用RestController注解标注Controller层:示例代码:app…...

【gitlab部署】centos8安装gitlab(搭建属于自己的代码服务器)
这里写目录标题部署篇序言要求检查系统是否安装OpenSSH防火墙问题准备gitlab.rb 配置坑点一忘记root密码重置使用篇gitlab转换成中文git关闭注册入口创建用户部署篇 序言 在团队开发过程中,想要拥有高效的开发效率,选择一个好的代码开发工具是必不可少的…...
2021年全国职业院校技能大赛(中职组)网络安全竞赛第三套试题A模块解析(超级详细)
2021年全国职业院校技能大赛(中职组) 网络安全竞赛试题 (3) (总分100分) 赛题说明 一、竞赛项目简介 “网络安全”竞赛共分A. 基础设施设置与安全加固;B. 网络安全事件响应、数字取证调查和应用安全;C. CTF夺旗-攻击;D. CTF夺旗-防御等四个模块。根据比赛实际情况…...

Hbase异步复制和同步复制解析
背景 Hbase是一个KV数据库,自然和Mysql以及Redis等会涉及到复制的问题,也有主从集群的概念,那么本文就来看下Hbase的复制逻辑 Hbase复制实现 首先我们先在回顾下,在Hbase实现中,每个RegionServer上面会包含多个Regi…...

TIKTOK海外直播公会如何申
在“清朗行动”的规范化整治下,国内秀场直播俨然成为了“夕阳行业”,早已度过了野蛮生长的阶段。随着直播公会内卷竞争加剧,公会的生存也愈发艰难,有的娱乐主播甚至纷纷转行做起了电商,可见国内娱乐直播行业的惨淡。 …...

6.springcloud微服务架构搭建 之 《springboot集成Gateway》
5.springcloud微服务架构搭建 之 《springboot集成Hystrix》 目录 1.gateway介绍 2.项目引入gateway 3.yml配置gateway参数 5.自定义全局Filter 6.测试 1.gateway介绍 服务网关(Spring Cloud Gateway)是Spring Cloud官方推出的 第二代网关框架&#…...

[N1CTF 2018]eating_cms_
目录 信息收集 代码审计 parse_url解析漏洞 信息收集 进入即是登录页面,抓包一看应该是SQL注入,但是空格、%、|等等啥的都被waf了,不太好注入,先信息收集一波 花一分钟扫下目录,发现一个viminfo和register.php Viminfo文件…...

《Spring系列》第13章 Aop切面(二) 代理创建
前言 本篇文章主要介绍AOP的源码,要想看懂AOP,那么就看AOP给容器中注入了什么组件,这个组件什么时候工作,这个组件的功能是什么? EnableAspectJAutoProxy会向IOC容器中注入一个后置处理器,它会在Bean的创…...
算法-贪心
贪心算法1信息学竞赛课堂贪心算法2贪心法实际生活中,经常需要求一些问题的“可行解”和“最优解”,这就是所谓的“最优化”问题。一般来说,每个最优化问题都包含一组“限制条件”和一个“目标函数”,符合限制条件的问题求解方案称…...

【数据结构与算法】树(Tree)【详解】
文章目录前言树一、树的基本概念1、树的定义2、基本术语3、树的性质二、树的存储结构1、双亲表示法2、孩子表示法3、孩子兄弟表示法二叉树一、二叉树的概念1、二叉树的定义2、几个特殊的二叉树3、二叉树的性质4、二叉树的存储结构二、遍历二叉树1、先序遍历2、中序遍历3、后序遍…...

OSPF------LSA 详解
LSA头部 [r1]display ospf lsdb 链路状态老化时间(Link-State Age) 16bits,单位s当该LSA被始发路由器产生时,该值被设置为0,之后随着该LSA在网络中被洪泛,老化时间逐渐累积。(但是不能让它一直增长&#x…...
js加解密入门
首先,让我们简单介绍一下百度公司的文心一言。文心一言是百度公司推出的一项文本生成工具,它可以根据给定的主题或关键词生成一句简短而富有启发性的文字。在我们的加密和解密方法中,我们将利用文心一言的特点来生成随机的字符串,…...

vue+Echarts导入自定义地图
在vue项目先安装echarts //在vue文件中的<script>中引入 import * as echarts from "echarts"; import geoJson from ../assets/map/Fmap.json; //自定义地图的位置 import * as topojson from "topojson-client"; //使用组件topojson-client自定…...
dp-组合总和 Ⅳ
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。题目数据保证答案符合 32 位整数范围。示例 1:输入:nums [1,2,3], target 4输出:7解释:所…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...