嵌入式C语言编程中经验教训总结(三)数组的正确使用

34 篇文章 3 订阅
33 篇文章 2 订阅
本文介绍了C语言中数组的正确使用方法,包括初始化、防止越界访问、作为函数参数时的注意事项。强调了在数组初始化时避免边界问题,以及在处理数组时防止越界访问的重要性。同时,解释了数组作为函数参数时,sizeof操作符的误用,建议在传递数组时携带数组长度。此外,还讨论了多维数组的概念和存储方式,并对比了指针数组在处理字符串时的灵活性和效率优势。
摘要由CSDN通过智能技术生成

数组的正确使用

1.数组初始化

在 C99 以后的标准中,允许使用单个指示符为数组的两段“分配”空间,如下面的代码所示:

#define Array_Length 20
int Data[Array_Length] ={0,1,2,3,4,[Array_Long-5]=15,16,17,18,19};

在 Data[Array_Length ]数组中,如果 MAX 大于 10时都没有问题,只不过第5到15的元素将用 0 值进行填充;如果 Array_Length 小于 10,前 5 个元素中将有几个被后 5 个元素(6,7,8,9,10)所覆盖,例如Array_Length=8,初始化结束后:

Data[Array_Length] ={0,1,2,15,16,17,18,19}

是不是和预期不一样了?

2.防止数组越界访问

在 C 语言中,数组必须是静态的。数组的大小在程序运行前就确定了。所谓的数组越界访问,就是指数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围之外。由于 C 语言不会像 Java 等语言对程序中数组下标取值范围进行严格检查,一旦发现数组上溢或下溢,都会因抛出异常而终止程序。而C 语言并不检验数组边界,而检验数组的边界是程序员要做的事情,数组的两端都有可能越界,从而使其他变量的数据甚至程序代码被破坏。
还依上面声明的数组为例:

  1. //其他代码
  2. for(i=Array_Length;i>0;i–)
  3. {
  4.  a=Data[i] ;
    
  5.  //其他代码   
    
  6. }

看出上面程序的问题了吗?

这里有两个隐含的bug,我们声明了Array_Length长度个元素的数组,但是别忘了,c语言的数组下标是从0,开始的,所以,数组元素Data[Array_Length]是根本不存在的,但C语言编译器却不会告诉你,也就是说,这种情况是允许的,但实际上,Data[Array_Length]的位置上,可能是其他变量(假设为t)的位置,这就会造成a在第一次循环时使用的并不是数组最后一个元素,而是t变量的值,此处为读操作,可能只是影响了for循环的结果,如果是写操作的哈,会直接修改t变量的值,会有什么结果就只有天知道了。

3.数组作为函数的参数时

假如函数func()的形参是上面声明的Data[i] 数组,通常是这样使用的:

extern int Data[];
函数代码如下所示:

void func(int Data[])
{
unsignedint i,j,len=sizeof(Data);//获取数组的长度;
//其他代码
for(i=0;i<len;i++)
{
Data[i]=j;
//其他代码
}
}

在 C 语言中,sizeof 是一个单目操作符,不是函数。其作用就是返回其操作数所占的内存字节数。其中,操作数可以是一个表达式或括在括号内的类型名,操作数的存储大小由操作数的类型来决定。例如,对于数组int a[5],可以使用sizeof(a)来获取数组的长度,这种想法对数组作为函数形参时却是行不通的,
实际上,编译器是将数组名Data隐含的转化为指向数组第一个元素的指针,函数体是使用指针的形式来访问数组的

                       len=sizeof(Data)

实际上获得的Data指针的长度,它显然和数组长度是两个概念,切记,获取数组的长度时不要对指针应用 sizeof 操作符,既然不能使用sizeof获取数组长度,那如何正确使用数组而不越界昵,可以在传递数组参数的时候,带上传入数组的长度,例如:
void func(int Data[],int len)
{
unsignedint i,j;
//其他代码
for(i=0;i<len;i++)
{
Data[i]=j;
//其他代码
}
}

4多维数组

C 语言中的多维数组(multidimensional array)其实就是元素为数组的数组。n 维数组的元素是 n-1 维数组。例如,二维数组的每个元素都是一维数组,特殊情况一维数组的元素计算单个元素了。

多维数组声明时,每个维度用一对方括号来表示,例如二维数据

Data[row][col] 

我们需要行row和列col两个维度才能确定唯一的一个内部元素。定义一个3x4的二维数组,可以这样声明:

int array[3][4] =
{
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }
};

该数据具有3行,每一行都具有4个元素,所以这个二维数组一共具有3x4=12个元素。

通过一个双循环嵌套来对这个二维数组进行初始化和显示:

for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
array[i][j] = i+j;
printf(“%d\n”, array[i][j]);
}
}

存储多维数组时,维度靠后的的数据连续存储,如下图:

在这里插入图片描述

5指针数组

所谓的指针数组,就是定义一个数组,数组里面的每一个元素都是一个地址。

例如:int a=1, b=2, c=3;
int * Add [5] = {&a,&b,&c};

其中则 Add [1] 就是&b, 所以 * Add [1] 与 b 是一样的。

指针数组常常作为二维数组的一种便捷替代方式,继承了指针的优点和灵活性,达到使用灵活,节省空间和提高效率的作用,例如,如果需要处理一批长短不一字符串,我们可以将它们存储在一个二维数组中,但是,该数组行空间大小必须足以存储下可能出现的最长字符串:

#define ARRAY_Num 500
#define STRLEN_MAX 1024
char myStrings[ARRAY_Num ][STRLEN_MAX ] =
{ // 字符举例:
“123”
“1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111”
“22222”
};

然而,这个方式造成大量的内存浪费,短字符串会让大部分的数据空间是空的;另一方面,有些行根本没有用到,但却得为它预留内存。解决这个问题的一个简单的解决方案就是使用指针数组,让指针指向对象(在此处的对象就是字符串),然后只给实际存在的对象分配内存(未用到的数组元素则是空指针)。

   #define ARRAY_Num 500

char *myStrPtr[ARRAY_Num ] =        // char指针的数组
{ // // 字符举例:
“123”
“1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111”
“22222”
};

这样一来,myStrPtr数组指针的每个元素空间都得到充分利用率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cyjbj

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

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

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

打赏作者

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

抵扣说明:

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

余额充值