目录

前言:

一、数组越界:

二、数组名:

1.sizeof(数组名):

2.&数组名:

三、数组名作为函数参数:


前言:

上篇文章中我们学习了一维数组与二维数组的相关基础知识,本文我将带领小伙伴们继续向后学习数组的相关知识。废话不多说,我们开始叭!

一、数组越界:

在我们编写程序时,数组越界这个问题可以说是屡见不鲜。所以在这个地方各位小伙伴们一定要认真学习,在今后的代码书写过程序中,为了我们代码更高的安全性和正确性,关于这个问题也应当多加注意。

首先我们要知道,数组的下标是有范围的。数组的下标从零开始,若数组中共有n个元素,则最后一个元素的下标应当为n-1

所以当数组的下标小于0或大于n-1,则超出了数组的合法空间访问,这个时候这种超出数组合法空间访问的情况就称为数组越界访问

同时,C语言本身不会进行数组下标的越界检查,故编译器不一定会报错。但我们应知道,编译器不报错并不意味着程序本身就是正确的。所以我们在编写代码时,应当对各种情况中的数组,自己做好越界检查

一维数组越界错误示例:

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>int main()
{//定义元素总数为10的数组:int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//定义下标:int i = 0;//循环访问数组元素:for (i = 0; i <= 10; i++){printf("arr[%d] = %d\n", i, arr[i]);}//函数返回值return 0;
}

我们把这杜纳简单的代码运行起来看看结果:

很明显在n=10时程序出现了问题,错误原因出在:

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
...
for (i = 0; i <= 10; i++)

在我们的代码中,我们定义的数组arr中的元素最大个数为10,则数组下标应当从零开始,到9为止。但在我们的循环中,由于我们的粗心大意,导致我们的循环进行了11次,下标从零来到了11,这时就造成了数组的访问越界错误的产生。

我们应当注意,在二维数组中,行和列都可能存在数组越界的错误。

二、数组名:

看到这部分的标题,各位小伙伴们心里可能就有疑问了,数组名就是数组名啊,这有什么可研究的?但是事实上,数组名不仅仅是一个名字那么简单。我们来看下面的代码:

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>int main()
{//定义数组arr:int arr[10] = { 1,2,3,4 };//查看数组名意义:printf("数   组   名   意   义:%p\n", arr);//查看数组首元素地址:printf("数组首元素arr[0]地址为:%p\n", &arr[0]);//查看数组名占用空间:printf("数组名占用空间:%d\n", *arr);return 0;
}

我们把这段代码编译运行起来看看数组名的意义:

很明显,我们可以观察到,数组名实质上是数组内首元素的地址

难道所有的数组名都是数组首元素地址,没有例外吗?答案也是否定的,即下面两个特例:

1.sizeof(数组名):

sizeof计算整个数组的大小,也因此,当sizeof内部单独放一个数组名时,数组名表示整个数组。即sizeof(数组名)表示整个数组的大小

编写代码进行验证:

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>int main()
{//定义数组arr:int arr[10] = { 1,2,3,4 };//查看数组名占用空间:printf("数 组 名 占 用 空 间  :%d\n", *arr);//查看sizeof内数组名占用空间:printf("sizeof内数组名占用空间:%d\n", sizeof(arr));return 0;
}

编译运行查看结果:

2.&数组名:

&为取地址操作符,作用为获取数据在内存中的存储地址,在使用&+数组名时,因为数组的存储是连续的,知晓了数组首元素的地址,与之相连的一连串数据即为数组中的数据元素,故表示整个数组。即&+数组名表示整个数组的存储地址

除以上sizeof(数组名)与&数组名两种情况外,所有的数组名都表示数组首元素的地址

那么我们为什么要去研究数组名呢?关于这个问题,我们通常会结合接下来的数组名作为函数参数之类的相关知识,来对一些实例进行处理。

三、数组名作为函数参数:

我们在编写代码的时候,有时会需要将数组作为参数传递给函数进行处理。我们就以冒泡排序为例来进行研究。

将一个整形数组进行排序,排序方式为将每个元素像冒泡一样逐一进行比较,这种排序方式就被形象地称为冒泡排序

