1.3动态内存分配 字符串
1.3.1几个内存区域
1.栈区(stack)
windows下,栈内存分配2M(确定的常数),超出了限制,提示stackoverflow错误
自动分配,释放
2.堆区(heap)
程序员手动分配释放,操作系统80%内存
3.全局区或静态区
4.字符常量区
5.程序代码区
1.3.2 动态分配内存
方法:void *malloc(unsigned size);
在堆内存开辟一定大小的内存.
参数列表: 内存大小单位是字节
返回值: 堆内存指针
方法: void free(void *ptr);
动态释放内存
参数列表: 堆内存指针
创建动态数组示例:
创建一个数组,动态指定数组的大小
(在程序运行过长中,可以随意的开辟指定大小的内存,以供使用,相当于Java中的集合)
void main(){ //静态内存分配创建数组,数组的大小必须是固定的,也就是说数组大小必须是常量 //int i = 10; //int a[i]; int len; printf("输入数组的长度:"); scanf("%d",&len); //开辟内存,大小len*4字节 int* p = malloc(len * sizeof(int)); //p是数组的首地址,p就是数组的名称(数组就是连续的内存区域) //给数组元素赋值(使用这一块刚刚开辟出来的内存区域) int i = 0; for (; i < len - 1; i++){ p[i] = rand() % 100; printf("%d,%#x\n", p[i], &p[i]); }
//手动释放内存 free(p); getchar(); } |
1.3.3 静态内存分配与动态内存分配
静态内存分配,分配内存大小的是固定,问题:1.很容易超出栈内存的最大值2.为了防止内存不够用会开辟更多的内存,容易浪费内存
动态内存分配,在程序运行过程中,动态指定需要使用的内存大小,手动释放,释放之后这些内存还可以被重新使用(活水)
方法 void *realloc(void *ptr, unsignednewsize);
对ptr地址的内存区域重新分配空间,
参数列表: 1.原来内存的指针 2.内存扩大之后的总大小
返回值: 重新分配后的内存区域的指针
重新分配内存的几种情况:
缩小,缩小的那一部分数据会丢失
扩大,(连续的)
1.如果当前内存段后面有需要的内存空间,直接扩展这段内存空间,realloc返回原指针
2.如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的内存区域释放掉,返回新的内存地址
3.如果申请失败,返回NULL,原来的指针仍然有效
重新分配内存示例:
void main(){ int len; printf("第一次输入数组的长度:"); scanf("%d", &len); int* p = malloc(len * sizeof(int)); int i = 0; for (; i < len; i++){ p[i] = rand() % 100; printf("%d,%#x\n", p[i], &p[i]); } int addLen; printf("输入数组增加的长度:"); scanf("%d", &addLen); //1.原来内存的指针 2.内存扩大之后的总大小 int* p2 = realloc(p, sizeof(int) * (len + addLen)); if (p2 == NULL){ printf("重新分配失败,世界那么大,容不下我。。。"); } //重新赋值 i = 0; printf("--------------------------\n"); for (; i < len + addLen; i++){ p2[i] = rand() % 200; printf("%d,%#x\n", p2[i], &p2[i]); } //手动释放内存 if (p != NULL){ free(p); p = NULL; } if (p2 != NULL){ free(p2); p2 = NULL; } getchar(); } |
1.3.4动态内存分配注意事项
1.不能多次释放
2.释放完之后(指针仍然存储有地址值),给指针置NULL,标志释放完成
3.内存泄露
p重新赋值之后,再free,并没有真正释放内存,正确的做法是重新赋值前先free
//错误写法 void main(){ //40M int* p1 = malloc(1024 * 1024 * 10 * sizeof(int)); //80M p1 = malloc(1024 * 1024 * 10 * sizeof(int) * 2); free(p1); p1 = NULL; getchar(); } //正确写法 void main(){ //40M int* p1 = malloc(1024 * 1024 * 10 * sizeof(int)); free(p1);//重新赋值前先释放 p1 = NULL; printf("%#x\n",p1); //80M p1 = malloc(1024 * 1024 * 10 * sizeof(int) * 2); free(p1); p1 = NULL; getchar(); } |
1.3.5字符串
字符串的几种表示方法
1) 使用字符数组表示字符串
char str[] = {'c','h','i','n','a','\0'}; //如果末尾没有’\0’,控制台会输出乱码
char str[6] = { 'c', 'h', 'i', 'n', 'a' };
注意: ’\0’表示结束符,不指定数组长度时需要末尾加上’\0’结束符;
指定字符数组长度且数组长度大于需要存储的字符个数,可以不加结束符;
还可以使用下面的表示方法:
char str3[] ="hahakkk";
2) 字符指针表示字符串
char *str = "how are you?";
两种表示方法有什么不同呢?
字符数组赋值只能在声明的时候赋值
字符数组表示字符串可以修改字符串,字符指针表示字符串不可以修改
字符串在线API网址:
http://www.kuqin.com/clib/string/strcpy.html
关于字符串与字符数组的区别请参考博客文章
http://blog.csdn.net/coderlei/article/details/79269038
函数名: stpcpy
用法:char *stpcpy(char *dest,char *src);
功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest结尾处字符(NULL)的指针。
举例:
#include <stdio.h> #include <string.h> int main(void) { char string[10]; char *str1 = "abcdefghi"; stpcpy(string, str1); printf("%sn", string); return 0; }
函数名: strcat
功 能: 字符串拼接函数
用 法: char*strcat(char *destin, char *source);
程序例:
#include <string.h> #include <stdio.h> int main(void) { char destination[25]; char *blank = " ", *c = "C++", *Borland = "Borland"; strcpy(destination, Borland); strcat(destination, blank); strcat(destination, c); printf("%sn", destination); return 0; } |