liuchuanwu的个人博客分享 http://blog.sciencenet.cn/u/liuchuanwu

博文

C语言的动态全局数组

已有 14840 次阅读 2013-8-23 13:35 |个人分类:C语言|系统分类:科研笔记| C语言, 动态, 数组, 全局, 结构体

   新学到的有用的知识,怕忘了,按我的理解做个笔记。可为他人参考。


一、动态数组

   C语言中不能直接定义动态数组,用普通的方式定义的数组其大小不能改变。如。通过int a[N];定义大小为N的整型数组,其后N的改变不会再改变原来数组大小。但我们可以间接地得到一个动态数组,即需要时通过malloc()或calloc()等动态存储分配函数分配一块空间,将其返回的所分配单元的起始地址赋给指针,我们就可以利用得到的指针进行和数组一样的操作。因为我们知道普通的数组名其实就是数组的起始地址,相当于一个指针常量。


例1,如我们想定义一个大小为n(例如10)的动态整型数组:

=====================

   int *a;

   int n;

   n = 10; //此处设为10

   a =(int *)malloc(sizeof(int)*n); /*动态分配存放10个整型的内存,将所分配空间起始地址转换为

                                                         整型地址赋给指针a*/

   a[5] = 100;                                  /*引用同一般数组,但不应超出所分配内存的大小

                                                       a[5]相当于*(a+5), 即从首地址向后跳过5个(整型)内存*/

   free(a);                                        //释放a所指的内存区

=====================

在知道地址和变量类型的情况下,a[i]等同于*(a+i),即从首地址开始跳过i个已知类型的数据元素。这两个内存函数原型为void *malloc(usigned size);和void *calloc(unsigned n, unsign size);它们包含在<stdlib.h>中。两者区别有二:一是前者分配size个字节大小的连续空间,后者分配n个size字节的连续空间。二是后者分配的内存初始化为0;而前者没有;如果想改变一个已分配地址的内存区的大小可以用函数void *realloc(void *p, unsign size)。这几个函数返回void 指针类型,赋值给其他类型指针时,需经过类型转换,系统一般在编译时也进行隐式转换。


二、多维动态数组

     C语言中普通多维数组其实是一维数组,只不过各元素也是数组类型。想得到多维的的动态数组,可以嵌套使用前面的方法,如将得到的动态数组的元素a[i]再定义为动态数组。即定义指向指针的指针,再由外向内逐级分配空间。


例2:定义三维动态数组a[n1][n2][n3],其中n1,n2,n3为正整数:

==========================

int ***a; //定义指针的指针的指针

int n1, n2, n3;

int i, j, k;

scanf("%d%d%d",&n1,&n2,&n3);

a=(int ***)malloc(n1*sizeof(int **));  /*a有n1个元素,每个元素仍为数组(其实是指针的指针)

                                                        a为数组首地址,a[1],a[2],...,a[n1]为其子数组元素首地址,以此类推直至得到元素*/
for(i=0; i<n1; i++)

{
   a[i]=(int **)malloc(n2*sizeof(int *));  //a[i]有n2个元素,每个元素为一维数组的首地址(其实是指针)
   for(j=0; j<n2; j++)
   {
       a[i][j]=(int *)malloc(n3*sizeof(int)); //a[i][j]为一维数组,大小为n3
       for(k=0; k<n3; k++)
       {
           a[i][j][k] = i*n2*n3+j*n3+k;          //元素a[i][j][k]的引用同一般数组
        }
     }

}

.......;

//使用后要释放存储空间,注意由内向外逐级释放

for(i=0; i<n1; i++)
{
   for(j=0; j<n2; j++) free(a[i][j]);
   free(a[i]);
}
free(a);
=====================

多维数组分配存储空间从外往内,释放空间时要由从内往外。函数分配的内存空间,即使没有指针指向,它仍然存在,不自动回收,所以不能通过这定指针为空来释放空间。


以上通过指针和指向指针的指针在逻辑上模拟出一个动态数组。但其和普通的数组在内存分配上是不同的。真正的数组内存顺序分配,数组名并不单独开辟变量存储,其数组地址为一常数分配后不可改变,数组各维大小相等。动态模拟的数组不同维的元素并不连续,各维数组大小可以不同。


三、全局动态数组。

   C语言的函数间参数传递为值传递,这与Fortran的地址传递不同。如果想通过调用函数来对原函数的变量进行操作可以将变量的指针(变量地址)传递给被调函数。另一种的方法是将变量设置为全局变量,这样其后的函数都可以对此变量进行操作了。如何定义一个全局动态数组呢,只要在函数体前声明一个全局指针,需要时在函数体内对此指针用malloc()或calloc()赋给地址即可。全局指针和其后分配的空间相当于一个全局数组。


   例3,如我们想得到一个全局动态结构体数组

========================

struct mystruct

{ int b;

 .......;};

struct mystruct *a;         //在函数体外定义mystruct类型的全局结构体指针a


void main()

{   ......;

   int n =10;

   a=(struct mystruct *)malloc(sizeof(struct mystruct)*n); //在函数内分配存储空间,把首地址赋给全局指针

   a[2].b = 100;          //使用同普通结构体数组, 此数组为全局变量

   .......;

   free(a);

}

========================


引出:如何从文件中读取二进制数据到所分配的内存空间(或数组)呢?或者如何写到文件呢,很简但,用fread和fwrite就行。这两各函数用于在文件中读写数据块。

fread(buffer, size, count, fp);

fwrite(buffer, size, count, fp);

buffer是一个指针,指向读写数据快首地址。size要读写数据的字节数,count读写多少各size。fp文件型指针。


  接上例如我们想从fp所指的文件读取一个大小为10的结构体数组

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

   fread(&a[i], sizeof(struct mystruct), 1, fp);

或者直接读取数组全部

   fread(a, sizeof(struct mystrnct), 10, fp);


   fread(a, sizeof(struct mystruct)*10, 1, fp);

 

2013年8月23日



https://wap.sciencenet.cn/blog-1005104-719123.html

上一篇:我的民族观
下一篇:兰大萃英班之道听途说
收藏 IP: 128.250.55.*| 热度|

1 徐大彬

该博文允许注册用户评论 请点击登录 评论 (2 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-4-19 05:44

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部