一. 内存存储区的划分:
1.栈区:栈区主要存放函数内部定义的变量,数组.函数调用时,开辟空间,函数执行完毕,回收空间,空间的开辟与回收有系统管理.
2.堆区:堆区最大的特点:空间的开辟与释放有开发人员手动管理.
3.全局区静态区:主要存放函数外部定义的全局变量以及静态变量,空间一旦开辟,就不会回收.直到应用程序执行结束.
4.常量区:存储常量.1.整形常量.2.浮点型常量.3,字符串常量.4.字符串常量.
5.代码区:存放程序编译之后生成的cpu指令.
二.malloc,在堆区开辟空间.
//在堆区开辟空间. //void * 泛型:可以代表所有的指针类型. //如果要存储两个整数,用int * ,存储8个字符,用char * ,存储4个人整数,用short *. //malloc 在堆区开辟n个字节大小的空间,返回空间的首地址. char *p = malloc(8); //存储iphone strcpy(p, "iphome"); printf("%s\n",p);//iphome //释放空间 //删除只是标记删除,不会清楚空间上的内容. free(p); p = NULL;
三.堆区空间问题.
1.野指针问题:访问没有所有权的空间.
2.过度释放:一块空间释放多次,程序会立即crash.
3.内存泄露:空间没有释放,造成内存堆积.不会造成立即crash,安全隐患.
处理方法 : p = NULL;
使用指针必备条件: 1.指针要由明确的指向.
2.指向一个可以控制的区域
四.malloc应用
1.一个有5个元素的数组空间.存储5个整数.
int *p = malloc(sizeof(int)*5); for (int i = 0; i < 5; i++) { p[i] = arc4random() % (40 - 20 + 1) + 20; printf("%d ",p[i]); } printf("\n"); //排序 for (int i = 0; i < 5 - 1; i++) { for (int j = 0; j < 5 - 1 - i; j++) { if (p[j] > p[j + 1]) { int temp = p[j]; p[j] = p[j + 1]; p[j + 1] = temp; } } } for (int i = 0; i < 5; i++) { printf("%d ",p[i]); } free(p); p = NULL;
2.有一个字符串,其中包含数字,提取其中的数字,要求动态分配内存保存.
printf("请输入一段字符串:\n"); char str[] = {0}; scanf("%s",str); int i = 0; int num = 0; while (str[i] != '\0') { if (str[i] >= '0' && str[i] <= '9') { num++; } i++; } char *q = malloc(sizeof(char)*(num+1));//根据长度生成空间 num + 1 字符串隐藏\0 int m = 0,n = 0; for (int i = 0; i < num; i++) { while (str[m] != '\0') { if (str[m] >= '0' && str[m] <= '9') { q[n] = str[m]; n++; } m++; } } q[n] = '\0';//多出来的存储\0 printf("\n"); for (int i = 0; i < num; i++) { printf("%c", q[i] ); } free(q); q = NULL;
3.输入3个学员的姓名,动态分配内存保存学员姓名,并在最后输出.
char *names[3] = {0}; //存储在堆区开辟的空间的首地址. char temp[255] = {0};//存储从控制台输入的字符串 for (int i = 0; i < 3; i++) { printf("请输入3个学生的姓名"); scanf("%s", temp);//输入到temp临时数组中. //动态计算输入的字符串的长度 unsigned long length = strlen(temp); //在堆区开辟空间. names[i] = malloc(length + 1);//将堆区空间的地址存储指针数组中, //将内容拷贝到堆区. strcpy(names[i], temp); } for (int i = 0; i < 3; i++) { printf("%s \n",names[i]); free(names[i]);<span style="font-family: Arial, Helvetica, sans-serif;">//空间的释放</span> names[i] = NULL; }
(2)calloc用法
1.void * calloc(unsigned n, unsigned size); 分配n个size大小的空间.并且把该内存上的所有字节清零. int *p = calloc(5, 4);//分配5块大小为4字节的空间,并且做清零操作. free(p); p = NULL;
(3)realloc 用法
void *realloc(void *p,unsigned newSize); int *p = malloc(10); printf("%p\n",p); int *q = realloc(p, 40);//重新分配一个大小为100 的空间. //realloc 返回当前空间的首地址.如果当前空间不够,则在另一块申请20个字节的空间,此时返回新的空间的地址. printf("%p\n",q); free(q); q = NULL; p = NULL;//不需要释放.
(4)memcpy用法
void *memcpy (void *dest, const void *source, size_t n); //从source指向内存开始拷贝到dest中n个字节. char *p1 = malloc(8); char *p2 = malloc(8); strcpy(p2, "frank"); printf("%s\n", p2); //memcpy(p1, p2, 6); memcpy(p1, p2, 4); memcpy(p1, p2 + 2, 4);//ank p1[4] = '\0'; printf("%s\n", p1);//fran
(5)memset用法
<pre name="code" class="cpp">4. void * memset(void *s, int c, size_t n); //从s指向的内存开始初始化n个字节的内容为c char *p1 = malloc(8); memset(p1,0,8);
五.练习
定义两个整型指针,分别用malloc、calloc对其分配空间保存3个元素,malloc分配的空间用memset清零,随机对数组进行赋值随机范围1-3,赋值后用memcmp比较两个数组。如果相同打印Good!否则打印Failed..
int *p = malloc(sizeof(int) * 3); int *q = calloc(3, sizeof(int)); memset(p, 0, sizeof(int) * 3); for (int i = 0;i < 3;i++) { p[i] = arc4random() % (3 - 1 + 1) + 1; q[i] = arc4random() % (3 - 1 + 1) + 1; printf("p:%d q:%d\n",p[i],q[i]); } //比较buf1和buf2指向的内存是否相同,比较count个字节 if(memcmp(p , q , sizeof(int) * 3) == 0){ //地址 .3即3个字节. printf("profect\n"); } else { printf("failed\n"); } free(p); free(q); p = NULL; q = NULL;
六.宏
定义宏:
三部分:1.#define 2.宏名 3. 替换的内容
宏的作用:
只做替换.
宏名的命名规范: 1.全部大写 2. k+驼峰
无参宏 #define kArrayNumber5 #define N
10
有参宏 #define MUL(A,B) ((A) * (B))
宏应该注意的几个问题.
1.宏名大写
2.参数一定要加小括号.
3.宏替换的内容不要加分号.
4.对于有参宏,宏名一与参数之间不要加空格.
七.枚举
定义枚举
枚举的作用 :罗列出所有的可能性
枚举是将人能够识别的标示符和计算机能够识别的数字结合在一起.
例子:
//定义枚举 typedef enum button { //通过1的每一位来表示一个状态. Close = 1 << 0,//关闭 001 第一位1表示关闭 Max = 1 << 1, // 最大化 010 第二位为1表示最大化 Min = 1 << 2//最小化 100 第三位为1表示最小化 }Button;
如果想宝贝多个枚举值,按位或即可,前提是枚举值通过左移符号对应值. BOOL b = Close | Max | Min; //001 010 100 = 111 printf("%d\n", b);
八.条件编译
以#开头的叫做预编译指令
预编译指令做一些文本以及代码的替换工作.
形式1:
#define A #ifdef A int a = 10;//条件编译(根据条件编译不同的代码) #else int a = 20; #endif printf("%d ", a);//10
形式2:
#define A #ifndef A //如果没有定义 int a = 10;//条件编译(根据条件编译不同的代码) #else int a = 20; #endif printf("%d\n",a);//20
形式3:
# if 10 //非0即为真,执行if,否则为假,执行else int a = 10; #else int b = 20; #endif printf("%d\n", a); //10
九.面试题 #include 与 #import
的区别
#import 相比 #include 能够防止重复导入,引起交叉编译.
#import " " 导入自定义的头文件
#impoer <> 导入系统的头文件