第四章 数组

news/2024/5/10 3:28:20/文章来源:https://blog.csdn.net/lxl_15139204961/article/details/131525867

前言

学习方法

  1. 可以多看几遍视频
  2. 把上课的代码,自己加加注释,在自己写之前,可以画一个流程图
  3. 照着流程图把代码自己实现一遍

不要怀疑自己,不要遇到困难就觉得自己不行,遇到困难就解决困难,编程初学者都是这样一步一步走过来的。


在指针阶段会演示整型、浮点型、字符型传递(传递的含义就是把一个变量传递给对应的子函数。)

一维数组

数组的定义

所谓数组,是指一组具有相同数据类型的数据的有序集合。

数组具有以下特点:

  1. 具有相同的数据类型
  2. 使用过程中需要保留原始数据

一维数组的定义格式为:

类型说明符 数组名 [常量表达式]

例如,定义一个整型数组,数组名为a,它有10个元素。

int a[10];

声明数组时要遵循以下规则:

  1. 数组名的命名规范和变量名的相同,即遵循标识符命名规则。
  2. 在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。
  3. 常量表达式中可以包含常量和符号常量,但不能包含变量。也就是说,C语言不允许对数组的大小做动态定义,即数组的大小不依赖于程序运行过程中变量的值。
int main() {//定义数组就是写一个变量名,后面加上方括号,方括号内写上整型常量//定义数组时,数组占据的空间大小就确定下来了int a[5] = { 1,2,3,4,5 };
}

使用符号常量,不需要掌握,知道可以这样写即可。

//符号常量
#define N 5
int main() {int a[N] = { 1,2,3,4,5 };
}

查看数组内存空间

看任何变量的内存,都是将该变量取地址,拖入内存窗口来看。 只有指针类型才能拖入内存窗口查看。带 * 号的表示是指针类型

在这里插入图片描述

在这里插入图片描述

赋初值

int a[5] = {1,2,3};

定义数组a有5个元素,但花括号内只提供3个初值,这表示只给前3个元素赋初值,后2个元素的值为0。

如果要使一个数组中全部元素的值为0,那么可以写为

int a[5] = {0,0,0,0,0};

或者

int a[5] = {0};

但肯定是第二种写法为好(当赋初值的个数小于数组大小时,则后面的元素会被自动赋值为0)。

数组访问越界

了解一下:微软的编译器设计,不同的变量之间有8个字节的保护空间(Mac和Linux是没有的)。[这并不是标准C规定的]。

在这里插入图片描述

数组访问越界的错误提醒:

Run-Time Check Failure #2 - Stack around the variable ‘a’ was corrupted.

在这里插入图片描述

原理:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

由上面的例子可知,访问越界会造成数据异常。

简单了解说明一下为什么C的执行效率比Java高:C语言中有指针,可以操作内存,因此效率高;而Java中没有指针,内存交给编译器管理(操作系统管理),提高了开发效率,但执行效率降低。

数组传递

自定义的函数必须写在main函数的上面

注意,自己写的其他方法要放在main方法的上面,否则编译不通

实现打印数组里的每一个元素,这里先将 “打印数组元素的方法” 中数组的大小写成固定数值。

//打印数组里的每一个元素
//自己写的print方法必须放在main方法的上面,否则编译不通
void print(int a[5]) {for (int i = 0; i < 5; i++){printf("a[%d]=%d\n", i, a[i]);}
}int main() {int a[5] = {1,2,3,4,5};print(a);
}

得到输出结果:

在这里插入图片描述

现在想在 “打印数组元素的方法” 中动态的得到数组的大小,进行如下尝试:

//打印数组里的每一个元素
void print(int a[5]) {for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("a[%d]=%d\n", i, a[i]);}
}int main() {int a[5] = {1,2,3,4,5};print(a);
}

而这次的输出结果是:

在这里插入图片描述

通过断点调试发现sizeof(a)=4,而与数组a的大小无关。无论传过来的数组多大,sizeof(a)始终等于4。原因在于数组在传递的时候数组元素是传递不过去的,只能传递数组的起始地址(实际上就是指针)

在这里插入图片描述

正确的写法是这样的,在print方法中新增一个参数表示数组的大小,调用该方法时传入数组的大小。[注:C语言中没有Java中的a.length方法]。

//打印数组里的每一个元素
void print(int a[],int len) {for (int i = 0; i < len; i++){printf("a[%d]=%d\n", i, a[i]);}
}int main() {int a[5] = {1,2,3,4,5};print(a,5);
}//以下代码实现也是正确的
/*
//形参和实参可以不一样
void print(int b[],int len) { //b、len是形参for (int i = 0; i < len; i++){printf("a[%d]=%d\n", i, b[i]);}
}int main() {int a[5] = {1,2,3,4,5};print(a,5);//a是实参
}
*/

