C语言学习 五、一维数组与字符数组

5.1一维数组

5.1.1数组的定义

数组特点:

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

C语言为了方便操作这些数据,提供了一种构造数据类型——数组,数组是指一组具有相同数据类型的数据的有序集合。

一维数组的定义格式为

数据类型 数组名[常量表达式];

例如:

int a[10]; //定义一个整型数组,数组名为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]; //不能用变量说明数组大小

 

5.2一维数组在内存中的存储

一维数组初始化方法:

(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)可以只给一部分元素赋值,例如:只给前5个元素赋初值,后5个元素值为0

int a =[10] = {0,1,2,3,4};

(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};

 

 5.3数组的访问越界

5.3.1访问越界例子

【访问越界演示】

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5}; //定义数组
    int j = 20;
    int i = 10;
    arr[5] = 6; //访问越界
    arr[6] = 7;
    printf("i=%d\n", i); //i=7 i并没有赋值,但是值却变化了
    return 0;
}

【运行结果】

 5.3.2查看内存视图

在内存视图依次输入&arr,&j,&i 来查看整型数组arr,整型变量j,整型变量i的地址。

 

 

 5.3.3总结
  • 访问越界是很危险的,C语言并没有对访问越界进行检查
  • CLion当中的地址都是8字节64位的,考研当中给的大多数为4个字节,即Windows32位控制台应用程序为0x00 00 00 00 到 0xFF FF FF FF,总计为2的32次方,大小为4G。
  • 数组注意点:编译器并不检查程序对数组下标的引用是否在数组的合法范围内:

好处:不用浪费时间对有些已知正确的数组下标进行检查

坏处:无法检测出无效的下标引用

一个良好的经验法则:

  • 如果下标值是通过那些已知正确的值计算得来则无需检查
  • 如果下标值是由用户输入产生,那么使用它们之前必须进行检查,以确保在有效范围内

 

5.4数组的传递

【数组传递反例】

#include <stdio.h>

//一维数组传递
//子函数是把一个常用的功能封装起来
//数组名传递到子函数后弱化成指针(8字节),子函数的形参接收到的是数组的起始地址,因此不能把数组的长度传递给子函数
void print(int a[]) {
    //数组传递不需要写数字,因为数组长度传递不过来
    int i;
    for (int i = 0; i < sizeof(a) / sizeof(int); i++) {
        //sizeof(a)/sizeof(int)
        //数组整个的长度/int的长度 即20个字节/int 4个字节 = 5
        printf("%d\n", a[i]);
    }
}

//main函数就是主函数
int main() {
    int a[5] = {1, 2, 3, 4, 5};
    print(a); //调用子函数
    return 0;
}

【运行效果】

 【单步调试】

【正确的数组传递例子】

#include <stdio.h>

//一维数组传递
//子函数是把一个常用的功能封装起来
//数组名传递到子函数后弱化成指针(8字节),子函数的形参接收到的是数组的起始地址,因此不能把数组的长度传递给子函数
void print(int b[], int length) { //多定义一个变量length作为数组的长度
    //数组传递不需要写数字,因为数组长度传递不过来
    int i;
    for (int i = 0; i < length; i++) {
        printf("%3d", b[i]);
    }
    printf("\n");//换行
    b[4] = 10;
}

//main函数就是主函数
int main() {
    int a[5] = {1, 2, 3, 4, 5};
    print(a, 5); //调用子函数 
    printf("b[4]=%d\n",a[4]); //发现b[4]值发生改变
    return 0;
}

【运行效果】

总结:

  • 在调用函数时,一维数组的长度传递不过去,所以通过length来传递数组中的元素个数。
  • 实际数组名中存储的数组的首地址,在调用函数传递时,是将数组的首地址赋给了变量b。
  • 在b[ ]的方括号中填写任何数字是没有意义的,因为不能将数组长度传递给子函数。
  • 此时在print函数内修改元素b[4]=10可以看到数组b的起始地址和main函数中数组a的起始地址相同,即二者在内存中位于同一位置,当函数执行结束时数组a中元素a[4]就得到了修改。

 

