#import <Foundation/Foundation.h>
// 利用关键字 static 修饰的变量 叫做静态变量 并且储存在静态区
// 特点1:如果你不给初值 默认是 0
// 特点2:只初始化一次
static int number1 = 10; // 全局静态变量
// 全局变量
int number2 = 5;
//void function(){
// // 局部静态变量
// // 局部静态变量的作用域 到大括号结束为止
//
// static int num = 10;
// num++;
// printf("num = %d\n", num);
//}
void function1(){
int a = 5;
int b = 6;
printf("%d %d\n", a, b);
}
void function2(){
int value = 100;
printf("%d \n", value);
}
void function3(){
int temp;
printf("%d \n", temp);
}
int main(int argc, const char * argv[]) {
// 内存划分为5个区域:栈区、堆区、静态区、常量区、代码区
// 内存地址 由高到低
// 学习目标:按顺序记忆
#pragma mark -- 代码区
// 电脑的存储 都是以二进制数据进行存储的
// 代码会被系统转化成二进制数据 存储到代码区
#pragma mark -- 常量区
// 常量区 存储的常量特点
// 常量 是运行期间 不能改变的量
// char *str = "dajun";
// // 把 j 更改成'z'
// // *(str + 2) = 'z'; // 企图修改常量。系统崩溃
//
// str = "haha"; // 指针的赋值 就是指针的重指向
// printf("%s\n",str);
//
//
// char str1[] = "dajun";
// // 数组名字 地址 数组首元素的地址
// // 数组首元素的常量地址
// // 把“ j 改成' y'
// // 是把常量区的常量字符串 拷贝到 栈区
// str1[2] = 'w';
// printf("%s\n",str1);
#pragma mark -- 静态区
// 静态区 : 存储两种变量
// 1.静态变量
// 2.全局变量
// 静态区变量 保存周期:直到程序运行结束,静态变量 才会被释放
// function();
// function();
// function();
#pragma mark -- 栈区
int n1 = 5;
int n2 = 10;
int n3 = 15;
function1();
printf("%p\n", &n1);
printf("%p\n", &n2);
printf("%p\n", &n3);
// 栈区有多大?
// 大概 7M - 8M
// char str[8187 * 1024] = {0};
// 出栈入栈的规则
// 先入栈的后出栈 先入栈的 在栈底
// 入栈 压栈
// 出栈顺序 : 从栈顶开始 出栈
// 之所以栈区容量不是特大 又不会出现崩溃的现象是因为栈区频繁的进行出栈和入栈 只要一次性不把栈空间堆满,不会轻易的崩溃。
// 定义变量的时候 切记:给初值,避免出现莫名其妙的问题
function2();
function3();
#pragma mark -- 堆区
// 堆区是程序员开辟空间 是程序员释放空间
// 手动开辟空间 手动释放空间
// 堆区的空间 大概就是内存的空间
// 开辟空间函数
// void *malloc(<#size_t#>)
// void * 代表无类型指针 可以转化成任何类型的指针
// size 开辟空间的大小 开辟多少字节空间
// 给整型指针p指向的位置 开辟了4个字节的 堆内存空间
int *p = malloc(4);
*p = 10;
printf("%d\n", *p);
char *str = malloc(8);
strcpy(str, "dajun"); // 正确
strcpy(str, "dajundajunda"); // 错误 开辟了多少空间 不要超过开辟的空间
int *p1 = malloc(4);
*p1 = 5;
// 开辟多少空间 最好你就用多少
short *p2 = malloc(4);
*p2 = 10;
*(p2 + 1) = 15;
// 释放空间函数
// free(*p1);
// 1、标记删除 不会抹去该空间存储的数据 只会把这块空间标记为可用
// 2、把指针置为空
// 开辟空间
int *p3 = malloc(4);
// 使用空间
*p3 = 10;
printf("%d\n", *p);
// 释放空间
free(p3);
p = NULL;
int *p4 = malloc(sizeof(int ) * 5);
for (int i = 0; i < 5; i++) {
*p4 = i + 1;
p4++;
}
// 指针地址发生变化 释放本不属于开辟的区域 这时候 就会崩溃
// 修改: 把指针移回去
for (int i = 0; i < 5; i++) {
p4--;
}
free(p4);
p4 = NULL;
// 有一字符串,其中包含数字,提取其中的数字.要求动态分配内存保存
// 提⽰: 先计算出有⼏个数字,然后根据数字的个数来开辟空间.
char str1[] = "da52jun094ai23z2p5mhd";
// 计算出有多少数字
int count = 0;
for (int i = 0; i < strlen(str1); i++) {
if (str1[i] >= '0' && str1[i] <= '9') {
// 进到分支 肯定是数字
// str1[count] = str1[i];
count++;
}
}
char *pchar = malloc(count + 1);
int index = 0;
for (int i = 0; i < strlen(str1); i++) {
if (str1[i] >= '0' && str1[i] <= '9') {
// 进到分支 肯定是数字
pchar[index] = str1[i];
index++;
}
}
*(pchar + index) = '\0';
printf("%s\n", pchar);
free(pchar);
pchar = NULL;
// 输入3个学员的姓名,动态分配内存保存学员姓名,并在最后输出
char *names[3] = {0};
char st[] = {0};
for (int i = 0; i < 3; i++) {
printf("输入姓名:\n");
scanf("%s",st);
// 开辟空间
names[i] = malloc((int)strlen(st) + 1);
// 保存字符串
strcpy(names[i], st);
}
for (int i = 0; i < 3; i++) {
printf("%s ", names[i]);
free(names[i]);
names[i] = NULL;
}
// 其他分配堆内存函数
// 在堆内存中 开辟 n * size 个字节空间 并且把开辟的内存空间清零
// 因为有一个清零的过程,所以效率偏低
// calloc(int n, size);
int *a = calloc(3, sizeof(int));
// 重新分配函数
// realloc(原来分配的地址, 新的空间大小)
// 情况1、如果原来分配的地址可以扩充空间 那么就在原地址扩充
// 情况2、如果原来分配的地址不能扩充 那么系统会重新分配一个空间 并且把原来地址储存的数据拷贝到新空间里 然后系统自动释放原地址的空间
int *p_old = malloc(10);
printf("%p\n", p_old);
int *p_new = realloc(p_old, 15);
printf("%p\n", p_new);
// free(0_old); 过度释放
free(p_new);
p_new = NULL;
// 内存操作函数
// 把开辟的空间 多少字节 重置成 c
// memset(开辟空间的指针, int c, 字节数)
// 用途: 把开辟好的空间清零
int *pp = malloc(sizeof(int) * 4);
for (int i = 0; i < 4; i++) {
pp[i] = i + 5;
}
// 清零
memset(pp, 0, 16);
for (int i = 0; i < 4; i++) {
printf("%d ", pp[i]);
}
// 内存拷贝函数
// 从来源 拷贝 到 目的地 多个字节
// *memcpy(目的地,来源, 字节数);
// 内存比较函数
// 两个地址 按字节 进行比较 返回第一个不同的差值
// memcmp(指针1,指针2,字节数)
return 0;
}