//函数声明
int max(int a, int b);
char * getString();
int main(int argc, const char * argv[]) {
//////////////////Lesson 10 动态内存管理 课堂笔记 和 练习
///////复习上周所学
/////////常量和变量的区别:
//常量中的内容不能被修改,只能访问;
//变量中存储的数据时可以随时修改的。
//
//const 关键字的作用: 修饰变量不可改变。当做常量使用
// const int a = 10;
////////以下变量谁可不变
//口诀:看const修饰谁, 谁就不可变, 将数据类型 int 去掉 (const后面跟的变量,*也是一体的)
// int b = 30;
// const int *p1 = &b; //*p1不可变; p1指针变量,*p1指针变量指向的存储空间。const 修饰*p1, 不能通过指针变量*p1修改指向的存储空间上的数据,但是p1可以重新赋值。
//
// int *const p2 = &b;//p2不可变,const修饰p2,p2中存储的数据不可更改,但是可以通过指针变量p2(使用*p2),修改指向的空间上的数据。
//
// int const *p3 = &b;//*p3不可变,同p1
//
// const int *const p4 = &b;//p4,*p4不可变
/////////不同数据类型定义的变量所存储的内容:
//int, short, long: 存储整数,整型数据。
//float, double:存储小数,浮点型数据。
//char:字符型数据。
//char *, int *, short *: 存储地址
//struct student: 存储结构体成员信息
//struct student * :存储结构体变量的地址
/////////指针数组
//常量区上存储的数据不可更改。
// char *str1 = "iPhone"; //str1存储常量字符串 iPhone 首地址;
//
// char *str2 = "Rose";
// char *str3 = "Tom";
// char *str4 = "Jack";
// char *str5 = "Android";
//
// //交换指针变量
// char *temp = str2;
// str2 = str3;
// str3 = temp;
// printf("%s \n", str3);
//
//
// char *strings[5] = {"iPhone", "Rose", "Tom", "Jack", "Android"};
// //strings[0] == str1
//
//
// char *tp = strings[1];
// strings[1] = strings[2];
// strings[2] = tp;
//
// printf("%s \n", strings[2]);
//
// printf("%p, %p", str1, strings[0]); //同一个字符串,是一个地址
////////// * 的作用
// int c = 10;
// int *p = &c; //定义指针变量时,*的作用只是为了告诉编译器,后面的变量是一个指针变量,用来存储地址。
//
// *p = 30; //此时,* 的作用,是根据指针变量找到指向的存储空间,并且存储数据30
//
// printf("%d \n", *p);//同上
//
////////////////////动态内存
//内存中的5分区
//1.栈区:主要存放局部变量或者数组,定义在函数内部,当函数调用时开辟空间,当函数结束后回收空间,内存有 系统 进行分配和回收。
//2.堆区:堆区内存由 开发人员 手动开辟,手动释放。
//3.全局、静态区:存放全局变量,以及静态变量; 程序运行时,开辟空间,程序运行结束空间回收。由 系统 进行管理。
//4.常量区:存放常量;整型,浮点型,字符型,字符串型; 常量区空间上得内容不可修改,read-only
//5.代码区:存放程序编译之后形成的CUP指令,告诉计算机程序如何运行。
//////
// int a = 10, b = 20;
//
// printf("%d\n", max(a, b));
//
// printf("%s", getString());
//
////////
//如何在堆区空间上存放数据。
//如何在堆区开辟空间
//malloc在堆区开辟n个字节大小的空间,并且返回空间的首地址。返回值类型void *泛型,代表任意指针的类型。
//如果申请 8 个字节的空间, 使用不同的指针类型变量接收, 存储的数据大小不同。
//char *: 8个字符
//int *: 2个整数
//short *: 4个整数
//long *: 1个整数
// char *p = malloc(7); //手动开辟空间
//
// strcpy(p, "iPhone");
// printf("%s\n", p);
//
// strcpy(p, "Apple");
// printf("%c\n", *(p + 3));
//
// free(p); //手动释放空间, 释放时需要给定开始地址; 释放只是把空间还给系统,属于标记删除,不清楚内容。
// printf("%p\n", p); //虽然释放了空间,但是p存的地址并没有清空
// printf("%s\n", p);
//
// p = NULL;//清空指针变量中得地址,指向无效的空间
//
/////堆区空间常见的问题:
/*
1.野指针错误:访问一块没有权限的空间,没有获得空间的使用权。存在安全隐患;解决方案:当把空间还给系统之后,将指针变量中存储的地址清空 即:赋值NULL
2.过度释放:对一块空间free多次,过度释放会立即导致crash.
3.内存泄露:空间没有及时的释放,造成内存堆积。就是没有free; 安全隐患.
*/
//开辟空间存储5个整数, 赋值10 - 20
// int *a = (int*)malloc(sizeof(int) * 5);
//
// for (int i = 0; i < 5; i++) {
// *(a + i) = arc4random() % (20 - 10 + 1) + 10;
// printf("%d ", *(a + i));
// }
//
// for (int i = 0; i < 5 - 1; i++) {
// for ( int j = 0; j < 5 - 1 - i; j++) {
// if (*(a + j) < *(a + j + 1)) {
// int temp =*( a + j);
// *(a + j) = *(a + j + 1);
// *(a + j + 1) = temp;
// }
// }
// }
// printf("\n");
// for (int i = 0; i < 5; i++) {
// printf("%d ", *(a + i));
// }
//
// free(a);
// a = NULL;
// 有⼀字符串,其中包含数字,提取其中的数字.要求动态分配内存保存
// char str[]= "lan5ou2015032056", *p = NULL;
//
// char *a[20] = {0};
// int count = 0;
// int i = 0, j = 0;
////方法1
// while (str[i] != '\0'){
// if (str[i] >= '0' && str[i] <= '9') {
// a[j] = (char*) malloc(sizeof(char));
// count++;
// a[j] = &str[i];
// j++;
// }
// i++;
// }
// for (int i = 0; i < count; i++) {
// printf("%c ", *(a[i]));
// }
/////方法2
// // 获得数字个数
// i = 0;
// while (str[i] != '\0'){
// if (str[i] >= '0' && str[i] <= '9') {
// count++;
// }
// i++;
// }
// //开辟空间
// char *num = malloc(count + 1);
// //存储字符
// j = 0;
// i = 0;
// while (str[i] != '\0'){
// if (str[i] >= '0' && str[i] <= '9') {
// *(num + j) = str[i];
// j++;
// }
// i++;
// }
// *(num + j) = '\0';
// printf("%s ", num);
// free(num);
// num = NULL;
//方法3
// i = 0, j = 0;
// while (str[i] != '\0'){
// if (str[i] >= '0' && str[i] <= '9') {
// p = realloc(p, sizeof(char));
// count++;
// *(p + j) = str[i];
// j++;
// }
// i++;
// }
//
// printf("数字个数:%d, %s ",count, p);
// free(p);
// p = NULL;
//2. 输⼊入3个学员的姓名,动态分配内存保存学员姓名,并在最后输出
//存储3个单词,意味着需要开辟3次空间,每次开辟空间都会返回对应的首地址, 所有为了存储3个地址,定义指针数组存储。
// char *word[3] = {0};
// char temp[20] = {0}; //存储控制台输入的字符串
//
// for (int i = 0; i < 3; i++) {
// printf("\nInput [%d] name :", i + 1);
// scanf("%s",temp);
// word[i] = malloc(strlen(temp) + 1);//根据输入的字符串动态在堆区分配空间
// strcpy(word[i], temp);
// }
//
// for (int i = 0; i < 3; i++) {
// printf("%s ", *(word + i));
// free(word[i]);
// word[i] = NULL;
// }
////////其他内存分配函数
//////calloc(n, size_t) c---clear 多了一步空间数据的清理操作,但是清理操作效率较低。
// //分配n个size⼤大⼩小的空间,并且把该内存上的所有字节清零。 分配n个size大小的空间
// int *ptr = calloc(5, 4);
//
// free(ptr);
// ptr = NULL;
//
//
// //////realloc 内存重新分配函数
// char *pstr = malloc(10);
// //10个空间不够,重新分配20个,不是追加
// char *pstr1 = realloc(pstr, 200); //工作原理:先以之前的开始地址作为基准,重新分配新的空间,如果此时发现剩余空间不足,会寻找新的空间。此时返回的地址,就和之前不一样的,另外realloc内部集成了将之前空间free的操作。
// printf("%p, %p", pstr, pstr1);
// free(pstr1); //只需释放realloc的空间即可。
// pstr1 = NULL;
// pstr = NULL;
//
///////内存操作函数
// void *memset(void *s , int c , size_t n)
// 从s指向的内存开始初始化n个字节的内容为c
// int memcmp(const void *buf1, const void *buf2, unsigned int count)
//
// ⽐比较buf1和buf2指向的内存是否相同,⽐比较count个字节
// void *memcpy(void *dest,const void*source , size_t n)
//
// 从source指向的内存开始拷⻉贝到dest,拷⻉贝n个字节
// 定义两个整型指针,分别⽤用malloc、calloc对其分配空间保存3个元 素,malloc分配的空间⽤用memset清零,随机对数组进⾏行赋值随机范 围1-3,赋值后⽤用memcmp⽐比较两个数组。如果相同打印Good!否则 打印Failed...
//
// int *ip1 = (int *)malloc(3 * sizeof(int));
// int *ip2 = (int *)calloc(3, 4);
//
// memset(ip1, 0, 12); //清 0 操作
//
// for (int i = 0; i < 3; i++) {
// *(ip1 + i) = arc4random() % 3 + 1;
// *(ip2 + i) = arc4random() % 3 + 1;
// printf("%d %d\n",*(ip1 + i), *(ip2 + i));
//
// }
// if ( memcmp(ip1, ip2, 1) == 0) {
// printf("GOOD");
// }else{
// printf("Failed");
// }
//
return 0;
}
//函数实现
int max(int a, int b){
return a > b ? a : b;
}
//char string[] = "Welcome to Lanou iOS!"; //放在这里是可以,不过不太安全
char *getString(){
// char string[] = "Welcome to Lanou iOS!"; // //数组string,是在函数内部定义的,属于局部变量,存储在栈区,当函数执行结束,数组空间被系统回收。外界拿到地址,将访问一块已经回收的空间。所以,要想安全的返回,必须保证返回之后空间还在。
// static char string[] = "Welcome to Lanou iOS!"; //设置成静态数组
char *string = "Welcome to Lanou iOS!"; //返回的是常量区Welcome 。。。。,首地址;
return string;
}