5.5字符数组与scanf读取字符串

5.5.1字符数组初始化及传递

字符数组的定义方法与前面的5.5.1一维数组类似,例如:

char c[10]; //定义一个长度为10的字符数组c

字符数组的初始化方式

(1)对每个字符单独赋值进行初始化

c[0] = '1';c[1] = ' ';c[2] = 'a'; c[3] = 'm';c[4] = ' ';c[5] = 'h';c[6] = 'a'; //初始化速度慢

(2)对整个数组进行初始化

char c[10] = {'1','a','m','h','a','p','y'}; //初始化速度慢

 (3)常用初始化形式:会自动将字符串里的每个字符都放入数组c里面

char c[10] = "Iamhappy"; //编写速度更快

char a[6] = "hello";

【内存视图】

 注意:

  • C语言规定字符串的结束标志是 '\0' ,而系统会对字符串常量自动加一个 '\0' 。
  • 为保证出力方法一致,一般人会人为在字符数组中添加  '\0' ,所以字符数组中存储的字符串长度必须比字符数组少1个字节,例如char c[10]最长存储9个字符,剩余的一个字符用来存储  '\0'

 【字符数组初始化及传递的正确例子

#include <stdio.h>

int main() {
    char c[10] = "Iamhappy";
    printf("%s\n", c);//使用%s来输出一个字符串,直接吧字符数组名放在printf后面
    //%s内部其实也有一个循环,能将字符数组输出
    return 0;
}

【运行效果】

  【字符数组初始化及传递的错误例子

#include <stdio.h>

int main() {
    //若字符串长度超过字符数组长度则会输出乱码
    char c[5] = "hello";
    //正确写法是 char c[6] = "hello";
    //输出字符串乱码时,要去查看字符数组中是否存储了结束符'\0'
    printf("%s\n", c);//使用%s来输出一个字符串,直接吧字符数组名放在printf后面
    return 0;
}

【运行效果】

【内存视图查看】

【总结】

  • 若字符串长度超过字符数组的长度则会输出乱码
  • 输出字符串乱码时,要去查看字符数组中是否存储了结束符'\0'

【自定义函数print模拟printf("%s\n",c);操作】

#include <stdio.h>

//定义一个print函数模拟printf("%s\n", c);操作
void print(char d[]) {
    int i = 0;
    while (d[i]) { //当走到结束符'\0',时循环结束
        printf("%c", d[i]);
        i++;
    }
    printf("\n"); //换行
    d[0] = 'H';//也可以修改字符数组中某一元素的值
}

int main() {
    //若字符串长度超过字符数组长度则会输出乱码
    char c[6] = "hello";
    char d[5] = "how";
    printf("%s\n", c);//使用%s来输出一个字符串,直接吧字符数组名放在printf后面
    print(d); //调用函数print
    printf("%c\n", d[0]); //d[0]的值已经修改
    return 0;
}

【运行效果】

5.5.2scanf读取字符串

scanf读取字符串时用%s

【scanf读取字符串例子】

#include <stdio.h>

int main() {
    char c[10];
    scanf("%s", c);
    //字符数组名c中存储了数组的起始地址,因此这里不用写取地址&c
    //使用scanf读取字符操作时,会自动往数组中填充一个结束符'\0'
    printf("%s\n", c);
    return 0;
}

【运行效果】

【若数组中已提前填充数据】

#include <stdio.h>

int main() {
    char c[10] = {"1234567"}; //若是提前在c中填充一些数据
    scanf("%s", c);
    //字符数组名c中存储了数组的起始地址,因此这里不用写取地址&c
    //使用scanf读取字符操作时,会自动往数组中填充一个结束符'\0'
    printf("%s\n", c);
    return 0;
}

【运行效果】

【单步调试内存视图:scanf语句运行前】

【单步调试内存视图:scanf语句运行后】