在子函数中修改数组元素

在子函数中可以直接修改数组元素,可以读可以写。

//打印数组里的每一个元素
//print是我们自定义的函数,C语言中没有print函数
void print(int b[],int len) {for (int i = 0; i < len; i++){printf("a[%d]=%d\n", i, b[i]);}b[4] = 20;//在子函数中修改数组元素}int main() {int a[5] = {1,2,3,4,5};print(a,5);//调用函数printf("a[4]=%d\n", a[4]);
}

输出结果:

在这里插入图片描述

字符数组

初始化字符数组

字符数组就是专门用来存字符串的(初试和机试)。

初始化字符数组:以后都用第二种初始化字符数组的方式char d[10] = “hello”;

int main() {char c[10] = {'h','e','l','l','o'};//这样初始化字符数组太麻烦了char d[10] = "hello";//这样初始化字符数组也可以,而且简单//给字符数组存一个字符串,就用第二种初始化方式,简单。//字符数组就是专门用来存字符串的(初试和机试)
}

在这里插入图片描述

C语言规定字符串的结束标志为’\0’,读到\0就不会再输出了,而系统会对字符串常量自动加一个’\0’,为了保证处理方法一致,一般会认为地在字符数组中添加’\0’,所以字符数组存储的字符串长度必须比字符数组少1字节。例如char c[10]最长存储9个字符,剩余的1个字符用来存储’\0’。

在这里插入图片描述

ASCII码表中\0对应编码是0000 0000 即值是0,\0在内存中存的值就是0.

所以正确的初始化字符数组代码如下:初始化字符数组时,一定要让字符数组的大小比看到的字符串的长度多1

//初始化字符数组时,一定要让字符数组的大小比看到的字符串的长度多1
int main() {char c[6] = {'h','e','l','l','o'};//字符数组存储的字符串长度必须比字符数组少1字节char d[5] = "how";//%s :输出一串字符串printf("%s------%s", c, d);//printf的%s,对应后面要写的是字符数组名或者字符串常量//printf("%s", "Chinese");//printf的%s,后面写字符串常量的例子
}

向字符数组中读取字符串

scanf中%s不用加&取地址符。[原因在于数组名本身存储的就是数组的起始地址(指针)。当然这里写上&取地址符也不会错,但一般不写].

%s和%d,%f一样都会忽略空格和\n。

scanf读取我们输入的字符串后会自动添加结束符\0。

//向字符数组中读取字符串
int main() {char e[20];//scanf中%s不用加&取地址符scanf("%s", e);//%s和%d,%f一样都会忽略空格和\n。printf("%s\n", e);
}

在这里插入图片描述

同时读取多个:

int main() {char e[20],f[20];scanf("%s%s", e,f);//,当读取多个时%s%s中间不用加空格,因为%s和%d,%f一样都会忽略空格和\n。printf("%s---%s\n", e,f);
}

%s、%d、%f都会忽略空格和\n,因此在输入多个时中间不用加空格,而%c不会忽略空格和\n,所以在多个混合输入时有%c出现时要在 %c前面加一个空格。

在这里插入图片描述

如何把wangdao xue408 读到同一个字符数组中(包括那个空格),用scanf实现较为麻烦,因为需要用到正则,不需要掌握。用gets就很容易实现了,gets可以一次读一行,中间有空格也可以读到一个字符数组中。

字符数组的传递

自定义的函数必须写在main函数的上面

/*
在传递整型数组时不光要传递数组名,同时还要传递数组长度。而字符数组在传递时,只需传递数组名即可,
不用传递数组长度。因为字符数组最后一个是 '\0',C语言规定字符串的结束标志为'\0',所以当扫描到'\0'时
就知道应该结束了,可以以此来作为循环结束的判断条件。
*/
//我们把d称为形参
void print(char d[]) {int i = 0;/*由于\0在ASCII码表中对应的编码就是0,所以循环判断条件也可以简写为while (d[i]!=0);又C语言中一切非0值都是真,0为假,所以可以再进一步简写为while (d[i]);*/while (d[i]!='0'){printf("%c", d[i]);i++;}printf("\n");
}int main() {//初始化字符数组时,一定要让字符数组的大小比看到的字符串的长度多1char c[10] = "hello";print(c);//我们把c称为实参,调用print函数时,是d=c (本质上就是赋值)
}

在这里插入图片描述

同整型数组一样,同样可以在子函数中修改字符数组元素。如下:

