C语言入门篇——数组篇

news2024/11/14 13:37:47

目录

1、数组

2、一维数组的创建和初始化

2.1数组的创建方式:

2.2数组的初始化

2.3一维数组的使用

​2.4一维数组在内存中的存储

3、二维数组的创建和初始化

3.1二维数组的创建

3.2二维数组的初始化

3.3二维数组的使用

3.4二维数组在内存中的存储

4、数组越界

4.1数组下标取值越界

4.2指向数组的指针的指向范围越界

5、数组作为函数参数

5.1数组名


1、数组

数组是由数据类型相同的一些列类型元素组成,需要使用数组时,通过声明数组告诉编译器数组中内含多少元素和这些元素的类型。编译器根据这些信息正确地创建数组。普通变量可以使用的类型,数组元素都可以用。要访问数组中的元素,通过使用数组下标数(也称为索引)表示数组中的各元素。数组元素的编号从0开始。

2、一维数组的创建和初始化

2.1数组的创建方式:

type_t arr_name [const_n];
数组类型 数组名字[数组大小];
数组类型 数组名字[数组大小] = { 初始化值1,初始化值2,...,初始化值N};

名词解释:

type_t:数组的元素类型

arr_name:数组名字

const_n:常量表达式,用来指定数组的大小

数组创建,在C99标准之前,[]中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念(后面再介绍)

2.2数组的初始化

数组常用来存储程序需要的数据,在这种情况下,在程序一开始就初始化数组比较好。

数组化的初始化是指:在创建数组的同时给数组的内容一些合理初始值(初始化)。

int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };

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

int arr3[10] = { 1,2,3,4,5};

char arr4[10] = { 'h','e','l','l','o' };

char arr5[] = { 'h','i' };

char arr6[] = "helloworld" ;

上面这一些初始化都是成立的,那数组对应的大小是多少?通过代码案例来直接查看:

int main(void)
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[] = { 1,2,3,4,5 };
	int arr3[10] = { 1,2,3,4,5 };
	char arr4[10] = { 'h','e','l','l','o' };	
	char arr5[] = { 'h','i' };
	char arr6[] = "helloworld";

	printf("arr1的长度为:%d\n", sizeof(arr1) / sizeof(int));
	printf("arr2的长度为:%d\n", sizeof(arr2) / sizeof(int));
	printf("arr3的长度为:%d\n", sizeof(arr3) / sizeof(int));
	printf("arr4的长度为:%d\n", sizeof(arr4) / sizeof(char));
	printf("arr5的长度为:%d\n", sizeof(arr5) / sizeof(char));
	printf("arr6的长度为:%d\n", sizeof(arr6) / sizeof(char));

	return 0;
}

总结:

  1. 当创建数组的时候有初始化数组的大小,整个数组的长度就为数组下标引用符里面的值
  2. 当创建数组的时候没有初始化数组的大小,但有给数组一些合理初始值,初始值的个数就是数组的大小
  3. 当创建数组的时候有初始化数组的大小,但给数组的合理初始值个数少于数组大小时,系统给数组其他没初始化元素补0

2.3一维数组的使用

在操作符篇中((1条消息) C语言入门篇——操作符篇_sakura0908的博客-CSDN博客)详细介绍了下标引用操作符,它是数组访问的操作符,这里不多加介绍。

需要记住的是,数组的首元素的下标是从0开始,而不是数学意义上的第一个(1)。

通过sizeof(数组名)/sizeof(数组元素类型)可以计算数组的元素个数。

int main(void)
{
    int arr[10] = { 0 };//数组的不完全初始化
    //计算数组的元素个数
    int sz = sizeof(arr) / sizeof(arr[0]);

    //对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
    for (int i = 0; i < 10; i++)
    {
        arr[i] = i;
    }
    //输出数组的内容
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

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

那创建的数组在内存中的存储会是怎么样呢?是连续的一块内存空间存放,还是零零散散的内存空间存放,通过取地址符&访问数组每一个元素的地址就知道答案了:

int main()
{
    int arr[10] = { 0 };
    int sz = sizeof(arr) / sizeof(arr[0]);

    for (int i = 0; i < sz; ++i)
    {
        printf("&arr[%d] = %p\n", i, &arr[i]);
    }
    return 0;
}

通过运行效果可以看到每个数组元素的地址是连续的,随着数组下标的增长,数组元素的地址,也是有规律的递增,由此可以得知结论:数组在内存中是连续存放的

3、二维数组的创建和初始化

怎么理解二维数组,一般有两种理解,第一种把它看成是行和列的元素组合,第二种把它看成是数组元素也是一个一维数组。两种理解方式都是可以的,看自己更能接受哪一种。通过下面图解更好地理解它:

3.1二维数组的创建

二维数组和一维数组的创建时类似的:

int arr1[5][5];

char arr2[5][5];

double arr3[5][5];

3.2二维数组的初始化

二维数组的初始化和一维数组的初始化有点类似,但也有着不同。

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

int arr[5][5] = {{1,2},{4,5}};

int arr[][5] = {{2,3},{4,5}};

记住:二维数组如果有初始化,行可以省略,列不能省略

3.3二维数组的使用

二维数组也是数组,所以也是使用下标引用操作符来使用二维数组。通过for嵌套循环给二维数组赋值和打印。

int main()
{
	int arr[3][4] = { 0 };
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			arr[i][j] = i * 4 + j;
		}
	}
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

