C

9. C语言教程-动态内存分配

9. Dynamic memory alloc

Posted by xuepro on October 30, 2017

“教小白精通编程”系列之“C语言教程” (版权所有,不得转载,擅自抄袭转载将承担法律责任)

动态内存分配

下面的这个学生成绩输入输出程序最多只能输入100个学生成绩,假如多于100个学生的情况怎么办?

struct student{
     char name[10];
     double score;
  }
  
  void Print(struct student stu){
     printf("%s,%lf\n",stu.name,stu.score);     
  }
  void Scanf(struct student *stu){
     scanf("%s %lf",&(stu->name),&(stu->score));    
  }

void main(){
  sturct student students[100]; /*最多能放100个学生成绩*/
  int n=0; /*实际学生人数*/  
  do{
     Scanf(&students[n]);
     if(s.score<0)       break;   /*推出循环*/
     n++; //新输入一个学生信息,人数增加1 
  }while(1);
  
  for(int i = 0 ; i<n ;i++)
     Print(students[i])
}

解决方法:可以根据实际情况来分配存放所有学生成绩的内存块。 即调用内存分配函数如malloc向操作系统申请足够大的内存空间。

使用完内存后,假如不再需要,应该调用内存释放函数如 free将这块内存还给操作系统! “有借有还”。

内存分配函数在 定义,所以程序需要包含这个头文件。

主要有4个内存分配和释放函数,如下:

  • void *calloc(int num, int size);

分配num个元素,每个元素占据字节数为size的内存块,返回该内存块的地址

  • void free(void *address);

释放 address 指向的内存块.

  • void *malloc(int num);

分配num个字节的内存块,返回该内存块的地址

  • void *realloc(void *address, int newsize);

重新分配newsize字节的内存空间,并将address指针变量指向的旧内存块的数据转移到新分配的内存块中.返回新内存块的地址

学生成绩单程序可以修改如下:

struct student{
     char name[10];
     double score;
  }
  
  void Print(struct student stu){
     printf("%s,%lf\n",stu.name,stu.score);     
  }
  void Scanf(struct student *stu){
     scanf("%s %lf",&(stu->name),&(stu->score));    
  }

void main(){
  sturct student *students; /*sturct student类型的指针变量*/
  int n=0; /*实际学生人数*/
  scanf("%d",&n);   /*从键盘输入实际的学生人数*/
  
  /*分配n个sturct student类型元素的内存块,
    并将返回地址转化为“sturct student类型的指针”,
    其中的sizeof用于查询一个sturct student类型变量占用的字节数。
    比如,sizeof(int)用于得到一个int类型变量占用内存的字节数
  */
  students = (sturct student *) malloc(n*sizeof(sturct student));  
  
  do{
     Scanf(&students[n]);
     if(s.score<0)       break;   /*推出循环*/
     n++; //新输入一个学生信息,人数增加1 
  }while(1);
  
  for(int i = 0 ; i<n ;i++)
     Print(students[i]);
   
  free(students);  /*释放students指向的内存块*/ 
}

链表

存储上面的学生成绩表,还有一种很好的方法,就是为每个学生数据动态分配一块内存块,表示不同学生数据的内存块之间用指针变量关联起来。即第1个学生的内存块中有一个存储第2个学生内存块的地址,第2个学生的内存块中有一个存储第3个学生内存块的地址,如此下去,如同一个链条一样,将这些学生的内存块串在一起。这种存储一组数据元素的方式称之为“链表”,而表示每个学生数据的内存块称为一个”结点“。

 我们不需要给每个学生的”结点“起一个名字,只要将第一个学生的”结点“保存在一个命名的指针变量,然后就可以通过这指针变量(比如叫做head)依次访问到每个”结点“。  

   

  我们可以用这个链表存储维护所有学生的数据,并执行各种操作比如:插入、删除、查找等。 

  上述链表中,除第一个学生外,其他学生结点的前面必然有一个”前驱结点”, 因此对这种链表进行操作比如删除一个结点,需要区分一个结点是否是第一个结点而执行不同的处理逻辑。为了使得对所有学生结点的操作能否统一起来,我们可以认为的增加一个没有实际数据的“结点”,将这个所谓的“头结点”放在最前面,它后面跟着的就是第1个学生的结点(称之为”首结点“)。即用如下形式的链表。     我们可以针对这种链表写一组辅助函数来对维护这个链表中的数据,比如初始化、插入、 删除、查找等.详细的实现代码可以参考

数据结构-线性表的链式实现(链式表

只要将其中的数据类型T换成学生数据类型就可以了。比如

 //用typedef 给无名结构类型起了一个新名字叫做T,
 // 或者说T就是表示一个学生信息的结构类型。
 typedef struct{
    char name[10]
    float score;
 } T;

 

关注“教小白精通编程”博客微博“教小白精通编程”  


支付宝打赏 微信打赏

您的打赏是对我最大的鼓励!