当前位置: 首页 > news >正文

邢台做网站企业wordpress widgets

邢台做网站企业,wordpress widgets,织梦搞笑图片网站源码,51我们一起做网站1 为什么要有动态内存开辟 int a 10; int arr[10] { 0 }; 上述定义了一个整型#xff0c;开辟了4个字节#xff0c;定义了一个整型数组#xff0c;开辟了40个字节#xff0c;但是是固定开辟的#xff0c;面对灵活多变的实际问题的时候可能就有点鸡肋#xff0c;这种开…1 为什么要有动态内存开辟 int a 10; int arr[10] { 0 }; 上述定义了一个整型开辟了4个字节定义了一个整型数组开辟了40个字节但是是固定开辟的面对灵活多变的实际问题的时候可能就有点鸡肋这种开辟空间的特点是 i) 开辟好空间之后不能改变 ii) 开辟的空间大小是固定的 那么为了解决实际问题就引入了动态内存开辟可以根据实际需要进行内存开辟。 那么引用了4个函数分别是malloc calloc free realloc而动态开辟函数开辟的空间都是在堆区开辟的不是栈区 2 malloc函数的使用 void* malloc (size_t size); 这是malloc函数的原型需要引用的头文件是stdlib返回的是void*指针返回void*指针的原因是因为实际工作中开辟的空间类型是根据实际需要确定的所以开辟好空间之后需要进行强制类型转化开辟空间的单位是字节参数表示的是开辟多少个字节最后返回的地址是开辟的字节的首地址。 那么开辟空间的话也是分为是否开辟成功的如果开辟成功了返回的就是那块空间的首地址如果开辟失败了返回的就是空指针比如我开辟几百亿个字节一般情况下返回的就是NULL所以我们用指针接收了地址后第一件事就是判断一下是不是空指针不然是会有警告的。 这是正常使用的情况那如果size_ t size是0呢这时候malloc的行为标准是未定义的操作就取决于编译器了。 代码1 int main() {int* p (int*)malloc(40);assert(p);for (int i 0; i 10; i){*p i;p;} for (int i 0; i 10; i){printf(%d , *(p i));}return 0; } 问运行结果是什么 答案是报错你可以把内存开辟的返回的地址理解成数组名数组名哪里能自增自减呢理解成数组名的缘由是因为free动态内存函数开辟了空间之后使用完空间是要被释放的而free的参数是开辟的空间的首地址所以p不能自增自减。防止后面释放空间释放错了。 3 free函数的使用 上面提到了返回的地址不能自增自减因为free( 头文件依然是stdlib)要出场了free免费释放在C语言里面就是专门用来释放动态内存开辟的空间的当使用完之后都是要free的。 int main() {int* p (int*)malloc(40);assert(p);for (int i 0; i 10; i){*(p i) i;} for (int i 0; i 10; i){printf(%d , *(p i));}free(p);p NULL;return 0; } free的参数是动态内存开辟的地址可能让人疑问的点就是为什么最后要给一个NULL这是因为我们传的是值不是地址free的形参是值所以释放空间的时候那块空间确实是释放了没错但是p还仍然保留着原来的数据所以需要手动置为空指针。 使用free的时候需要注意的 ·free的参数一定是动态开辟的地址如果不是那么free的行为是未定义的 ·free的参数如果是NULL那么该函数什么事都不做 4 calloc函数的使用 void* calloc (size_t num, size_t size); calloc函数的原型如上头文件依然是stdlib作用是开辟num个大小为size字节的空间它和malloc是极其相似的唯一的不同就是calloc会自动初始化空间为0malloc函数则不会初始化 举个例子 int main() {int* p (int*)calloc(10, sizeof(int));assert(p);for (int i 0; i 10; i){printf(%d , *(p i));}free(p);p NULL;return 0; } 最后的运行结果应该全是0。 5 realloc函数的使用 realloc函数才是动态内存开辟函数的老大因为点啥呢因为它可以扩大空间比如你写代码到一半发现空间不够了这时候就需要realloc函数来操作了它可以扩大空间 void* realloc (void* ptr, size_t size); realloc函数的原型如上头文件依然是stdlib第一个参数一般都是动态开辟的地址第二个是表示扩大到多少字节所以一般情况下使用该函数之前一般都是已经动态开辟了空间的那么什么是特殊情况呢 如下 int main() {int* p (int*)realloc(NULL, 40);assert(p);for (int i 0; i 10; i) {*(p i) i;}for (int i 0; i 10; i){printf(%d , *(p i));}free(p);p NULL;return 0; } 这种情况realloc函数就是malloc函数也就是说如果realloc函数的第一个参数是空指针的话那么就是从内存中随机开辟空间此时的realloc函数就是malloc函数。 那么realloc函数一般用法就是用来扩大空间的如果你想实验一下缩短空间也是可以试试的只不过这个时候realloc函数的行为是未定义的。 realloc函数扩大空间有两种情况 1 原地址的后面有足够的空间用于扩容  2 原地址的后面没有足够的空间用于扩容 第一种情况没什么好说的原有空间变大而已第二种情况realloc会在堆区重新找一个符合需要的空间如果没有找到就会返回空指针如果找到了那么原有的数据会赋值到新空间且原有空间会被释放所以realloc函数开辟完空间之后如果是重新找空间开辟的就会释放原来的空间那么实际写代码的时候我们就会重新用一个指针来接收新空间判断完是不是空指针后再决定要不要赋给原来的地址 realloc函数和其他函数最不一样的地方就是在于它会自己释放空间这点需要注意realloc函数举个例子   int main() {int* p (int*)calloc(25, sizeof(int));assert(p);int* pa realloc(p, 20 * sizeof(int));//两种情况 所以用另一个指针接收assert(pa);if (pa ! NULL){p pa;}free(*p);free(*pa);p NULL;pa NULL;return 0; } Tips所有动态内存开辟的空间是不会自己释放的释放的空间都是需要自己释放的要么就是程序结束由操作系统来释放。 int* Test() {int* p *(int*)malloc(40);return p; } int main() {//操作return 0; }这样的p只要不释放空间都是可以使用的。 6 常见的动态内存开辟的错误 1对空指针的解引用 //对空指针的解引用 int main() {int* p (int*)malloc(INT_MAX * INT_MAX);;*p 20;free(p);p NULL;return 0; } 这里内存是开辟不了这么多的空间的所以p是空指针那么解引用之后自然就会报错 2对动态内存开辟空间的越界访问 //对动态内存开辟空间的越界访问 int main() {int* p (int*)calloc(10, sizeof(int));assert(p);for (int i 0; i 10; i){*(p i) i;} for (int i 0; i 10; i){printf(%d , *(p i));}free(p);p NULL;return 0; }我们使用了calloc函数开辟了10个整型空间使用的时候循环次数是11次那么最后一次循环就会越界访问到未开辟的空间系统就会报错。3)  对非动态内存开辟的空间释放 //对非动态开辟的空间进行释放 int main() {int a 10;int* pa a;free(pa);pa NULL;return 0; } 前面提到free函数只能释放动态内存开辟的空间因为局部变量 全局变量是在栈区 静态区的而free适用于堆区的动态内存开辟所以使用free释放非动态内存开辟的空间的时候系统就会报错。 4free释放一部分动态内存开辟的空间 //使用free释放一部分动态内存开辟的空间 int main() {int* p (int*)malloc(10 * sizeof(int));assert(p);p;free(p);p NULL;return 0; } 前面提及我们可以把动态内存开辟返回的地址当作数组名这样可以避免我们给该地址自增自减因为free释放都是释放的一整块空间那么自增之后free的参数不是起始地址就会导致释放过多也会导致越界访问系统就会报错。 5对同一块空间多次释放 //对同一块空间多次释放 int main() {int* p (int*)calloc(10, sizeof(int));assert(p);/* 操作*/free(p);//p NULL;/*操作*/free(p);p NULL;return 0; } 对同一块空间多次释放后free再去访问那个地址 自然就会报错但是如果前面释放了空间之后并且置于0是没有问题的因为free的参数如果是空指针的话就不会有任何行为。 6动态内存开辟的空间未释放 //动态内存开辟的空间未释放 int main() {int* p (int*)malloc(40);/*操作*/return 0; } 如果开辟的空间没有进行释放那么内存中这块空间的状态就是一直被占用的情况就会导致内存泄露假如这种情况多了的话说不定某一天你的系统内存就被占满了然后你一重启就会发现欸对了所以动态内存开辟的空间一定要正确释放。 7 动态内存开辟函数题目解析 代码1 void GetMemory(char* p) {p (char*)malloc(100); } int main() {char* str NULL;Getmemory(str);strcpy(str, hello world);printf(str);return 0; } 程序运行到strcpy的时候就会报错最开始str是空指针那么这里的传参方式是传值调用所以即使p的地址已经指向了malloc开辟的100字节str仍然是空指针还有一个问题是出了函数GeiMemory的时候p就会被销毁了也会导致内存泄漏并且打印出错 Tipsprintf这里是没有问题的可以自行实验一下,比如pirntf(abcdefg\n); 实际上传的也是该字符串的地址。 void GetMemory(char** p) {*p (char*)malloc(100); } int main() {char* str NULL;GetMemory(str);strcpy(str, hello world);printf(str);free(str);str NULL;return 0; } 这是修正后的代码。 代码2 char* GetMemory() {char p[] Hello world;return p; } int main() {char* str NULL;str GetMemory();printf(str);return 0; } 如果经过调试我们会发现str指向的确实是常量字符串的地址实际打印的效果却是一串乱码其实这是因为出了Getmemory函数的作用域导致常量字符串被销毁但是返回的地址是没问题的是数据没了此时的p就是野指针了。 修改的方式也很简单只需要加一个static就行了。 char* GetMemory() {static char p[] Hello world;return p; } int main() {char* str NULL;str GetMemory();printf(str);return 0; } 代码3 void Getmemory(char** p, size_t num) {*p (char*)malloc(num); } int main() {char* str NULL;Getmemory(str, 100);strcpy(str, hello);printf(str);return 0; } 程序看起来是没有问题的确实是打印了hello,但是还是存在问题内存泄漏没有释放空间。 代码4 int main() {char* str (char*)malloc(100);assert(str);strcpy(str, hello);free(str);if (str ! NULL);{strcpy(str, world);printf(str);}return 0; } 这串代码的运行结果是打印world虽然free了动态开辟的空间但是str仍然指向了那块空间str先是赋值了hello然后判断不是空指针再次复制了world所以最后的结果是world这个str就是野指针了虽然运行结果是对的但是程序仍然是有问题的。 8 柔性数组 在C99标准中允许柔性数组的存在比如 struct St {int i;int arr[0]; };其中arr就是柔性数组但有的编译器可能无法通过所以有时候0是没有加的。 柔性数组的特点是 i柔性数组一定是最后一个成员 iisizeof计算大小的时候不包括柔性数组的大小 iii使用malloc的时候开辟的空间应该大于结构体前面成员大小的总和以此来符合预期 int main() {struct St{char i;int j;int arr[0];};printf(%zd\n,sizeof(struct St));return 0; } 结合内存对齐柔性数组的特点最后的结果是8。 柔性数组的使用 struct St {char i;int j;int arr[0]; }; int main() {struct St* ps (struct St*)malloc(sizeof(struct St) 10 * sizeof(int));assert(ps);ps-i w;ps-j 520;//使用柔性数组for (int m 0; m 10; m){ps-arr[m] m;}//空间不够struct St* pt (struct St*)realloc(ps,sizeof(struct St) 15 * sizeof(int));assert(pt);ps pt;printf(%c\n, ps-i);printf(%d\n, ps-j);for (int n 10; n 15; n){ps-arr[n] n;}for (int m 0; m 15; m){printf(%d , ps-arr[m]);}free(pt);ps NULL;pt NULL;return 0; } 常规结构体在栈区开辟的空间有了柔性数组我们就需要用到malloc函数那么结构体就是在堆区开辟的空间在使用的时候需要注意最后释放只需要释放一个指针因为realloc函数是会自己释放上一块空间的在开辟空间的时候 struct St* ps (struct St*)malloc(sizeof(struct St) 10 * sizeof(int)); 这种写法是为了更直观的看到开辟的空间比整个结构体都大这样柔性数组才有自己的空间 那么还有一种模拟柔性数组的写法如下   struct St {char i;int j;int* arr; }; int main() {struct St* ps (struct St*)malloc(sizeof(struct St));assert(ps);ps-i w;ps-j 520;ps-arr (int*)malloc(10*sizeof(int));assert(ps-arr);//使用柔性数组for (int i 0; i 10; i){*(ps-arr i) i;}//空间不够int* pt (int*)realloc(ps-arr,15 * sizeof(int));assert(pt);ps-arr pt;printf(%c\n, ps-i);printf(%d\n, ps-j);for (int n 10; n 15; n){*(ps-arr n) n;}for (int m 0,n 0; m 15; m,n){printf(%d ,*(ps-arr m));}free(pt);free(ps);ps-arr NULL;pt NULL;ps NULL;return 0; } 结构体的最后一个成员是int*,也可以是其他类型的指针这种写法是先为结构体的其他成员开辟空间再给int*开一个单间需要用的时候给个malloc空间不够给个realloc这样的话也是类似于柔性数组的它与上面的写法不同的是多次开辟空间多次释放略显繁琐但是访问速度快点上面的优点就是内存方便释放两种写法各有优势。 感谢阅读
http://www.w-s-a.com/news/372410/