【sacnf读取字符串中带有空格】

【若需要读取空格如何操作】

定义两个字符数组,用scanf同时读取两个字符串

#include <stdio.h>

int main() {
    char c[10];
    char d[10];
    scanf("%s%s", c, d);
    //字符数组名c中存储了数组的起始地址,因此这里不用写取地址&c
    //使用scanf读取字符操作时,会自动往数组中填充一个结束符'\0'
    //scanf使用%s会自动忽略空格和回车(与%d和%f类似)
    printf("c=%s,d=%s\n", c, d);
    return 0;
}

【运行效果】

 

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

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

相关文章

虚拟+现实,刷新线上直播的“打开方式”

近年来&#xff0c;短视频和线上直播大热&#xff0c;成为我们看世界的途径之一&#xff0c;我们渐渐习惯了看屏幕里面的虚拟世界。随着AIGC技术的不断革新&#xff0c;让虚拟直播间的体验感越来越真实&#xff0c;给我们带来了不同寻常的体验。 虚实融合&#xff0c;超越传统…

将ORB-SLAM3用图像增强的方式打开

ORB-SLAM3在复杂光照环境下&#xff0c;特征提取和特征匹配的性能明显下降&#xff0c;其准确性和鲁棒性收到很大影响&#xff0c;尤其是当周围环境获取的ORB特征点数量不足时&#xff0c;位姿的估计过程无法进行&#xff0c;甚至或导致初始化和跟踪失败的情况&#xff0c;目前…

03、Lua 基本语法

Lua 基本语法 Lua 基本语法第一个 Lua 程序交互式编程脚本式编程 注释单行注释多行注释 标示符关键词全局变量 Lua 基本语法 Lua学习起来非常简单&#xff0c;我们可以创建第一个 Lua 程序&#xff01; 第一个 Lua 程序 交互式编程 Lua提供了交互式编程模式。我们可以在命令…

开始喜欢上了runnergo,JMeter out了?

RunnerGo是一款基于Go语言、国产自研的测试平台。它支持高并发、分布式性能测试。和JMeter不一样的是&#xff0c;它采用了B/S架构&#xff0c;更灵活、更方便。而且&#xff0c;除了API测试和性能测试&#xff0c;RunnerGo还加上了UI测试和项目管理等实用功能&#xff0c;让测…

蓝桥杯刷题-串的处理

串的处理 代码 s input().split() l_new [] for i in s:i list(i)new""for j in range(len(i)-1): # 遍历newi[j]if i[j].isdigit() and i[j1].isalpha(): # 在字母和数字之间添加“_”new_if i[j].isalpha() and i[j1].isdigit(): # 同上new_newi[-1]l_new.appe…

K3 计划订单投放时,将“关联物料”传递到采购和生产订单的“组部件”字段

参考K/3 WISE 中MRP计算投放过程中 销售订单自定义字段怎么携带到任务单这篇文章&#xff0c;进行优化。 在表ICMrpDestBills下增加触发器&#xff0c;代码如下 CREATE TRIGGER [dbo].[ICMrpDestBills_update]ON [dbo].[ICMrpDestBills]AFTER INSERT,UPDATE AS BEGINSET NO…

mysql 设置初始密码

link 1.首先输入以下指令&#xff1a; sudo cat /etc/mysql/debian.cnf运行截图如下&#xff1a; 2. 再输入以下指令&#xff1a; mysql -u debian-sys-maint -p//注意! //这条指令的密码输入是输入第一条指令获得的信息中的 password ZCt7QB7d8O3rFKQZ 得来。//请根据自己的实…

【CKA模拟题】如何发布一个SVC资源

题干 For this question, please set this context (In exam, diff cluster name) kubectl config use-context kubernetes-adminkubernetesYou have an existing Nginx pod named nginx-pod . Perform the following steps: Expose the nginx-pod internally within the cl…

Linux系统部署Paperless-Ngx文档管理系统结合内网穿透实现公网访问

