(C/C++学习笔记) 十四. 动态分配
十四. 动态分配
● C语言实现动态数组
C语言实现动态数组,克服静态数组大小固定的缺陷 |
C语言中,数组长度必须在创建数组时指定,并且只能是一个常数,不能是变量。一旦定义了一个数组,系统将为它分配一个固定大小的空间,以后不能改变,称为静态数组。但在编程过程中,有时我们所需的内存空间无法预先确定,对于这个问题,用静态数组的办法很难解决。 动态数组是相对于静态数组而言。静态数组的长度是预先定义好的,在整个程序中,一旦给定大小后就无法改变。而动态数组则不然,它可以随程序需要而重新指定大小。动态数组的内存空间是从堆(heap)上分配(即动态分配)的。是通过执行代码而为其分配存储空间。当程序执行到这些语句时,才为其分配。程序员自己负责释放内存。 |
#include <stdio.h> #include <stdlib.h> int main(){ int arrLen; // 数组长度 int *array; // 数组指针 int i; // 数组下标 printf("输入数组长度:"); scanf("%d", &arrLen); // 动态分配内存空间,如果失败就退出程序 array = (int*)malloc( arrLen*sizeof(int) ); if(!array){ printf("创建数组失败!\n"); exit(1); } // 向内存中写入数据 for(i=0; i<arrLen; i++){ array[i] = i+1; } // 循环输出数组元素 for(i=0; i<arrLen; i++){ printf("%d ", array[i]); } printf("\n"); free(array); system("pause"); return 0; } |
1 2 3 4 5 6 7 8 9 10 |
注意: 静态数组的长度不能改变, 但是它的数组元素的值可以改变, 如果要删除某个数组元素就比较复杂了, 可在学了数据结构后解决 |
● C语言的动态内存分配(堆管理)
Dynamic memory allocation in C----C语言的动态内存分配(堆管理) malloc(), calloc()和realloc()这三个函数用来在堆(heap)中分配内存空间, free()函数用来释放已经分配好的堆空间; 使用上述函数时要包含头文件<stdlib.h> malloc () function is used to allocate space in memory during the execution of the program. It does not initialize the memory allocated during execution, e.g., it carries garbage value. malloc () function returns null pointer if it couldn't be able to allocate requested amount of memory. calloc () function is also like malloc () function. But calloc () initializes the allocated memory to zero. But, malloc() doesn't (It carries garbage value). realloc () function modifies the allocated memory size by malloc () and calloc () functions to new size. ※ 上述三个函数返回值是一个指针, 指向一段可用内存的首地址 free () function frees the allocated memory by malloc (), calloc (), realloc () functions and returns the memory to the system. ※ free()函数无返回值 |
|
malloc () malloc (number *sizeof(int)); |
calloc () calloc (number, sizeof(int)); |
/* allocate memory for an array of 50 integers */ int *numbers; numbers = (int *) malloc(50 * sizeof(int)); /* allocate memory for a 100-character string */ char *str; str = (char *) malloc(100); //为避免出错, 最好写成: str = (char *) malloc(100 * sizeof(char)); |
long * newmem; newmem = (long *)calloc(100, sizeof (long)); |
realloc () realloc (pointer_name, number * sizeof(int)); |
free () free (pointer_name); |
char *p; p = malloc(20 * sizeof(char)); //没有强转malloc()返回的void*型的值 ... p = realloc(p, 100 * sizeof(char)); //也可以利用realloc()和已经分配好的内存空间再分配一个新的空间, 如: pp = realloc(p, 100 * sizeof(char)); //p和pp两个指针不同 |
free(umbers) //numbers是已经分配的一个内存空间的首地址 |
在C里,用malloc()等函数动态分配内存时,是不推荐强转其返回值的。例如写成: int *arr = malloc(sizeof(int) * 5); 而不是: int *arr = (int *)malloc(sizeof(int) * 5); 因为void *到其它类型的指针是隐式转换的 (C++要强转,不然会报错), 而malloc(), calloc(), realloc()的返回值类型是void *, 所以不推荐强转其返回值, 但也不会出错. 不过大多参考书都有强制转换, 而且在VC++ 6.0这种比较老的编译器上, 不强转的话, 编译会出错 |
Difference between malloc() and calloc() functions in C: |
|
malloc() |
calloc() |
It allocates only single block of requested memory |
It allocates multiple blocks of requested memory |
int *ptr; ptr = malloc( 20 * sizeof(int) ); For the above, 20*4 bytes of memory only allocated in one block. Total = 80 bytes |
int *ptr; ptr = calloc( 20, 20 * sizeof(int) ); For the above, 20 blocks of memory will be created and each contains 20*4 bytes of memory. Total = 1600 bytes |
malloc () doesn't initializes the allocated memory. It contains garbage values |
calloc () initializes the allocated memory to zero |
type cast must be done since this function returns void pointer int *ptr; ptr = (int*)malloc(sizeof(int)*20 ); |
Same as malloc () function int *ptr; ptr = (int*)calloc( 20, 20 * sizeof(int) ); |
Difference between static memory allocation and dynamic memory allocation in C
Static memory allocation |
Dynamic memory allocation |
In static memory allocation, memory is allocated while writing the C program. Actually, user requested memory will be allocated at compile time. |
In dynamic memory allocation, memory is allocated while executing the program. User requested memory will be allocated at run time. |
Memory size can't be modified while execution. Example: array |
Memory size can be modified while execution. Example: Linked list |
△reallocNULL,
malloc()和free() |
#include<stdlib.h> main() { int *numbers; numbers = (int *) malloc(50 * sizeof(int)); printf("%d\n",(int *)malloc(50 * sizeof(int))); //为什么这两句的结果不一样 printf("%d\n",numbers); //number是一个指针, 存储了被分配空间(一段内存单元: a series of data units)的首地址 printf("%d\n",numbers+2); //结果是number存储的地址加两个sizeof(int) *numbers=10; *(numbers+2)=20; printf("%d\n",*numbers); printf("%d\n",*(numbers+2)); free(numbers); //释放完块内存之后,没有把指针置 NULL,这个指针就成为了"野指针",也有书叫"悬垂指针" //这是很危险的,而且也是经常出错的地方, 所以一定要记住一条:free 完之后,一定要给指针置 NULL, 即: numbers = NULL; } |
calloc()和realloc() |
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { 个字节的空间; 另外, 因为不知道是将一个字符串常量还是若干字符赋给char *, 所以不要用const修饰 strcpy(p, "abcdef123"); printf("p = %s\n", p); const char *p1 = "hello world"; 是用于合并后的字符串末尾的'\0' char *p2 = (char *)realloc(p, 1024 * 100); strcat(p2, p1); printf("p2 = %s\n", p2); printf("%d\n",p); printf("%d\n",p2); if (p == p2) { printf("realloc没有改变指针变量p指向的变量的地址\n"); } else { printf("改变了\n"); } free(p); return 0; } |
使用calloc函数分配数组内存 |
#include <stdlib.h> #include<stdio.h> int main() { int* array; /*定义指针*/ int i; /*循环控制变量*/ array=(int*)calloc(3,sizeof(int)); /*数组内存*/ for(i=1;i<4;i++) /*使用循环对数组进行赋值*/ { *array=10*i; /*赋值*/ printf("NO%d is: %d\n",i,*array); /*显示结果*/ array+=1; /*移动指针到数组到下一个元素*/ } return 0; } |
个英文字母 |
/* Demonstrates the use of malloc() to allocate storage */ /* space for string data. */ #include <stdio.h> #include <stdlib.h> char count, *ptr, *p; int main( void ) { /* Allocate a block of 35 bytes. Test for success. */ /* The exit() library function terminates the program. */ ptr = (char *)malloc(35 * sizeof(char)); if (ptr == NULL) { puts("Memory allocation error."); return 1; } /* Fill the string with values 65 through 90, */ /* which are the ASCII codes for A-Z. */ /* p is a pointer used to step through the string. */ /* You want ptr to remain pointed at the start */ /* of the string. */ p = ptr; for (count = 65; count < 91 ; count++) *p++ = count; /* Add the terminating null character. */ *p = '\0'; /* Display the string on the screen. */ puts(ptr); free(ptr); return 0; } |
● 内存泄露memory leakage (内存丢失)
内存泄露memory leakage (内存丢失) |
● 关键字new和delete
关键字new和delete ※ new和malloc一样, 如果申请内存空间成功, 则返回被分配内存的首地址给定义的指针; 否则(比如没有足够的内存空间), 则返回0, 即空指针. new的用法: :指针变量名=new 类型标识符; :指针变量名=new 类型标识符(初始值); :指针变量名=new 类型标识符[内存单元个数]; delete的用法: 1. 删除单变量地址空间 int *a = new int; delete a; //释放单个int的空间 2. 删除数组空间 int *a = new int[5]; delete []a; //释放int数组空间 |
:指针变量名=new 类型标识符: #include <iostream.h> void main() { int *pa; pa=new int; //申请一个int大小的空间 *pa = 100; cout<<"*pa= "<<*pa <<endl; //100 delete pa; pa = NULL; //delete只是删除动态内存单元, 并不会将指针pa本身删除(△那该怎么删除呢?); 根据前人经验, 为避免引入bug, 最好将pa赋值为NULL, 这样pa就不是野指针了 :指针变量名=new 类型标识符(初始值); //因此上述代码等同于: /* int *pa; pa=new int(100); //申请一个int大小的空间 cout<<"*pa= "<<*pa <<endl; //100 delete pa; pa = NULL; */ //_____________________________________________ :指针变量名=new 类型标识符 [内存单元个数]; int *pb; pb=new int[5]; //申请一个数组空间 for(int i=1;i<5;i++) { *(pb+i)=i; } cout<<"*(pb+2)= "<<*(pb+2)<<endl;//2 delete[] pb; //也可以是delete[5] pb; pb = NULL; //_____________________________________________ int (*pc)[3]; //定义了一个指针数组 int j; pc=new int[2][3]; //申请一个二维数组空间 for (i=0;i<2;i++) for(j=0;j<3;j++) *(pc[i]+j)=1; cout<<"*(pc[1]+1)= "<<*(pc[1]+1)<<endl;//1 delete[] pc; //也可以是delete[3] pc; 不可以是delete[2]p[3] pc = NULL; } |
● malloc()/free()与new/delete的区别
malloc/free是C/C++语言的标准库函数,new/delete是C++的运算符 |
● 缓冲区操纵管理(Buffer manipulation function)
常用函数是: memset() ,memcpy() ,memmove(), 使用它们必须在源文件声明区包含头文件string.h, 函数原型分别是: void * memset ( void * ptr, int value, size_t num ); void * memcpy ( void * destination, const void * source, size_t num ); |
● 缓冲区,缓冲器:用于临时存储被写入到文件和从文件读取的数据,并以与接收时不同的速度传输数据. 缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。 ● 用malloc()等函数分配的堆空间就是缓冲区; 声明一个字符数组, 也相当于开辟了一个缓冲区 ● 缓冲区位于内存, 但不确定是在堆区还是在栈区, 例如: //下面分配了一个栈内的缓冲区 void func() { char buffer[1024]; } //下面分配了一个堆内的缓冲区 //下面局部(指针)变量buffer存储在栈上, 由于它是局部变量, 自然存储在栈区; 但这个变量是一个指向分配在堆区的一块内存空间的指针 void func() { char *buffer = malloc(1024); } |
memset() 将内存的前n个字节设置为特定的值 memset()函数原型 void * memset ( void * ptr, int value, size_t num ); 在以ptr为起始地址、长度为num个字节的内存区间内, 把每个字节的值都设值成value。 ptr--要填充的内存块的指针(Pointer to the block of memory to fill)。 value--为要设置的值。参数 value 虽声明为 int,但必须是 unsigned char,所以范围在0 到255 之间。你既可以向 value 传递 int 类型的值,也可以传递 char 类型的值,int 和 char 可以根据 ASCII 码相互转换。 num --为 ptr 的前 num 个字节,size_t 就是unsigned integral type。 返回值--ptr is returned. |
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char str[] = "http://c.biancheng.net"; //字符数组是可以被修改的,字符串是只读的,不能被修改,而 memset() 又必须修改 str,所以不能将 char str[] = "http://c.biancheng.net"; 声明为 char *str = "http://c.biancheng.net";,否则运行时会报错。 memset(str, '-', 7); puts(str); system("pause"); //包含在头文件stdlib.h中, 作用是在命令行上输出"Press any key to exit",等待用户按一个键,然后退出 return EXIT_SUCCESS; //使用这一返回语句需要加头文件stdlib.h, 和return 0一样表示程序无错误退出 } |
memcpy() 复制内存内容 & strcpy() |
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N (10) int main() { char* p1 = "hel\0lo"; char* p2 = (char*)malloc(sizeof(char) * N); char* p3 = (char*)memcpy(p2, p1, N); printf("p2 = %s\np3 = %s\n", p2, p3); char str1[]="hel\0lo"; char str2[40]; strcpy (str2,str1); printf("str2=%s\n",str2); free(p2); p2 = NULL; p3 = NULL; system("pause"); return 0; } |
内存重叠出现的情况 |
char *p = NULL; //也可以先定义一个野指针, 然后在末尾加p=NULL, 这样p就不是一个野指针了 p = (char *)malloc(10); memcpy(p,"1234679",strlen("1246789")); printf("before p = %s/n", p); strcpy(p+1,p);//这里重叠了; 这个时候如果使用strcpy函数则程序会崩溃; 使用memcpy的话程序会等到错误的结果; 原因就是memcpy(),strcpy()这两个函数没有对内存重叠进行处理 printf("after p = %s/n", p); free(p); |
memmove() 复制内存内容(可以处理重叠的内存块) |
#include <stdio.h> #include <stdlib.h> #include <string.h> int main () { char str[] = "memmove can be very useful......"; 个字节"very useful, 目的地是str后的第20*sizeof(char)个字节 puts (str); system("pause"); return 0; } |
(C/C++学习笔记) 十四. 动态分配的更多相关文章
- python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例
python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...
- SharpGL学习笔记(十四) 材质:十二个材质球
材质颜色 OpenGL用材料对光的红.绿.蓝三原色的反射率来近似定义材料的颜色.象光源一样,材料颜色也分成环境.漫反射和镜面反射成分,它们决定了材料对环境光.漫反射光和镜面反射光的反射程度.在进行光照 ...
- 【转】angular学习笔记(十四)-$watch(1)
本篇主要介绍$watch的基本概念: $watch是所有控制器的$scope中内置的方法: $scope.$watch(watchObj,watchCallback,ifDeep) watchObj: ...
- angular学习笔记(十四)-$watch(1)
本篇主要介绍$watch的基本概念: $watch是所有控制器的$scope中内置的方法: $scope.$watch(watchObj,watchCallback,ifDeep) watchObj: ...
- Java学习笔记十四:如何定义Java中的类以及使用对象的属性
如何定义Java中的类以及使用对象的属性 一:类的重要性: 所有Java程序都以类class为组织单元: 二:什么是类: 类是模子,确定对象将会拥有的特征(属性)和行为(方法): 三:类的组成: 属性 ...
- MYSQL进阶学习笔记十四:MySQL 应用程序优化!(视频序号:进阶_32)
知识点十五:MySQL 的应用程序优化(32) 一.访问数据库采用连接池 把连接当做对象或设备,统一放在‘连接池’里.凡是需要访问数据库的地方都从连接池里取连接 二.采用缓存减少对于MySQL的访问: ...
- Swift学习笔记十四:构造(Initialization)
类和结构体在实例创建时,必须为全部存储型属性设置合适的初始值. 存储型属性的值不能处于一个未知的状态. 你能够在构造器中为存储型属性赋初值,也能够在定义属性时为其设置默认值.下面章节 ...
- JavaScript权威设计--Window对象之Iframe(简要学习笔记十四)
1.Window对象属性的文档元素(id) 如果在HTML文档中用id属性来为元素命名,并且如果Window对象没有此名字的属性,Window对象会赋予一个属性,它的名字是id属性的值,而他们的值指向 ...
- Oracle学习笔记十四 内置程序包
扩展数据库的功能 为 PL/SQL 提供对 SQL 功能的访问 用户 SYS 拥有所有程序包 是公有同义词 可以由任何用户访问 一些内置程序包 程序包名称 说明 STANDARD和DBMS_STAND ...
随机推荐
- Educational Codeforces Round 57 (Rated for Div. 2)
我好菜啊. A - Find Divisible 好像没什么可说的. #include<cstdio> #include<cstring> #include<algori ...
- [IDEA插件] - 一个不错的插件
今天看到微信平台一篇推送IDEA插件的文章继而下载了个插件看了下. 名字叫做codehelper.generator codehelper.generator http://plugins.jetbr ...
- python 进程队列
#_*_coding:utf-8_*_ from multiprocessing import Process,Queue import os,time def f(q,n): q.put([n,'h ...
- -bash: brew: command not found
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" ...
- python datetime模块来获取当前的日期和时间
#!/usr/bin/python # -*- coding: UTF- -*- import datetime i = datetime.datetime.now() print ("当前 ...
- 简单了解SQL(结构化查询语言)
简单了解SQL(结构化查询语言) 年10月,美国国家标准学会对SQL进行规范后,以此作为关系式数据库管理系统的标准语言(ANSI X3. 135-1986),1987年得到国际标准组织的支持下成为国际 ...
- 对不队—— Alpha冲刺
第三天 日期:2018/6/18 一. 今日完成任务:会议内容管理部分 冯晓.马思远:会议网站栏目管理开发,博客撰写 王爽.彭辉:参会人员管理开发 吴琼.郝延婷:审稿专家管理开发 1.1会议管理界面 ...
- JS中Ajax的同步和异步
ajax同步 : 意味着此时请求Server后,JS代码不再继续执行,等待Server返回后才继续往下执行. ajax异步 : 意味着此时请求Server后,JS代码继续执行,不管Server什么时候 ...
- USACO 铂金 T1
题意 给出一个数轴,每次可以选择停下并得到当前点的收益,或者继续随机向左右游走,走到边界游戏结束收益为0. 求从每个点出发的最大期望收益.(n<=1e5) 有一个显然的dp方程 这个方程是带环的 ...
- Vladik and Entertaining Flags CodeForces - 811E (并查集,线段树)
用线段树维护每一块左右两侧的并查集, 同色合并时若不连通则连通块数-1, 否则不变 #include <iostream> #include <algorithm> #incl ...