3.4二维数组在内存中的存储

一维数组在内存是连续存放的,那二维数组呢?

int main()
{
	int arr[3][4] = { 0 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
		}
	}
	return 0;
}

可以看到二维数组在内存中确实也是连续存储的,如下图图解:

4、数组越界

所谓的数组越界,简单地讲就是指数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围之外,这类错误也是 C 语言程序中最常见的错误之一。

在 C 语言中,数组必须是静态的。换而言之,数组的大小必须在程序运行前就确定下来。由于 C 语言并不具有类似 Java 等语言中现有的静态分析工具的功能,可以对程序中数组下标取值范围进行严格检查,一旦发现数组上溢或下溢,都会因抛出异常而终止程序。也就是说,C 语言并不检验数组边界,数组的两端都有可能越界,从而使其他变量的数据甚至程序代码被破坏。

一般情况下,数组的越界错误主要包括两种:数组下标取值越界与指向数组的指针的指向范围越界。

4.1数组下标取值越界

数组的下标是有范围限制的。 数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。 所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。 C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的, 所以程序员写代码时,最好自己做越界的检查。

这里的-858993460是什么东西?

十进制数字-858993460转换为二进制数字之后为:1100 1100 1100 1100 1100 1100 1100 1100,二进制转换为十六进制数字之后为:0xCCCCCCCC。

给函数分配栈空间的时候,其中的数据有可能是别的函数使用过的,或者是垃圾数据,所以在使用这段栈空间之前,会先将这段栈空间全部用CC填充,0xCC在X86指令集中对应的汇编是int3。

int(interrupt)是中断,3是中断码,根据中断码进行相应操作,int3起到一个断点的作用,IDE的断点调试就是使用了int3指令,从而不会往下继续执行。

假设 jmp、jz 等跳转语句后面跟的地址值给错了,指向了函数的栈空间,当跳转到函数的栈空间时,如果之前的数据是一些敏感操作,这样就会很危险,但是填充了CC后,程序就会停下来,不会再执行。

这样程序出现内存越界时,调试器可以捕捉这个异常,而在Release下默认内存清零。

而且汉字“烫”的编码也是CC,所以有时候还可能看到很多“烫烫烫烫烫烫烫”。。。

4.2指向数组的指针的指向范围越界

指向数组的指针的指向范围越界是指定义数组时会返回一个指向第一个变量的头指针,对这个指针进行加减运算可以向前或向后移动这个指针,进而访问数组中所有的变量。但在移动指针时,如果不注意移动的次数和位置,会使指针指向数组以外的位置,导致数组发生越界错误。下面的示例代码就是移动指针时没有考虑到移动的次数和数组的范围,从而使程序访问了数组以外的存储单元.

int main(void)
{
    int i;
    int* p;
    int a[5];

    //数组a的头指针赋值给指针p
    p = a;
    for (i = 0; i < 10; i++)
    {
        //指针p指向的变量
        *p = i + 10;
        //指针p下一个变量
        p++;
    }
}

 for 循环会使指针 p 向后移动 10 次,并且每次向指针指向的单元赋值。但是,这里数组 a 的下标取值范围是 [0,4](即 a[0]、a[1]、a[2]、a[3] 与 a[4])。因此,后 5 次的操作会对未知的内存区域赋值,而这种向内存未知区域赋值的操作会使系统发生错误。

5、数组作为函数参数

在实现具体的功能函数的时候,常常会将数组作为参数传入函数,但是初学者可能会出错,例如,当我们编写冒泡排序算法时,就需要传入数组然后进行排序,有的人也许就会写出下面的代码:

void bubble_sort(int arr[])
{
    int sz = sizeof(arr) / sizeof(arr[0]);
    for (int i = 0; i < sz - 1; i++)
    {
        int j = 0;
        for (j = 0; j < sz - i - 1; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
            }
        }
    }
}
int main()
{
    int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
    bubble_sort(arr);
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

运行发现当我们进行了冒泡排序之后的数组元素排序和原数组元素排序是一样的,这是为什么呢?

在我们VS2022的编译软件里面,系统对下面这行代码进行了警告:

    int sz = sizeof(arr) / sizeof(arr[0]);

 

 当我们对求出来的sz值进行打印的时候,发现的sz的值为1????这就是一个非常奇怪的地方了,之前介绍过,sizeof(数组名字)/sizeof(数组元素类型)的求值应该是数组元素的个数,那为什么sz的值为1呢?这里就需要我们了解数组名这个概念了。

5.1数组名

一般情况下,C语言中数组名在表达式中被解读为指向数组首元素的指针

C语言中数组名在表达式中被解读为指向数组首元素的指针, 即数组名在表达式中值为数组首元素的地址。但是也有着几种特殊情况:

  1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数 组。
  2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

除此这两种情况之外,所有的数组名都表示数组首元素的地址。

最后附上数组冒泡排序的设计代码:

void bubble_sort(int arr[],int sz)
{
    for (int i = 0; i < sz - 1; i++)
    {
        for (int j = 0; j < sz - i - 1; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
            }
        }
    }
}
int main()
{
    int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr,sz);
    for (int i = 0; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot中一个注解优雅实现重试Retry框架

目录: 1、简介2、实现步骤 1、简介 重试&#xff0c;在项目需求中是非常常见的&#xff0c;例如遇到网络波动等&#xff0c;要求某个接口或者是方法可以最多/最少调用几次&#xff1b;实现重试机制&#xff0c;非得用Retry这个重试框架吗&#xff1f;那肯定不是&#xff0c;相信…

【云计算•云原生】2.云计算环境下的新趋势—云原生

文章目录 1.什么是云原生2.云原生概述2.1 微服务2.2 容器云2.3 serverless无服务器2.4 DevOps2.5 持续集成和持续交付2.6 openStack 1.什么是云原生 按照自己的理解&#xff0c;可以将云原生拆分成云原生&#xff0c;云就是上一节中的云计算的云&#xff1b;原生即为诞生的环境…

Visual Studio C# WinForm开发入门(3):各种控件介绍

1、窗体 窗口就是打开程序我们所面对的一个面板&#xff0c;里面可以添加各种控件&#xff0c;如下图所示&#xff0c;我们可以在属性栏设置其标题名称、图标、大小等。 双击标题框&#xff0c;会生成Load函数&#xff0c;也可以到事件里面去找 Load函数是窗口生成后需要…

Spring Doc OpenAPI3.0 抛弃SpringFox拥抱SpringDoc

Spring Doc 1 简介 SpringDoc是SpringBoot 的API文档工具。官网&#xff1a;https://springdoc.org/ 在使用SpringBoot 2.6以前去创建API文档工具一般会采用SpringFox提供的Swagger库&#xff0c;但是由于SpringBoot版本的不断升级和SpringFox摆烂不更新&#xff0c;导致了S…

springboot项目需要读取非application.yml/properties 的配置文件

目录&#xff1a; 1、操作步骤2、总结3、扩展4、第二种方法获取配置文件bean 1、操作步骤 1.新建配置文件&#xff1a; 2.编辑配置文件&#xff1a; test-serverrd-dev02.jr.rong360.com3.新建Config类&#xff1a; Component PropertySource(value "kirara.properti…

销量破亿,董洁直播间凭何出圈?

近期&#xff0c;“没有五位数走不出”的董洁直播间火了…… 纵观这几年各大平台直播带货&#xff0c;火已不是什么新鲜事&#xff0c;而为何董洁的直播能火上热搜呢&#xff1f;本期&#xff0c;千瓜将解析董洁直播&#xff0c;同品牌方聊聊小红书直播的那些事儿。董洁「种草式…

Win10分辨率怎么看?2种必须学会的方法!

案例&#xff1a;win10分辨率 【为了方便办公&#xff0c;最近我的电脑连接了2个显示屏&#xff0c;但感觉电脑显示怪怪的&#xff0c;可能是分辨率设置不对&#xff0c;大家知道应该怎么查看电脑的分辨率吗&#xff1f;感谢感谢&#xff01;】 我们的win10系统支持多种分辨率…

ChatGPT的未来:人工智能技术的新发展趋势

第一章&#xff1a;人工智能技术的新发展趋势 近年来&#xff0c;随着人工智能技术的不断发展和应用&#xff0c;ChatGPT这样的大型自然语言处理模型已经成为人工智能技术的重要组成部分。未来&#xff0c;人工智能技术的发展将更加快速&#xff0c;我们可以看到以下几个方面的…

制造型企业为何需要MES管理系统,企业怎样选择合适的MES

MES管理系统是专门针对制造型企业而设计的&#xff0c;能实现对生产车间、工厂信息化管理&#xff0c;帮助制造型企业提高生产效率&#xff0c;加快数字化转型。目前针对制造型企业生产效率、企业竞争力和生产管理状况的需求&#xff0c;MES管理系统已经成为实现生产经营目标的…

MySQL创建用户并赋权限

MySQL创建用户并赋权限 省流1.创建mysql用户1.1 新建用户1.2 查询用户信息 2. 授权用户2.1 指定数据库和表赋权2.2 赋予全部权限2.3 查看用户权限2.4 回收用户权限 3. 修改用户密码4. 删除用户5. 刷新权限(务必执行) 省流 如果只是希望新建一个用户并且赋予全部执行权限&#…

android react native报错

1.报错图片 解决方案&#xff1a; android下的build.gradle文件 修改 如图 报错 E:/androidData/caches/transforms-2/files-2.1/399126eae79af6235d7a4ae871926a31/jetified-kotlin-stdlib-1.6.10.jar!/META-INF/kotlin-stdlib.kotlin_module: Module was compiled with an i…

华为云 HCIP云迁移 学习课程提供的考试样题提交之后没有反馈正确答案的问题

最近在考HCIP的云迁移&#xff0c;但是他提供的考试样题昨晚发现没有正确答案&#xff0c;只会告诉你对错&#xff0c;判断题还好解决&#xff0c;但是多选题就麻烦了。这边研究了一下&#xff0c;share一下&#xff0c;方便大家学习和验证自己的学习成果 这边去看了他的 api r…

杰理-OTA升级电量限制

杰理-OTA升级电量限制 获取升级异常状态标志位&#xff08;升级过程中断开重新连接&#xff0c;不做电量限制&#xff09;

【观察】华为:运力算力存力“协同”,推动数字生产力“跃升”

可以看到&#xff0c;过去几年数字化转型已经席卷全球&#xff0c;随着新技术的广泛应用&#xff0c;新的机会和价值正在不断被发现和创造。从某种程度上说&#xff0c;数字化转型不再是“可选项”&#xff0c;而变成了“必选项”。 确实如此&#xff0c;目前已经有超过170多个…

基于JS简单甘特图(IT枫斗者)

基于JS简单甘特图 基于JS简单甘特图 先来看一下效果吧&#xff0c;这里的需求是从早上的5点为开始时间&#xff0c;到第二天到凌晨5点 前期准备 其实网上有很多甘特图的实现方式&#xff0c;但是他们都只能具象到天&#xff0c;不能具体到某个时间点&#xff0c;而且每一个…

ESD/EMI防护设计

内容摘取自<Rockchip_RK3568_Hardware_Design_Guide_V1.0_CN.pdf> 1.1概述 本章对于RK3568产品设计中的ESD/EMI防护设计给出了建议&#xff0c;帮助客户更好的提高产品的抗静电、抗电 磁干扰水平。 1.2 术语解释 本章中的术语解释如下&#xff1a;  ESD&#xff08;E…

直播预告丨打破 Python 束缚:Level 2 因子的脚本优化实践

有人说&#xff0c;DolphinDB 是一个时序数据库&#xff1b; 也有人说&#xff0c;DolphinDB 就是 Python 加数据库的结合&#xff1b;还有人说&#xff0c;DolphinDB 是一个支持流数据处理的实时计算软件…… 我们经常会听到类似的理解&#xff0c;其实很多小伙伴都会有好奇…

Python爱心表白,快去发给你心仪的人叭~

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,YOLO,活动领域博主爱笑的男孩。擅长深度学习,YOLO,活动,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typecollect个人…

Hive ---- Hive入门

Hive ---- Hive入门 1. 什么是Hive1. Hive简介2. Hive本质 2. Hive架构原理1. 用户接口&#xff1a;Client2. 元数据&#xff1a;Metastore3. 驱动器&#xff1a;Driver4. Hadoop 1. 什么是Hive 1. Hive简介 Hive是由Facebook开源&#xff0c;基于Hadoop的一个数据仓库工具&a…

关于 mysql本地使用ODBC连接突然无法连接上且无法搜索到database的 解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/130360385 红胖子网络科技的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…