知晓了排序原理,我们很容易写出代码进行实现。那我们一起来看看,下面的代码是否是正确的,又能否实现冒泡排序:

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>//定义函数实现冒泡排序:
void bubble_sort(int arr[])
{int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (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[10] = { 3,1,7,5,8,9,0,2,4,6 };//打印排序前数组:printf("打印排序前数组:\n");int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}printf("\n");//尝试函数排序:bubble_sort(arr);//打印排序后数组:printf("打印排序后数组:\n");for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

那么这个程序到底能否实现冒泡排序?我们把它编译运行起来看看结果:

我们观察两次输出结果发现,这个函数并没有实现数组的比较和交换。这是为什么?

这就牵扯到我们上面提到的数组名的相关知识了,我们来看函数的调用:

//尝试函数排序:
bubble_sort(arr);

这里我们的目的是将数组传入函数进行处理,因为数组名本身就是地址,故在传址调用时不使用取地址操作符&。但是根据我们刚刚的了解,这里的数组名既不在sizeof中也没有使用取地址操作符&,而除这两种情况外,所有的数组名都表示数组首元素的地址!换句话说,这里仅仅只是将数组中的第一个元素传递给了函数。我们添加一行代码来打印一下传入元素数量进行验证:

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>//定义函数实现冒泡排序:
void bubble_sort(int arr[])
{int sz = sizeof(arr) / sizeof(arr[0]);//传入数据元素数量验证:printf("传入了 %d 个数据元素!\n", sz);int i = 0;for (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[10] = { 3,1,7,5,8,9,0,2,4,6 };//打印排序前数组:printf("打印排序前数组:\n");int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}printf("\n");//尝试函数排序:bubble_sort(arr);//打印排序后数组:printf("打印排序后数组:\n");for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

编译运行查看验证结果:

果然,经过验证,我们的参数传入是有误的,导致函数并没有接受到正确的参数,最终无法实现我们的预期功能。

那么我们要怎么做才能实现我们的目的呢?

很简单,我们都知道,数组中数据元素的存储是连续的。也就是说,只要我们知道了数组的首元素地址,只需要从首元素地址开始,继续向后读取等同于数组中的数据元素数量的数据即可

而既然调用时只向函数传入首元素地址,函数中无法进行计算,那我们只需要在函数外进行计算,并将计算结果也传入函数即可:

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>//定义函数实现冒泡排序:
void bubble_sort(int arr[], int sz)
{//传入数据元素数量验证:printf("传入了 %d 个数据元素!\n", sz);int i = 0;for (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[10] = { 3,1,7,5,8,9,0,2,4,6 };//打印排序前数组:printf("打印排序前数组:\n");//计算数组中的数据元素个数:int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}printf("\n");//尝试函数排序:bubble_sort(arr, sz);//打印排序后数组:printf("打印排序后数组:\n");for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

我们再将经过修改的代码编译运行起来,看看经过修改后的程序能否达到我们的要求:

这一次我们看到,我们修改过的的程序很好的完成了我们的预期任务。至此,关于数组名和数组作参的知识我们就大致掌握啦!

到这里,我们关于数组的学习就基本结束啦!希望各位小伙伴们能够多加练习,巩固基础,为接下来的学习和提升做好准备!成功没有什么秘诀,如果真的有,也就两个,第一个就是坚持到底,永不放弃;第二个是当你想放弃的时候,回过头来看看第一个秘诀!

新人初来乍到,辛苦各位小伙伴们动动小手,三连走一走 ~ ~ ~  最后,本文仍有许多不足之处,欢迎各位看官老爷随时私信批评指正!

C语言第九课:数组(下)——数组越界、数组名与数组作参相关推荐

  1. java实现初始化三角形数组_Java 数组、多维数组,动态、静态初始化,数组JVM内存模型分析...

    Java 数组.多维数组,动态.静态初始化,数组JVM内存模型分析 什么是数组 所谓数组,是具有相同数据类型的若干变量或者数据按照一定排序规则组合起来的一种数据存储格式.数组中的数据称为数组元素,我们 ...

  2. C语言中不检查数组下标是否越界。

    C语言中不检查数组下标是否越界. 转载于:https://www.cnblogs.com/AsmLearner/p/3405567.html

  3. c语言数组越界是什么意思,数组越界操作是什么原因

    满意答案 一.什么是数组访问越界? 我们通过数组的下标来得到数组内指定索引的元素.这称作对数组的访问. 如果一个数组定义为有n个元素,那么,对这n个元素(下标为0 到 n-一的元素)的访问都合法,如果 ...

  4. C语言二维数组下三角、上三角螺旋赋值并打印

    题目:将一个7*7(只能要求必须行和列相等的矩阵)的二维数组下三角部分以螺旋.依次+1的方式填满并输出(如下图所示) 方法:依旧设置四个变量Left.Right.Up.Down控制循环,不过只有三种模 ...

  5. 嵌入式C语言基础知识查漏补缺--内存管理函数指针数组

    内存管理: 堆和栈的理解和区别 局部变量 静态局部变量 全局变量 静态全局变量 作用域 在定义变量的{}之内有效 在定义变量的{}之内有效 整个工程,所有文件 当前文件 生命周期 程序运行至变量定义处 ...

  6. C语言学习——从零开始学编程(第五篇:数组)

    文章目录 前言--小颖的话 一.一维数组 1.一维数组的创建和初始化 1)一维数组的创建(定义) 2)一维数组的初始化 2.一维数组的使用 3.一维数组在内存中的存储 二.二维数组 1.二维数组的创建 ...

  7. C语言指针基础知识点(六)--通过指针引用多维数组

    指针系列目录   C语言指针基础知识点(一)–指针及指针变量   C语言指针基础知识点(二)–指针变量的引用   C语言指针基础知识点(三)–指针变量作为函数参数   C语言指针基础知识点(四)–通过 ...

  8. 01_Java语言基础部分(数据类型与表达式、流程控制语句、数组与方法)

    1. Java语言主要由5中符号组成 标识符:数字.字母.美元符.下划线(注意不能数字开头) 关键字(被Java赋予特殊意义的单词,注意所有关键字都是小写):   goto和const保留了它们,但是 ...

  9. C语言向有序数组中插入一个数使该数组仍保持有序

    C语言向有序数组中插入一个数使该数组仍保持有序 #include<stdio.h> int main() {     int n,i,j,t,k;     printf("您喜欢 ...

最新文章

  1. 智能跳过节假日算法java_java计算两个日期之前的天数实例(排除节假日和周末)...
  2. 分享一个多线程实现[冒泡][选择][二分法]排序的例子
  3. Google的三篇大数据思想论文
  4. java队列优先级_优先级队列-Java的PriorityQueue与最小堆有何不同?
  5. Java中的几种对象(PO、VO、DAO、BO、POJO)
  6. Java并发编程-ReadWriteLock读写锁
  7. 系统集成资质-信息系统项目管理师考试综合介绍
  8. C++ 多态与虚函数面试题
  9. linux yum被占用
  10. MFC把 ListCtrl的数据导出到excel表格
  11. 华硕主板前置耳机插孔没有声音怎么办
  12. python和jieba库进行简单文本处理之天龙八部小说
  13. 基于电力行业信息安全基线的量化管理系统研究与应用
  14. 黎曼积分求解可微曲线的弧线长度
  15. 在黑暗中哭泣的众筹,黎明的曙光还未到来
  16. C语言--逗号运算符及逗号表达式
  17. CC防御过程中,WAF的主要特点有哪些?
  18. 编写Java程序,实现简单的五子棋博弈游戏(美和易思Java练习习题)
  19. android跳一跳功能实现,Android 数字跳动显示的TextView实现
  20. 电路设计_LED压降常识

热门文章

  1. 《未来绽放的篇章》——毕业季征文,展望充满希望的前方
  2. 海量资源请加QQ群282781158
  3. 1.1计算机的基本组成:运算器、控制器、存储器、输入设备和输出设备
  4. 大开眼界!“巨齿鲨”现身2018世界机器人大会?
  5. 美亚kindle排名第一的Python 3入门书,火遍了整个编程圈...
  6. for_each用法
  7. OpenHarmony/HarmonyOS中用ArkTS实现登陆界面
  8. 本地python库离线包批量导出和导入
  9. 数独——个人项目(项目地址)
  10. [FAQ21281]android P分区表中odmdtbo与dtbo分区的说明