c语言—— 数组 基础(详解)

数组简介

数组是一种数据结构,它一次性存储多个相同类型的变量。数组是使用类型声明的,数组具有以下属性:

1   数组从字面上理解就是存放一组数,但在C语言中数组存放的并不一定是数字,也可以是其他数据类型。

2   数组的索引从零开始:具有n个元素的数组的索引是从0到n-1。

3   数组元素可以是任何类型,包括数组类型。

4   在一个数组中存放的值都是同一数据类型的,并且可以通过循环以及数据操作的方法对数组的值进行运算或操作。
 

定义数组

声明数组的时候要明确以下三点:
1.确定数组名称; \*标识符指定了数组的名称,记住,数组名是一个常量,代表着数组元素集合在内存存储的起始地址,不能进行自增自减运算。*\
2.确定数组元素的类型;/* 可以是整型、浮点型等基本数据类型,还可以是结构体、类等自定义数据类型。*\
3.确定数组的维数及每维的大小

类型说明符  数组名 [ 常量表达式1 ] [ 常量表达式2 ][ 常量表达式3 ] .....                                              例如:  int  a [ 6 ] //   a 表示为数组名 ,此数组有6个元素 ,                                                                分别是      a[0],  a[1]  ,a[2],  a[3],  a[4],  a[5]

  注意:

1   数组名必须是合法标识符。

2   C语言中,数组元素下标从0开始,int [6];所定义的数组a中并不存在数组元素a[6].

3   常量表达式可以包括常量和符号常量,不能包括变量。下列定义是错误的:

int n;     n=3;      int  a[n];

一维数组

定义:一般把同一种数据类型的一个集合定义成数组,以便对整个集合的数据进行处理。

1.1. 一维数组的定义方式

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

例如:int  a [ 10 ]        它表示数组名为a,此数组有10个元素,                                                           分别是   a[0]    a[1]  ,  a[2],  a[3]   a[4]   a[5]   a[6]   a[7]   a[8]   a[9]   

1.2. 一维数组元素的表示

C语言中,定义的数组 a[ n ] 中,共有n个元素,分别用  a[0]  a[1]  ....  a[n-1] 表示,即  下标范围是  0 ~ n-1  。

一维数组元素的输入输出:

C语言中,一维数组元素的输入输出一般只能对每个元素依次执行,为了方便操作,一般使用一重循环语句配合使用。

例如:  int a[20], i;

for( i=0 ; i<20 ; i++ )

sscanf("%d", &a[ i ])

打印1~10的数组元素 

 打印数组1~10中的 1  3  5  7  9

练习:定义数组,输入10个实数,并按输入相反次序输出该10个实数。 

1.3. 一维数组的初始化

一维数组的初始化就是在定义一维数组同时给数组赋初值。                                                          

一维数组的初始化有以下几种方式:

1  在定义数组是对数组元素全部赋值。如 :

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

2  只给数组元素部分元素赋值。 如 :

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

3  给数组元素所有元素赋初值时,可以省略数组长度。 如:

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

注意:  整体给数组赋值只能在定义数组是使用,数组初始化是必须从第一个元素开始依次初始化


1.4. 一维数组的存储

定义数组时,在内存中按照所定义的数组类型及元素个数分配一段连续的存储空间给数组,             如int a[10] ,在内存中分配4*10个字节的空间给数组a,因为一个整型数据占4个字节,共10个元素,所以分配4*10个字节空间。数组名 a 表示该数组所分配连续内存空间中第一个单元的地址,即首地址。一维数组内存分配如下所示

 打印a[10]的地址

仔细观察输出的结果,可知随着数组下标的增长,元素的地址,也在有规律的递增。 由此可以得
出结论:数组在内存中是连续存放的

总结:

  1. 数组在内存中开辟是线性连续且递增的。
  2. 在c语言中,任何变量(基本变量,指针变量,结构体变量,数组变量)的空间都是整体开辟,但任何元素的起始地址一定是开辟字节当中最小的。

 二维数组

2.1. 二维数组的定义

二维数组是指由多个一维数组组成的一个数组,每个一维数组也称作二维数组的一行,而所有一维数组的元素又称为二维数组的。二维数组可以理解为一个表格,其中每一行表示一个对象或记录,每一列表示一个属性或字段,而单元格中的值就是对象在该属性或字段上的取值。二维数组可以用以下方式定义:

类型说明符  数组名  [常量表达式] [常量表达式] //   类型名 数组名  [ 行长度 ][ 列长度 ];

例如  int a[4][5] ,b[5][10]; 

注意:

二维数组a[ n ] [ m ]可以看作定义n(行)*m(列)的数组,把二维数组看作一个特殊的一维数组,

如 int a[3][4] 是一个一维数组,它有3个元素:a[0], a[1], a[2] ,   每个元素又是一个包含4个元素的一维数组 

二维数组行标和列表都从0开始,整个二维数组元素个数都是行标和列表的乘积,

如:int a[2][3] ,元素共有6个,分别是:a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] ;要注意的是数组a中是没有a[2][3]这个元素的

 二维数组中元素排列的顺序是:即在内存中先顺序存放第一行的元素,再存放第二行的元素       


2.2. 二维数组的引用

二维数组的表达形式:

数组名 [ 下标 ]  [ 下标 ]

数组元素可以出现在表达式中,也可以被赋值,例如:

int a[3][4]  , b[4][7] , c[99][10];

a[2][3]=2 ;

b[4][5]=a[2][3]*2;

注意:二维数组元素引用时,一般都是使用双重循环对每个元素进行引用。

2.3. 二维数组的初始化

初始化二维数组是在创建数组的同时为每个元素赋予初始值。这可能需要更多的关注,尤其是在初始化多维数组时。


        在定义二维数组时,当然也可以对数组元素赋值,二维数组的初始化方法有两种。

分行赋初值:

                类型名  数组名  [ 行长度 ][ 列长度 ] = { {初值表0},....,{初值表n },.... };

//如初始化二维数组 a:  int a [3][3]={ {1,2,3},{4,5,6},{7,8,9} };

        同样二维数组的初始化也可以只针对部分元素,如  int a[3][3] = { {1,2,3} ,{ } ,{4,5} }; 只对第一行和第三行前两个元素赋值

顺序赋初值:

                类型名  数组名 [ 行长度 ][ 列长度 ] = { 初值表 };

//根据数组元素在内存中的存放顺序,把初值表中的数据依次赋给元素,如 int a[3][3]={ 1,2,3,4,5,6,7,8,9 };

//当然它也可以针对部分赋初值,只是我们很少这样,较容易出错,因为你要特别注意顺序 int a[3]

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

  • 连续存储: 在内存中,二维数组的元素实际上是以一维数组的形式连续存储的,每一行的元素排列在一起,行与行之间相邻。
  • 内存地址计算: 计算二维数组中元素的内存地址需要使用起始地址、行索引、列数以及每个元素的大小。

注意:

  1. 二维数组在内存的空间布局上,也是线性连续且递增的!!!
  2. 二维数组本质上也是一维数组,只不过内部元素放的是一维数组

扩展:

二维数组在定义的时候,可以不给出行数,但必须给出列数,二维数组的大小根据初始化的行数来定

#include<stdio.h>
int main()
{
int a[][3]={
{1,2,3},
{1,2,3},
{4,5,6}
           }

printf("sizeof(a)=%d\n",sizeof(a));    // sizeof()   数组名

return 0;
}        

字符数组

3.1字符数组的定义

字符数组的定义与一维数组的定义相同:类型说明符  数组名 [ 常量表达式 ] 

例如:char c [ 12 ];

c[0]='H' ; c[1]='o' ; c[2]='w';c[3]='  ' ; c[4]='a' ; c[5]='r' ; c[6]='e' ; c[7]= '  ' ;  c[8]='y' ;  c[9]='o' ;  c[10]='u' ;  c[11]='?' ;  

c[0]c[1]c[2]c[3]c[4]c[5]c[6]c[7]c[8]c9[]c[10]c[11]
How  空格are空格you?

3.2字符数组的初始化

1. 对字符数组元素逐个赋值。

char c [3]={ 'H'. ;0' , 'w' } ;

2. 当初值个数与预定数组长度相同,可以省略数组长度。

char c [ ] ={ 'H' ,  'o',   'w' } ;

数组c的长度自动定为 3 。

3. 二维数组的初始化。

char c [] [] = {{ ' ' , ' ' ,' * ' ,' * ' , ' * '   } ,{ ' ' , ' ' ,' * ' ,' * ' , ' * '   }, { ' ' , ' ' ,' * ' ,' * ' , ' * '   } };

3.3字符数组的引用

可以通过引用字符数组中的一个元素,得到一个字符

 数组越界

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

#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
  int i = 0;
  for(i=0; i<=10; i++)/本来i<10,当i<=10的时候,就越界访问了
 {
    printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
 }
return 0;
}

避免数组越界

为了避免数组越界,有一些实用的方法和最佳实践:

  1. 检查索引范围: 在访问数组元素之前,始终检查索引是否在合法的范围内。可以使用条件语句来验证索引的有效性

if (index >= 0 && index < arrayLength) {
    // 执行数组元素访问操作
} else {
    // 处理越界情况,如报错或返回错误码
}
 

1. 使用循环: 在使用循环遍历数组时,确保循环的索引在合法范围内。循环条件应考虑数组长度。
2. 注意多维数组: 对于多维数组,确保每个维度的索引都在有效范围内。例如,对于 int myArray[3][4];,确保行索引在0到2之间,列索引在0到3之间。
3. 使用sizeof: 在使用数组时,可以使用 sizeof 运算符来获取数组的大小,以便进行索引的合法性检查。
 

数组作为函数参数

当数组作为函数参数传递时,数组名是一个指向数组首元素内存地址的常量指针。数组名实际上被解释为指向数组首元素的指针,这使得函数能够访问整个数组。

总结


通过本文的探讨,我们深入了解了在C语言中创建、初始化和使用一维数组的过程,同时还探讨了二维数组的相关内容。此外,我们还研究了数组越界问题以及如何将数组作为函数参数传递。以下是我们从这篇文章中所获得的关键信息:

5.1 一维数组的重要性和使用


1. 一维数组是C语言中的重要数据结构,用于有效地存储和管理一系列相同类型的数据。
创建数组时,我们需要指定数据类型、数组名称和大小。
2. 数组可以通过显式初始化来设置初始值,也可以部分初始化,未初始化的元素会被设为默认值。
3. 数组中的元素可以通过索引进行访问,索引从0开始,通过循环遍历数组可以实现对每个元素的操作。
4. 数组在内存中是连续存储的,可以通过内存地址计算和指针来访问元素。


5.2 二维数组的构建和使用


1.. 二维数组是表格状的数据结构,适用于需要表示行和列关系的情况。
2. 创建二维数组时,除了数据类型和名称,还需要确定行数和列数。
3. 通过提供初始化值来初始化二维数组,每个元素通过行索引和列索引定位。
4. 二维数组的访问也是通过双重索引实现的,行和列索引都从0开始。


5.3 避免数组越界问题


1. 数组越界指试图访问数组范围之外的元素,可能导致未定义行为、内存损坏和安全漏洞。
2. 可以通过检查索引范围、使用循环时确保索引在有效范围内,以及使用sizeof运算符来避免数组越界问题。


5.4 数组作为函数参数的特性


1. 数组名作为函数参数时,实际上是传递了一个指向数组首元素的常量指针。
2. 在函数参数中,数组名退化为指针,无法直接获取数组大小,需要通过额外参数传递。
3. 二维数组的访问也是通过双重索引实现的,行和列索引都从0开始。


5.5 避免数组越界问题


1. 数组越界指试图访问数组范围之外的元素,可能导致未定义行为、内存损坏和安全漏洞。
2. 可以通过检查索引范围、使用循环时确保索引在有效范围内,以及使用sizeof运算符来避免数组越界问题。


5.6  数组作为函数参数的特性


1. 数组名作为函数参数时,实际上是传递了一个指向数组首元素的常量指针。
2. 在函数参数中,数组名退化为指针,无法直接获取数组大小,需要通过额外参数传递。
3. 了解数组名在函数参数中的特性有助于正确处理数组的大小和越界问题。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幻觉的信仰*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值