极品wordpress素材教程网站,网站建设教程 项目式,二手车网站建设论文,网站建设的流程 步骤目录 C内存分布
变量的四种存储方式
函数返回值使用指针(指针函数)
动态分配内存空间
不能使用外部函数的普通局部变量的地址
通过指针函数返回静态局部变量的地址
动态内存
根据需要分配内存,不浪费(根据用户的需求设置内存的容量)
被调用函数之外需要使用被调用函数内…目录 C内存分布
变量的四种存储方式
函数返回值使用指针(指针函数)
动态分配内存空间
不能使用外部函数的普通局部变量的地址
通过指针函数返回静态局部变量的地址
动态内存
根据需要分配内存,不浪费(根据用户的需求设置内存的容量)
被调用函数之外需要使用被调用函数内部的指针对应的地址空间
补充:指针函数和函数指针不同(详细例子请看第四站,函数指针):
突破栈区限制,可以给程序分配更多内存
动态内存的分配使用和释放
new 和 delete 运算符使用的一般格式为
内存泄漏
当忘记释放内存 当开启释放内存 内存检查工具
VS自带的
内存泄漏工具 C内存分布
1、栈区stack由编译器自动分配释放存放函数的参数值局部变量值等。
2、堆区heap一般由程序员分配释放随叫随到挥之即走(动态内存)。
3、全局/静态区static全局变量和静态变量的存储是放在一起的在程序编译时分配。
4、文字常量区存放常量字符串。
5、程序代码区存放函数体包括类的成员函数、全局函数的二进制代码 变量的四种存储方式
分别为自动变量auto、寄存器变量register . 静态变量 static、外部变量extern)。 auto - 函数中所有的非静态的局部变量。(auto一般省略(c11以上不用写auto会报错,因为内部已经含有))
register - 一般经常被使用的的变量如某一变量需要计算几千次可以设 置成寄存器变量register 变量会被存储在寄存器中计算速度远快于存在内存 中的非 register 变量。
C 的 register 关键字已经优化如果我们打印它的地址它就变成了普通的 auto 变量
static - 在变量前加上 static 关键字的变量。
extern - 把全局变量在其他源文件中,声明成 extern 变量可以扩展该全局变量的作用域至声明的那个文件其本质作用就是对全局变量作用域的扩展。 #include iostreamusing namespace std;
//外部变量,可以用本文件其他源文件中的全局变量
extern int extern_a;//这里不能再给这个外部变量赋值//静态全局变量
static int c 18;//寄存器变量
void register_demo() {register int i 1;//寄存器变量本身没有地址// C 的 register 关键字已经优化如果我们打印它的地址它就变成了//普通的 auto 变量cout 寄存器变量i的地址值: i endl;
}
//静态局部变量
void static_demo() {//静态变量,只会初始化一次,也就是这条语句只会执行一次,//被static的变量值,在函数体执行完后不会释放,下次执行改函数体,//这个变量可以用上一次执行函数体的值static int a 18;int b 18;a;b;c;cout a作为静态局部变量的值: a endl;cout c作为静态全局变量的值: c endl;cout b作为局部变量auto的值: b endl;
}
void extern_demo() {extern_a;cout 外部变量的值: extern_a endl;
}
int main(void) {int i 18;//c语言可以写上auto也不会报错,但是c做了升级写了auto会报错cout 局部变量的值: i endl;cout endl;register_demo();cout endl;for (int i 0; i 3; i) {static_demo();cout endl;}cout endl;extern_demo();
}
函数返回值使用指针(指针函数)
可以返回函数内部动态分配内存地址 局部静态变量地址 以及全局静态变量和外部变量 地址
动态分配内存空间
#include iostream
#include stdlib.h
using namespace std;//返回动态内存分配地址
int* add1(int x, int y)
{int* sum NULL;sum new int;*sum x y;return sum;
}
int main()
{int a 3, b 5;int* sum NULL;//接收外部函数动态内存分配的地址 oksum add1(a, b);cout*sumendl;delete sum;system(pause);return 0;
}
不能使用外部函数的普通局部变量的地址
(普通局部变量的值在函数调用结束后值会释放)
(这样是错误的 vs版本升级后,这种写法会触发断点,但是以前的不会),但是依然会运行出结果,这种结果会被栈空间覆盖掉(如果后面有其他函数用到这片空间)那么这个函数所运行的结果也会被后来的函数值覆盖掉,运行出来的值并不正确 #include iostream
#include stdlib.h
using namespace std;int* add(int x, int y) {int sum x y;return sum;
}//程序动态动态分配一块内存空间,这片空间会覆盖在上面函数在调用结束后,释放的空间之上
int* add1(int x, int y)
{int* sum NULL;sum new int;*sum x y;return sum;
}
int main()
{int a 3, b 5;int* sum NULL;//不能使用外部函数局部变量的地址(这样是错误的)sum add(a, b);//如果再输出这个外部函数局部变量的值之前,调用一片由程序员动态分配内存的指针函数,那么这片申 //请的内存空间会覆盖掉上面函数的之前使用的空间,add1(a,b);cout*sumendl;//这里输出的值就会受到上面这个函数的影响从而返回错误的值delete sum;system(pause);return 0;
}
通过指针函数返回静态局部变量的地址
:这种方法是可以的,不同于上面这种普通局部变量,静态变量的特点:(只会初始化一次,但是当函数调用结束后,运行出来的值并不会释放) #include iostream
#include stdlib.h
using namespace std;//通过指针函数返回静态局部变量的地址
int* add(int x, int y)
{static int sum 0;//静态变量的值不会因为函数调用结束而释放cout 函数内部的值: sum endl;sum x y;return sum;
}int main()
{int a 3, b 5;int* sum NULL;sum add(a, b);cout 第一次调用静态后的函数值: *sum endl;*sum 8888;sum add(a, b);cout 第二次调用静态后的函数值: *sum endl;return 0;
}
动态内存 根据需要分配内存,不浪费(根据用户的需求设置内存的容量) #include iostreamusing namespace std;int main(void) {int a[] { 11,2,34,12,18,19,17,10 };int len sizeof(a) / sizeof(a[0]);int num 0;//1.按需分配根据需要分配内存不浪费int* salary NULL;cout 请输入内存数: endl;cin num;//判断输入的数是否大于数组的长度,不大于则输入不合法//需要按需分配内存,就得大于本来数组的长度if (num len) {cout 输入数字不合法!.. endl;}//第一种:使用指针形式逐个赋值salary new int[num];for (int i 0; i len; i) {*(salary i) a[i];}//将多出a数组的值,赋值为18for (int i len; i num; i){*(salary i) 18;}for (int i 0; i num; i) {cout 输出第 i 1 的值为: *(salary i)endl;}cout endl;//第二种:使用内存拷贝函数,c提供//从源 a 所指的内存地址的起始位置开始拷贝 len 个字节到目标 salary 所指的//内存地址的起始位置中memcpy(salary, a, len);for (int i len; i num; i) {*(salary i) 18;}for (int i 0; i num; i) {cout 输出第 i 1 的值为: *(salary i)endl;}delete[] salary;
} void *memcpy(void *dest, const void *src, size_t n); #include string
功能从源 src 所指的内存地址的起始位置开始拷贝 n 个字节到目标 dest 所指的 内存地址的起始位置中
被调用函数之外需要使用被调用函数内部的指针对应的地址空间 #include iostreamusing namespace std;
/*
2.被调用函数之外需要使用被调用函数内部的指针对应的地址空间*/
//指针函数返回动态内存
int* demo(int count) {int* pointer NULL;//通过c的方式申请内存空间pointer new int[count];//通过c语言的方式申请内存空间//pointer (int*)malloc(sizeof(int) * count);for (int i 0; i count; i) {*(pointer i) 100 i;}for (int i 0; i count; i) {cout 通过指针函数返回的值 *(pointer i) endl;}return pointer;
}
//通过二级指针
void demo1(int count, int** pointer1) {int* ap NULL;*pointer1 new int[count];ap *pointer1;for (int i 0; i count; i) {*(ap i) 100 i;}for (int i 0; i count; i) {cout 通过二级指针返回的值 *(ap i) endl;}}
int main(void) {int* pointer1 NULL;int count 10;//cout 通过指针函数调用返回的值: endl;//pointer1 demo(count);//cout endl;//for (int i 0; i count; i){// cout 通过指针函数调用返回的值: *(pointer1 i) endl;//}cout 通过二级指针调用返回的值: endl;demo1(count, pointer1);cout endl;for (int i 0; i count; i) {cout 通过二级指针调用返回的值: *(pointer1 i) endl;}delete pointer1;//要释放内存return 0;
}
补充:指针函数和函数指针不同(详细例子请看第四站,函数指针):
函数指针是指向函数的指针变量用于存储和调用函数。 指针函数是返回值为指针类型的函数用于返回不同的指针值或函数指针。 函数指针可以作为一个指针类型,成为指针函数的类型,
突破栈区限制,可以给程序分配更多内存
函数分配的栈空间大小一般都有限制,Windows一般为1-2M,但是可以使用动态内存分配,给函数分配更多的内存空间(也不能太大,程序员动态分配的内存空间大小一般为2个G左右,也就是堆空间大小为2G左右)一个函数可供分配就1G左右,当写到第三的时候就会出现运行出错
#include iostreamusing namespace std;
/*
3.突破栈区限制,可以给程序分配更多内存*/
void demo() {int* ap NULL;ap new int[1024 * 1024*1000*1.02];//1个G是能分配的,但是当到达1.03G就会报错
}
void demo1() {int* ap NULL;ap new int[1024 * 1024 * 1000 * 1.02];//1个G是能分配的,但是当到达1.03G就会报错}int main(void) {demo();demo1();return 0;
} 当分配三个时候:程序报错bad_alloc,这个就是动态内存溢出的意思
动态内存的分配使用和释放
在 C 语言中是利用库函数 malloc 和 free 来 分配和撤销内存空间的。C提供了较简便而功能较强的运算符 new 和 delete 来 取代 malloc 和 free 函数。(支持互相混合使用的)
(注意 new 和 delete 是运算符不是函数因此执行效率高。)
new 和 delete 运算符使用的一般格式为 new 运算符 动态分配堆内存 使用方法
指针变量 new 类型(常量;//常量可缺省
指针变量 new 类型[表达式]; //数组
指针变量 new 类型[表达式][表达式] //二维数组
delete 运算符 释放已分配的内存空间 使用方式其中“指针变量” 必须时一个 new 返回的指针
普通类型非数组使用: delete 指针变量
数组 使用: delete[] 指针变量
#include iostreamusing namespace std;int main(void) {//第一种分配动态内存不执行初始化int* p1 new int;*p1 100;//第二种分配动态内存同时执行初始化int* p2 new int(100);// 第三种 malloc 返回值是 void *int* p3 (int*)malloc(sizeof(int));free(p1); //基础类型可以 new free 可以混搭delete p3; //基础类型可以 malloc delete 可以混搭delete p2; //free(p2); 同样效果int **p4 new int*[1];free(p4);return 0;
}
内存泄漏
在企业开发中,一个项目往往需要一天24小时不断运行,如果忘记内存释放,程序内存就会一直运行,造成系统内存的浪费导致程序运行速度减慢甚至系统崩溃等严重后果。
当忘记释放内存 #include iostream
#include Windows.h
using namespace std;//用来记录没有释放内存的
void demo() {int* p1 NULL;p1 new int[1024*10];p1[0] 1;
}
int main(void) {for (int i 0; i 102400; i){//便于观察内存泄漏情况demo();Sleep(5);}return 0;
} 当开启释放内存 #include iostream
#include Windows.h
using namespace std;void demo1() {int* p1 NULL;p1 new int[1024*10];p1[0] 0;delete[] p1;
}
int main(void) {for (int i 0; i 102400; i){//便于观察内存泄漏情况demo1();Sleep(5);}return 0;
} 内存检查工具
VS自带的
VisualC debugger 和 CRT 库
第一步 包含以下头文件 :debug需要在debug模式下调试才能看到内存泄漏的信息
#define _CRTDBG_MAP_ALLOC
#include stdlib.h #include crtdbg.h
第二步 接管 new 操作符
#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ ,__LINE__)
#define new DBG_NEW
#endif
#endif
第三步 在代码结束出输出内存泄漏信息
_CrtDumpMemoryLeaks(); #include iostream
#include Windows.h
#include stdlib.h
#include crtdbg.h
#define _CRTDBG_MAP_ALLOC_
using namespace std;#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ ,__LINE__)
#define new DBG_NEW
#endif
#endif
//用来记录没有释放内存的
void demo() {int* p1 NULL;p1 new int[1024 * 100];p1[0] 1;
}
int main(void) {for (int i 0; i 5; i) {//便于观察内存泄漏情况demo();Sleep(5);}_CrtDumpMemoryLeaks();return 0;
}
内存泄漏工具
内存泄漏工具 Windows : Purify,BoundsCheaker、Deleaker、VisualLeak DetectorVLD, Linux 平台Valgrind memcheck