分享
 
 
 

第六章 “另类”数组

王朝other·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

动态数组与字符串常量可算是两种“另类”数组。

VLA可变长数组并不为C89所支持,C99才开始支持VLA。但如果想在只支持C89的编译环境中使用VLA的话,怎么办呢?我们可以用动态数组来“模拟”,动态数组在矩阵的运算中很常见,常用来向函数传递一个大小可变的矩阵。动态数组的原理,是利用一块或多块动态分配的内存存储各维的首地址,这样就可以p[i][j]的形式访问数组的数据了。但是,动态数组并非真正的数组,它只是对数组的一种模拟。由于具有数组类型的数组名是系统行为,在用户这一级没法做到,因此只能以指针的形式存放首地址,sizeof(p)和sizeof(p[i])结果都是4字节。虽然动态数组是依靠动态分配内存来建立的,但动态的意义并非来自这里,而是指大小可变。笔者觉得用“动态数组”这个名称来命名非常适合,既不失大小可变的特征,又可以跟VLA可变长数组区分开来。

下面是建立动态数组的示例:

#include <stdio.h>

#include <stdlib.h>

void computedata(int *, int, int);

int main(void)

{

int iData[100], x, y;

do

{

printf("The product obtained by multiplying x and y must be less than 100!");

printf("x=");

scanf("%d", &x);

printf("y=");

scanf("%d", &y);

}

while(x*y > 100);

computedata(iData, x, y);

return 0;

}

void computedata(int *ipSource, int iRow, int iColumn)

{

int **ipTemp, i, j;

ipTemp = (int **)malloc(iRow*sizeof(int*));

for(i=0; i<iRow; ++i) ipTemp[i] = ipSource+i*iColumn;

for(i=0; i<iRow; ++i) for(j=0; j<iColumn; ++j) ipTemp[i][j] += 1;

free(ipTemp);

return;

}

以上示例把动态数组ipTemp的元素都加了1,由于只是示例,笔者省略了检测数据合法性的代码。iRow是第一维上界,iColumn是第二维上界,iData是源数据缓冲区,iRow*iColumn的积不能超过iData缓冲区的大小,否则就会越界了,但可以比它小。示例中iData被定义为一维数组,当然根据自己的需要也可以用其它类型的缓冲区代替,例如动态分配的一块内存,或者多维数组,如果是多维数组,例如三维数组int iData[10][10][10],调用computedata函数时,实参iData得做一些转换:

computedata((int *)iData, x, y);或者computedata(&iData[0][0][0], x, y);都可以。

ipSource指针用来传递缓冲区的首地址,这个指针由于要用来计算各维的地址,因此最好定义为一级指针,这样比较方便。ipTemp是一个二级指针,这是因为它指向的那块内存存放的是指针,这些指针指向各维的首地址,对ipTemp的元素来说,ipTemp就是二级的。最后记得free(ipTemp);

以上是定义一个二维动态数组的例子,多维动态数组的创建方法跟这个类似,下面给出三维动态数组的代码:

void computedata(int *ipSource, int iHigh, int iRow, int iColumn)

{

int ***ipTemp, i, j, k;

ipTemp = (int ***)malloc(iHigh*sizeof(int**));

for(i=0; i<iHigh; ++i) ipTemp[i] = (int **)malloc(iRow*sizeof(int*));

for(i=0; i<iHigh; ++i) for(j=0; j<iRow; ++j) ipTemp[i][j] = ipSource+i*iRow*iColumn+j*iColumn;

for(i=0; i<iHigh; ++i) for(j=0; j<iRow; ++j) for(k=0; k<iColumn; ++k) ipTemp[i][j][k] += 1;

for(i=0; i<iHigh; ++i) free(ipTemp[i]);

free(ipTemp);

return;

}

下面来讨论字符串常量。

众所周知,C语言是没有字符串变量的,因而,C89规定,字符串常量就是一个字符数组。因此,尽管字符串常量的外部表现形式跟数组完全不同,但它的确是一个真正的数组,实际上,字符串常量本身就是这个数组的首地址,并且具有数组类型,对一个字符串常量进行sizeof运算,例如sizeof("abcdefghi"),结果是10,而不是4。字符串常量与一般数组的主要区别,是字符串常量存放在静态存储区,而一般数组(非static)则是在栈中静态分配的。由于字符串常量是数组首地址,因此可以数组引用的形式使用它,例如:

printf("%s", &"abcdefghi"[4]);

这将打印出字符串efghi。还可以这样:

printf("%s", "abcdefghi"+4);

同样打印出字符串efghi。实际上,&"abcdefghi"[4]等价于&*("abcdefghi"+4),去掉&*后,就是"abcdefghi"+4了。

我们可以利用字符串常量这些特性写出一些有趣的程序来,例如:

#include <stdio.h>

int iLine=1;

int main(void)

{

printf("%*s\n", 7-(iLine>4?iLine-4:4-iLine), "*******"+2*(iLine>4?iLine-4:4-iLine));

if(++iLine != 8) main();

return 0;

}

这个程序不使用任何数组形式的引用,不使用循环,就可以打印出用*号组合出来的菱形。当然,笔者并非鼓励大家编写这样的代码,但通过这样的例子加深对字符串常量的认识,仍然是非常重要的。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有