相关文章:

  • 前端如何优化网站性能大学学校类网站设计
  • 中国铁路建设投资公司网站熊学军中国it外包公司排名前50
  • 房产网站的建设广州推广排名
  • 湟源县网站建设wordpress删除未分类
  • 营销型网站开发推广厦门百度seo公司
  • 遵义网站开发培训上海中高风险地区名单最新
  • 禹州市门户网站建设做网站可以申请个体户么
  • 大良营销网站建设效果彩票网站搭建 做网站
  • 做网站的公司为什么人少了在中国如何推广外贸平台
  • 盘锦网站制作工业电商网站怎么配色
  • 白云企业网站建设seo排名点击软件
  • wordpress跨站脚本攻击漏洞国外注册的域名国内能用吗
  • 西部数码网站管理助手2工信部资质查询网站
  • 公司网站哪个建的好吉林网站制作
  • 视频网站怎么引流wordpress私人玩物
  • 我的家乡湛江网站设计新钥匙网站建设
  • 辽宁网站推广爱前端wordpress5.0.3主题
  • python怎么做网站贵阳网站制作
  • 深圳网站的优化seo网络推广有哪些
  • 网站建设实习报告范文荆州市城市建设档案馆网站
  • 网站开发信息平台项目总结企业网站如何推广
  • 网站备案名称规定手机免费h5制作软件
  • 接网站建设单子的网站网页设计尺寸多大
  • 订制型网站费用做网站的问题
  • 淮阳住房和城乡建设网站桂林新闻桂林人论坛
  • 公司网站建设价格标准老版本网站开发工具
  • 门户网站开发费怎做账做网站交互demo工具
  • 中山最好的网站建设黄村网站建设价格
  • 企业网站首页应如何布局互联网营销师证书报名入口
  • 绍兴做网站哪家好篮球网站设计