文章目录 1. 部署Paperless-ngx2. 本地访问Paperless-ngx3. Linux安装Cpolar4. 配置公网地址5. 远程访问6. 固定Cpolar公网地址7. 固定地址访问 Paperless-ngx是一个开源的文档管理系统&#xff0c;可以将物理文档转换成可搜索的在线档案&#xff0c;从而减少纸张的使用。它内置…

二手车交易网站|基于JSP技术+ Mysql+Java+ B/S结构的二手车交易网站设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;ssm&#xff0c;springboot的平台设计与实现项目系统开发资源&#xff08;可…

一些恶意样本的流量分析学习

Trickbot Trickbot 是一种自 2016 年以来一直在感染受害者的信息窃取者和银行恶意软件。Trickbot通过恶意垃圾邮件&#xff08;malspam&#xff09;分发&#xff0c;也由其他恶意软件&#xff08;如Emotet&#xff0c;IcedID或Ursnif&#xff09;分发。 分析来自恶意垃圾邮件…

Frida 官方手册 中文版 ( 机翻+人翻 )

Frida 英文文档&#xff1a;https://frida.re/docs/home/ Frida 中文文档&#xff1a;https://pypi.org/project/frida-zhongwen-wendang/ 目的&#xff1a;给自己一个认真阅读文档的机会&#xff01;&#xff01;&#xff01; 部分名词找不到合适的中文表达&#xff0c;直接使…

计算机视觉技术:美颜SDK在直播平台的集成与优化

当下&#xff0c;美颜技术在直播平台中的应用变得愈发重要。接下俩&#xff0c;小编将深度讲解计算机视觉技术在美颜SDK集成与优化方面的应用&#xff0c;以提升直播平台的用户体验。 一、美颜技术的发展 传统的美颜功能只是简单地对图像进行柔化处理&#xff0c;而现在的美颜…

你真的会数据结构吗:堆

❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载&#xff0c;请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主&#xff0c;代码兴国&#xff01;❤❤❤ 好久不见&#xff0c;甚是想念&#xff0c;不知道大家有没有察觉到大伟的头像和名字变了鸭 <(*&#xffe…

RK3568驱动指南|第十三篇 输入子系统-第151章 通用事件处理层read和write函数分析

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

Leetcode第26题:删除有序数组中的重复项

代码实现 注意:该题要求原地删除&#xff0c;不能引入额外的连续内存空间 class Solution:def removeDuplicates(self, nums: List[int]) -> int:not_sorted_lengthlen(nums)while(not_sorted_length>0):numnums.pop(0)not_sorted_length-1if num not in nums:nums.appe…

【二十三】【算法分析与设计】三柱汉诺塔详解,计算子移动次数,正常递归计算,观察数据得出数学规律,递归图得出数学规律,将递归函数转化为递推式

目录 汉诺塔递归 汉诺塔子移动次数的计算 牛牛的汉诺塔 选择正常的递归模拟计算子移动次数 根据具体数据得出数学规律 根据递归图得出数学规律 将递归函数转化为递推式 结尾 汉诺塔递归 汉诺塔是一个经典问题&#xff0c;相传在古印度圣庙中&#xff0c;有一种被称为汉…

【框架】说一说 Fork/Join?

SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习Java框架 个性签名&#xff1a;人生乏味啊&#xff0c;我欲令之光怪陆离 本文封面由 凯楠&#x1f4f7; 友情赞助 目录 前言 什么是 Fork&#xff1f; 什么是 Join&#xff1f; Fork/Join 的核心组件 F…

基于K-近邻的PLOSAR图像分类

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

网络原理(6)——IP协议

目录 一、网段划分 现在的网络划分&#xff1a; 1、一般情况下的家庭网络环境 2、IP地址 3、子网掩码 4、网关 以前的网络划分&#xff1a; 二、特殊IP 1、环回 IP 2、主机号为全 0 的IP 3、广播地址IP 三、路由选择&#xff08;路线规划&#xff09; 一、网段划分…