void print(char d[]) {int i = 0;while (d[i]!='\0'){printf("%c", d[i]);i++;}printf("\n");//在子函数中修改字符数组元素。修改字符数组中的字符串的内容,把首字母变大写。d[0] = d[0] - 32;//A:65  a:97   大写字母与小写字母的差是32
}int main() {//初始化字符数组时,一定要让字符数组的大小比看到的字符串的长度多1char c[10] = "hello";print(c);printf("%s\n", c);
}

gets函数

gets函数只能读取字符串

使用scanf读取字符串会遇到一个问题,scanf通过%s读取字符串时,当遇到空格以后,就会匹配结束,这样没办法把一行带有空格的字符串存入到一个字符数组中。这个问题可以用gets解决。

gets函数的格式如下:

//char *str类型是字符指针
char *gets(char *str);

gets函数从标准输入中读取字符并把它们加载到str(字符串)中,直到遇到换行符(\n)或到达EOF。【所以gets可以一次读一行,空格也能读入】

输入“how are you”,共11个字符,可以看到gets会读取空格,同时可以看到我们并未给数组进行初始化赋值,但是最后有’\0’(因为字符串的结束标志是\0,只有遇到\0才会停止输出),这是因为gets遇到\n后不会存储\n,而是将其翻译为空字符’\0’。

在这里插入图片描述

gets读一个字符就将其填到字符数组中,当读到\n时不会将其填到字符数组中,当读到\n就会停止匹配,同时gets会给字符数组填结束符\0,所以可以理解为将\n翻译为了\0。

在这里插入图片描述

字符数组的数组名存的就是字符数组的起始地址,类型就是字符指针。而数组的起始地址就是第一个元素的地址,即有&c[0]==c。如下图:

在这里插入图片描述

好好理解下面这段话

char c[20]; c是一个字符数组,但是编译器给c内部存了一个值,c里面存的值的类型是字符指针。

我们在定义其他变量时如整型变量i、浮点型变量f、字符型变量,我们拿这些变量的值时直接拿这个变量名即可,如直接访问i。但在定义数组时如char c[20],拿数组里的每一个元素时不会再去访问数组名c,而只会去访问c[0]-c[19],这时候编译器就会把数组名c中填一个固定的值。

int main() {char c[20];//字符数组的数组名里存的就是字符数组的起始地址,类型就是字符指针gets(c);/*函数调用是值传递,是把c里存的值传给gets,c里的值类型是字符指针,符合gets函数的格式*/puts(c);
}

puts函数

puts只能输出字符串,printf可以输出所有类型如整型、浮点型、字符型、字符串等。

puts函数的格式:

int puts(char *str);

str系列字符串操作函数

初试中如果不考字符串的操作,则一般用不到str函数;但如果初试中考了字符串的操作,则用到str函数的概率非常高。需要指出的是过去只有一年在初试科目中考察了字符串处理。但str函数在机试中很重要。

str系列字符串操作函数主要包括strlen、strcpy、strcmp、strcat等(可以查询C/C++函数大全)。strlen函数用于统计字符串长度,strcpy函数用于将某个字符串复制到字符数组中,strcmp函数用于比较两个字符串的大小【两个字符串比较,是比较对应字符位置的ASCII码。(从前往后依次逐个对比字符的ASCII码值)。】;strcat函数用于将两个字符串连接到一起。各个函数的具体格式如下所示:[注:当有const修饰表示此处可放字符串常量]

#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);

size_t就是int类型,当不知道是什么类型时可以用如下操作:

在这里插入图片描述

对于传参类型char*,直接放入字符数组的数组名即可。

注意使用str系列函数需要使用#include <string.h>头文件

//strlen函数是得到字符数组里字符串的长度。
int main() {int a,b;char c[20] = "wangdao";a = sizeof(c);//使用这种方法得到的是字符数组的长度,输出结果a=20。printf("%d\n", a);b = strlen(c);//使用这种方法得到的是字符数组里面字符串的长度,输出结果b=7。printf("%d\n", b);
}

练习使用str系列函数:

int main() {/*strlen函数是得到字符数组里字符串的长度,同时字符数组里的结束符\0不计入总长度内*/char c[20] = "wangdao";printf("数组c内字符串的长度=%d\n", strlen(c));char d[20];strcpy(d, c);//strcpy是把一个字符串复制给另一个字符串,d赋给c/*strcpy的格式如下:char *strcpy(char *to,const char *from);当有const修饰表示此处可放字符串常量如放置字符串常量的例子:strcpy(d, "study");*/puts(d);/*strcmp:比较两个字符串的大小。格式:int strcmp(const char *str1,const char *str2);两个地方都有const修饰说明两个地方都能放字符串常量str1 > str2 返回值为1;str1 < str2 返回值为-1;str1 = str2 返回值为0两个字符串比较,是比较对应字符位置的ASCII码。(从前往后依次逐个对比字符的ASCII码值)。如比较"how"与"hello",先对比第一个字符,相等;再对比第二个字符,o的ASCII码大于e的ASCII码,所以how>hello*/int ret = strcmp("how", "hello");printf("两个字符串比较后的结果=%d\n",ret);/*strcat:拼接两个字符串。格式char *strcat(char *str1,const char *str2);strcat实现拼接的原理是将后面的填入前面的字符数组中。因此目标数组要能够容纳拼接后的字符串(还应包括一个结束符)*/strcat(c, "study");puts(c);
}

输出结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_325657.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SSH连接vmware 虚拟机 centos

检查虚拟机设置的网络连接是否为NAT模式 点击左上角“编辑” -> “虚拟网络编辑器” 在虚拟网络编辑器中查看IP地址 &#xff0c;点击NAT模式后&#xff0c;点击“NAT设置 记住自己的网关,下面在服务器中配置需要 进入服务器的 /etc/sysconfig/network-scripts/ 编辑 i…

浑元太极马老师和小薇-UMLChina建模知识竞赛第4赛季第7轮[更新]

DDD领域驱动设计批评文集 欢迎加入“软件方法建模师”群 《软件方法》各章合集 参考潘加宇在《软件方法》和UMLChina公众号文章中发表的内容作答。在本文下留言回答。 第7轮一直无人得分&#xff0c;再次更换题目。 因有的题目之前已经出过&#xff0c;本轮需要最先答对全…

Android View 事件派发流程

原文链接 Android View 事件派发流程 自从乔帮主横空出世推出了iPhone以来&#xff0c;触控式的操作便成了21世纪智能设备的标准输入方式。对于同是智能操作系统的Android来说&#xff0c;也不例外。事件&#xff0c;特别是触控事件对于移动应用程序开发来说是一个非常重要的&…

软件DevOps云化发展的趋势 【课程限时免费】

你了解什么是DevOps吗&#xff1f; 它是怎么诞生的&#xff1f; DevOps能做些什么&#xff1f; 相信对于DevOps的实践者和关注者来说&#xff0c;对它已经不陌生了&#xff0c;但是对于刚刚进入开发者领域不久的小伙伴应该并不清楚&#xff0c;下面就让小智带你一起了解DevO…

C. Insert Zero and Invert Prefix - 构造+思维

分析&#xff1a; 数组b的最后一个元素永远不可能使1&#xff0c;因为即使在最后一个位置操作&#xff0c;也只会把前n-1个元素反转&#xff0c;最后一个元素只能为0.然后可以发现只要a[i]0就可以直接输出0&#xff0c;当a[i]1时一连串的1只需要最后一个1的位置改变成1的字串长…

Keil5中写的软件延时函数不起作用现象解析_ARM_Compiler_volatile关键字

一、问题描述 在学习野火霸天虎F407寄存器点亮LED时&#xff0c;出现实验现象&#xff1a;LED灯不亮&#xff0c;野火霸天虎F407资料。 main.c代码如下&#xff1a; #include "stm32f4xx.h"void Delay(unsigned int count);int main(void) { #if 0/* 第一步&a…

oracle rowscn 简单记录

可以通过ROWSCN 侦测row是否有变化&#xff0c;但需要注意&#xff1a; 默认是一个block的scn 相同可以通过create table ROWDEPENDENCIES 在每行上记录无论哪种模式&#xff0c;ROW SCN是一个大致值&#xff0c;不是准确值 NOROWDEPENDENCIES | ROWDEPENDENCIES This claus…

Maven安装和配置详细教程

Maven安装和配置详细教程 1、Maven简介 Maven 是 Apache 软件基金会的一个开源项目,是一个优秀的项目构建工具,它用来帮助开发者管理项目中的 jar,以及 jar 之间的依赖关系、完成项目的编译、测试、打包和发布等工作。 2、Maven下载 点击Maven下载官方地址下载Maven。或者去…

C#与C++编程环境对比:优点与应用场景详解

C#与C是两种常用的编程语言&#xff0c;它们在编程环境方面有一些相同点和不同点。首先&#xff0c;它们都可以用于开发跨平台的应用程序。其次&#xff0c;它们都具有强大的面向对象编程能力。但是&#xff0c;它们在语法、性能和应用领域等方面存在一些不同点 。 在语法方面…

使用Wireshark 找出 TCP 吞吐瓶颈

