动态内存分配基本使用及常见问题
为什么需要动态内存管理?创建一个数组,我们要为数组指定大小,int arr[10];,这属于静态创建一个数组,数组arr存放在栈上。这样的创建方式有一些局限性,小了呢不够用,大了呢又浪费空间,因此要引入动态内存管理。 动态创建一个数组,不再受元素个数的限制,当元素个数与容量相等时,可以很方便地扩容。 如何动态内存管理,我们来介绍几个函数。 malloc 1void* malloc (size_t size); 参数size为要为空间开辟的字节数,开辟成功后返回值为该空间的首地址,失败则返回NULL.当size为0时,要看编译器如何处理,具体返回什么不确定。 动态开辟内存后,不需要再使用这块空间时,要使用free函数释放内存。,否则会内存泄漏。free释放后这块内存可以再次被分配,但被释放的空间的值没有被改变,它仍然指向相同(无效)的位置。 free专门用来释放动态分配的空间,如果空间为空,不执行任何操作。切记不可以用free来释放静态分配的内存空间。 12345678910111213141516#include <stdio.h>#include<stdlib...
C语言的结构体及内存对齐
结构体基础 结构体就是一些成员的集合,结构体的每一个成员可以是整型、数组、指针、结构体等不同的类型。 下面是一个简单的结构体结构,包含了类型声明struct Stu、成员、结构体变量s1的声明。 123456struct Stu { //类型 //成员 char name[20]; int age; char sex[10];}s1; //结构体变量 我们可以像上面那样声明一个结构体变量,也可以像下面这样单独声明。 1struct Stu s2; struct是结构体关键字,Stu是结构体标志,两者构成了结构体类型。上面的语句表示为struct Stu类型的结构体声明了一个变量s1。下面是对s1的赋值操作,可以在声明结构体变量的时候直接赋值。 1struct Stu s1 = { "panghutx",20,"male" }; 在声明结构体时,我们可以对结构体不完全声明。 12345678910struct{ int a; char b; double c; }...
博客一周年啦
今天是3月29日,博客第一篇博文是在去年3月29日,不知不觉博客已经一年了。 一年前的今天,是大一下返校的前一天,今天,是大二下开学的第五周,一年后的今天,是大三下,不知道是在准备考研还是忙着就业。 一年后的事,一年后再说,活在当下,珍惜现在。突如其来的疫情已经持续三年了,都忘了没有疫情的生活是啥样了,三年多少人因为疫情失去了生命。上周让人悲痛的客机坠毁事件,航班人员全部遇难,向遇难者默哀。真是不知道明天和意外哪个会先来,生命无常,活着就好。 今天早上腾讯云连发了多条消息,原来是学生机和域名都快过期了。学生机是1核2G,每年108,我也不打算续费了。昨天看了橙梓的服务器迁移计划,我又心动了,今天买了五年2核2G4M的服务器,330元,我用处不大,只是觉得挺便宜的,下次续费就是2027年了,这下不用担心到期了。 下午忙活半天把hexo部署到了服务器,这下速度应该快了些,博客至少还能再活五年。五年后,我要发篇博客:博客五周年啦! 五年后的事,五年后再说吧。
常用的字符串处理函数
字符串处理类 strlen 简单介绍 size_t strlen ( const char * str ); Geting string length. 参数:str,返回值:字符串长度 字符串以\0作为结束标志,返回\0之前的字符个数。返回值是size_t(无符号)。 模拟实现 123456789101112131415161718192021222324//方法1:计时器int My_strlen1(char* ps) { int count = 0; while (*ps) { count++; ps++; } return count;}//方法2:指针相减int My_strlen2(char* ps) { char* start = ps; while (*ps) { ps++; } return ps - start;}//方法3:递归int My_strlen3(char* ps) { if (*ps == '\0') return 0; else...
c语言操作符练习总结
sizeof()的坑🕳 123456789101112131415#include <stdio.h>int i;int main(){ i--; if (i > sizeof(i)) { printf(">\n"); } else { printf("<\n"); } return 0; } 观察上端代码,思考一下输出结果是什么? 首先定义了一个全局变量,全局变量没有赋值,默认值为0;然后i–;i变成了-1.你也许会说sizeof(-1),-1是int类型的,占4个字节,-1<4,结果不就是<吗!其实不然,结果是>,-1大于4?数学是体育老师教的! 原因在于sizeof()的返回值是无符号整型,也就是unsigned int,两数比较时,编译器会将左侧的值也转换成无符号整数,-1在内存中存储的是全1,即111111111111111111111111111...
浮点数在内存中的存储
观察下面的代码,输出结果是什么呢? 1234567891011int main(){int n = 9;float *pFloat = (float *)&n;printf("n的值为:%d\n",n);printf("*pFloat的值为:%f\n",*pFloat);*pFloat = 9.0;printf("num的值为:%d\n",n);printf("*pFloat的值为:%f\n",*pFloat);return 0;} 以整数存储,以整数取出,结果相同;以浮点数存储,以浮点数取出,结果也相同。 以整数存储,以浮点数取出,结果不同;以浮点数存储,以整数取出,结果也不同。 由此可见,整数和浮点数在内存中的存储是不同的。 下面我们看一下浮点数的存储规则,浮点数在内存中的表示是由IEEE(电气与电子工程协会)规定好的。 任何一个二进制浮点数,可以表示成 (-1)^S表示符号位,s为0浮点数是正数,s为-1浮点数是负数;M表示有效数字,范围在[1,2);2^E表示指...
倒置字符串,我爱中国,中国爱我。
描述:将一句话的单词进行倒置,标点不倒置。比如 I like China. 经过函数后变为:China. like I 有些时候,主语和宾语位置互换词义不会改变。比如,一件衣服穿两天,两天穿一件衣服。北京是首都,首都是北京。如果你已经读完了这段话,恭喜你已经浪费了几秒钟,这和这道编程题没什么关系…… 思路:我们可以两次使用字符串逆序,第一次先将字符串整体逆序,第二次将单个单词再逆序。逆序字符串,无非是找到字符串的起始位置和结束位置,也就是左下标和右下标,当左下标地址小于右下标地址时,互换两个下标位置的字符串。关键在于寻找起始位置和结束位置,例如字符串arr,第一次字符串整体逆序,起始位置就是字符串的首地址arr,结束位置就是起始位置+字符串长度-1.第二次逆序每个单词,起始位置就是每个单词的起始位置,结束位置是空格或字符串0的前一位置。逆序每个单词要注意何时进行逆序,遍历整个字符串,当arr[i]的元素为空格或字符串0时,进行单词的逆序。 1234567891011121314151617181920212223242526272829303132333435#include&l...
多种方法求两个正整数的最大公约数和最小公倍数
鲁迅说过:“求解最大公约数和最小公倍数有很多方法”,公约数,就是几个数共有的约数,最大公约数,就是公约数中最大的那个数,公倍数,就是几个数共有的倍数,最小公倍数,就是公倍数中最小的那个数。虽然看起来是句废话,其实它就是废话……下面我们看一下求解最大公约数和最小公倍数的几种方法。 求任意两个正整数的最大公约数 最大公约数(Greatest Common Divisor,GCD),先说约数,a能被b整除,b就是a的约数,几个数共有的约数就是这几个数的公约数,公约数中最大的那个数就是最大公约数。举个例子,4和20的公约数有1,2,4,最大公约数是4。可见两个数的最大公约数必不大于两数中最小的那个。 思路一:如果求出最大公约数,穷举法从小到大(从1到两数中较小的一个)遍历,然后输出最大的那个,这样做比较麻烦,不妨我们从大到小(从两数中较小的一个到1)遍历,第一个能同时整除两个数的那个即为所求。 123456789101112131415161718192021222324int main(){ int a = 0; int b = 0; int tmp = 0; int i ...
Visual Studio环境下一段有趣的代码
1234567891011int main(){ int i = 0; int arr[10] = { 0 }; for (i = 0; i <= 12; i++) { arr[i] = 0; printf("youngsay.cn\n"); } return 0;} 观察这段代码,运行会有何效果? 你可能会说,既然越界访问了,那不就报错了?其实不然,运行发现,程序没有报错,一直死循环。 注意:该段代码依赖环境,vs编译器,debug模式,x86平台下才有这样的效果。 为什么陷入了死循环,这要从栈区的使用习惯开始说起。静态变量,函数形参都存放到栈中,而栈是从高地址开始存放。**栈区的使用习惯是先使用高地址处的空间。**我们还知道,**数组随着下标变大,地址是由低到高变化的。**所以上段代码在栈中的内存布局,如下图所示。 vs编译器,debug模式,x86平台下,i和数组arr间刚好空了2个下标的空间。所以i和arr[12]指向了同一块地址,不信我们可以调试看一下i和arr[12]的地址。...
C语言实现简单的扫雷游戏
《扫雷》是一款大众类的益智小游戏,游戏目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。 这篇博客教大家用C语言制作一个简易版扫雷游戏,和之前的井字棋大同小异。 我们准备三个文件,分别为game.c,test.c,game.h game.c文件用来写实现游戏功能的各个函数代码,test.c文件写游戏的总流程,game.h文件用来声明函数和初始值. 先看test.c,由menu()``game()``main()三个函数组成。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include"game.h"menu(){ printf("--------------------\n"); printf("-----1.开始游戏-----\n"); printf("-----2.退出游戏-----\n"); p...