Debug 网络质量的时候&#xff0c;我们一般会关注两个因素&#xff1a;延迟和吞吐量&#xff08;带宽&#xff09;。延迟比较好验证&#xff0c;Ping 一下或者 mtr[1] 一下就能看出来。这篇文章分享一个 debug 吞吐量的办法。 看重吞吐量的场景一般是所谓的长肥管道(Long Fat …

【C】数据在内存中的存储

前言 > 在内存中&#xff0c;整型和浮点型存储的方式是不同的&#xff0c;从内存中读取的方式也是有所差异的&#xff0c;这篇文章主要介绍整型和浮点型在内存中存储的方式。 整型在内存中的存储 计算机中有符号数有3种表示方式&#xff1a; 原码&#xff1a;直接将二进制按…

GO语言包相关总结 -引用(本地和远程),自定义,安装,使用

本篇文章总结以下go语言包相关的知识。 目录 一.导入包 &#xff08;1&#xff09;常规导入 &#xff08;2&#xff09;别名导入 &#xff08;3&#xff09;特殊导入 二.自定义包 三.安装自定义包 四.调用自定义包调用 五.获取远程包 六.go中的保留函数 七.实战 - G…

机器学习技术(二)——Python科学运算模块(Numpy、Pandas)

机器学习技术&#xff08;二&#xff09;——Python科学运算模块&#xff08;Numpy、Pandas&#xff09; 文章目录 机器学习技术&#xff08;二&#xff09;——Python科学运算模块&#xff08;Numpy、Pandas&#xff09;一、Numpy1、介绍、安装与导入2、Numpy常用操作 二、Pan…

mybatis多参数传递报错问题分析+硬核mybatis底层源码分析+@Param注解+图文实战环境分析【4500字详解打通,没有比这更详细的了!】

文章目录 1.问题描述2.问题场景模拟再现2.1 场景环境2.2 数据库与表创建2.3 Maven环境搭建&#x1f340; pom.xml导入依赖&#x1f340; jdbc.properties&#x1f340; mybatis-config.xml&#x1f340; User实体类&#x1f340; Mapper 接口&#x1f340; UserMapper.xml 映射…

IT-OT 安全融合是优化风险管理的关键

最新报告揭示了运营技术检测和响应方面的显着可见性差距。 全球网络安全运营商趋势科技宣布了一项新研究&#xff0c;显示企业安全运营中心 (SOC) 正在将其能力扩展到 OT 领域。 然而&#xff0c;重大的可见性和技能相关的挑战仍然造成障碍。 研究发现&#xff0c;一半的组织…

决策树ID3

文章目录 题目一基础知识解题过程①算总的信息量②求解各个指标的信息增益&#xff0c;以此比较得出根节点③ 从根节点下的晴天节点出发循环上述步骤④ 从根节点下的多云节点出发&#xff0c;循环上述步骤⑤ 从根节点下的雨节点出发&#xff0c;循环上述步骤⑥画出最终的决策树…

4.设计模式之后七种模式后11种模式命令访问者迭代器发布订阅中介者忘备录解释器状态策略职责链和空模式

1.命令(command)模式 不知道命令接收者(对象)是谁,支持撤销 (接受者 间接调用执行 的具体行为) 命令调用者和接收者解耦 //只要实现命令接口即可 (就是客户端给个命令,然后命令类传给接收类执行) 优点和缺点 容易撤销操作 命令队列可以多线程操作 增加过多的命令类 空命令也是一…

揭秘元宇宙背后的最炫科技风

&#xff1a;元宇宙&#xff0c;这个词汇在近年来越来越被人们所熟知。它是一个虚拟的世界&#xff0c;由数字化的现实世界和虚拟现实技术所构成。在元宇宙中&#xff0c;人们可以自由地探索、交互、创造和享受各种虚拟体验。而这一切&#xff0c;都离不开最炫科技风的支持。 …

道路车辆功能安全第2 部分:功能安全管理

道路车辆功能安全 第2 部分&#xff1a;功能安全管理 1 范围 GB/T 34590的本部分规定了应用于汽车领域的功能安全管理的要求&#xff0c;包括&#xff1a; ——独立于项目的关于所涉及组织的要求&#xff08;整体安全管理&#xff09;&#xff1b;及 ——项目特定的在安全生命周…

Docker常见问题集合

一、Docker安装 1、yum 安装 1&#xff09;更新yum包到最新 yum update2&#xff09;安装软件需要的软件&#xff0c;yum-util&#xff08;提供 yum-config-manager 功能&#xff09;&#xff0c;device-mapper-persistent-data、lvm2&#xff08;devicemapper 驱动依赖&…