// main.m
#import <Foundation/Foundation.h> #import "Student.h" void test(){ int a = 10; printf("test 中a 的地址%p\n",&a); } void test1(){ int b = 20; printf("test1中的 b 的地址%p\n",&b ); } char * str() { char string[20] = "iPhone"; return string; //内存问题一:野指针问题,空间回收,访问不该访问的内存; } int main(int argc, const char * argv[]) { //定义5个学生数组 // Student BJS[5] = {0}; // printf("请输入5个学生的姓名,性别,年龄,学号,分数:\n"); // // for (int i = 0; i < 5; i++) { // scanf("%s%c%d %d %f",(BJS + i)->name,&(BJS + i)->sex,&(BJS + i)->age,&(BJS + i)->num,&(BJS + i)->score); // } // // printStudent(BJS,5); // // sortStudentByName(BJS,5); // // printStudent(BJS,5); // // printf("=====================栈区======================\n"); int a = 10; int b = 10; int c = 10; printf("%p\n%p\n%p\n",&a,&b,&c); //栈区 局部变量存储的区域 /* 1.栈区内存分配规则:由大到小分配,由小到大存储; 2.函数调用就是一个入栈出栈的过程,调用函数,入栈,系统会为函数分配所需要的空间;函数结束,出栈,系统回收函数使用的内存空间; 3.栈区空间的分配有系统完成,不需要我们(iOS 开发工程师)手动管理; 4.系统为每一个应用程序分配的栈区空间有限且小,但是程序之所以没有崩溃,是因为栈区空间一直频繁的开辟和释放; */ // int a[5] = {1,2,4,5,6}; // for (int i = 0 ; i < 5; i++) { // printf("a地址:%p\n",(a + i)); // } // int b[5] = {3,4,6,7,9}; // for (int i = 0 ; i < 5; i++) { // printf("b地址:%p\n",(b + i)); // } test(); test1(); //a 和 b 的地址是相同的, a 被调用完成后直接释放, b又用得那个地址,假如 b 不初始化的话将会得到之前这个空间内存储的值,即之前a 的值.栈内存返回是不安全的,禁止!!! printf("=====================堆区======================\n"); int *p_1 = malloc(4); int *p_2 = malloc(4); int *p_3 = malloc(4); printf("%p\n%p\n%p\n",p_1,p_2,p_3); //堆区 堆区由我们(iOS 开发工程师)手动开辟,手动释放,自主管理 /* void * malloc(size_t);在堆区开辟指定字节的空间,并把对应空间的首地址返回 void * 泛指,指代所有指针类型 1.整型:在堆区开辟4个字节,并把10存储在开辟的空间内 int *p_int = malloc(4); *p_int = 10; printf("%p %d",p_int, *p_int); 释放 void free(void *);将给定的地址空间释放 释放的不是内容,而是内存使用的标记 free(p_int); 2.数组 //随机20-40之间的5个数,并把数字存在堆区 int *p_ints = malloc(5 * sizeof(int)); for(int i = 0; i < 5; i++){ *(p_ints + i) = arc4random()%(40 - 20 + 1) + 20; } for(int i = 0; i < 5, i++){ print("%d ",*(p_ints + i)); } //释放 free(p_ints); 过度释放: //free(p_int); 如果释放时错写为上次释放过的堆区地址,将会出现过度释放的问题; //如果在堆区空间释放后,继续访问此空间的话,照样会读取里面的内容,虽然其已经释放但是其空间的内容不会消失,而只是标记为已释放;该野指针的问题解决需要改变其指针为 NULL p_int = NULL; p_ints = NULL; //字符串 char str[] = "iPhone10"; //在堆区开辟对应空间 char *p_str = malloc(strlen(str) + 1); strcpy(p_str,str); printf(" %s \n",p_str); free(p_str); p_str = NULL; 内存泄露:对于在堆区开辟的地址,没有释放,而重新定义其指向另外开辟的空间,将不会有指针指向它,它的地址无从可知了则之前的空间将会浪费,就是所谓的内存泄露.当没有释放的空间积累到一定量的时候,会造成电脑顿卡,频频 crash;所以当堆区开辟的内存使用完毕后,一定要释放!!! */ //有一字符串,其中包含数字,提取其中的数字.要求动态分配内存保存 // char str[] = "asdt43668hgkfi34"; // //计数器 // int count = 0; // //循环遍历数组 找到数字 // for (int i = 0; i < strlen(str);i++ ){ // if(str[i] <='9'&& str[i]>= '0'){ // count++; // } // } // printf("%d ",count); // //根据字符数开辟空间大小 // char *p_str = malloc( count + 1); // int index = 0; // for(int i = 0; i < strlen(str); i++){ // if(str[i] <='9'&& str[i]>='0'){ // *(p_str + index) = str[i]; // index++; // *(p_str + index) = '\0'; // } // } // // printf(" %s ",p_str); // // free(p_str); // p_str = NULL; // // //输入3个单词,动态分配内存保存学员姓名,并在最后输出 // char str[100] = {0}; // char *p_str[3] = {0}; // printf("please import three words:\n"); // for (int i = 0; i < 3; i++) { // //输入单词 // scanf("%s",str); // //根据输入字符串的长度,开辟对应空间大小 // p_str[i] = malloc(strlen(str + 1)); // //将字符串拷贝到开辟空间中 // strcpy(p_str[i],str); // } // for (int i = 0; i < 3; i++) { // printf("%s ",p_str[i]); // free(p_str[i]); // p_str[i] = NULL; // } // // // //void *calloc(int n,int size_t);开辟 n * size_t个字节空间,并把首地址返回,相比 malloc, 它多了一步清零操作,效率低; //存储5个整型数 // int *p_int = calloc(5, sizeof(int)); // for (int i = 0; i < 5; i++) { // printf("%d ",*(p_int + i)); // 此时打印出是5个0,因为其开辟时做了清零操作 // *(p_int + i ) = arc4random()%(40 - 20 + 1 ) + 20; // } // for (int i = 0; i < 5; i++) { // printf(" %d ",*(p_int + i)); // } // free(p_int); // p_int = NULL; // // // // // void *realloc(void * p,size_t),在给定的地址基础上重新开辟新的空间,并把新的空间地址返回. // // 如果在之前的地址后空间被占有,且需要开辟的空间比之前要大,则系统自动换有足够空间的地址开辟. // char *p = malloc(20); // char *p_1 = realloc(p, 40); // // printf("p = %p,p_1 = %p",p,p_1); // // //free(p) //对于 realloc 来说,在释放空间时,只需要释放最新的地址,释放旧的地址就会造成过度释放; // // // //内存操作函数 // //void *memset(void * ,int , size_t) 从传入地址开始,开辟 size_t 个字节,重置为指定数值 // //整型 // int *p = malloc(4); // memset(p,0,4); // printf("%d ",*p); // // // //字符串 // char *p_str = malloc(10); // memset(p_str, 'a', 9); // *(p_str + 9) = '0'; // printf("%s",p_str); // // // //void *memcpy(void *,const void *,size_t):从指定的地址开始向目标地址拷贝指定字节的内容 // // char wrongName[] = "BJS123456"; // char rightName[] = "654321"; // // //将 right 中的某个字符开始向 wrong 中的某些字符 复制3个字节 // memcpy( wrongName+6, rightName+3, 3); // // printf("\n%s",wrongName); // // // // //memcmp(const void *, const void *,size_t):通过给定的地址和目标地址进行给定字节数的比较,前面减后面的 // // int result = memcmp(wrongName + 3, rightName + 1, 2); // printf("result = %d",result); // //定义两个整型指针,分别⽤用malloc、calloc对其分配空间保存3个元 素,malloc分配的空间⽤用memset清零,随机对数组进⾏行赋值随机范 围1-3,赋值后⽤用memcmp⽐比较两个数组。如果相同打印Good!否则 打印Failed... // int *p_2 = calloc(3, sizeof(int)); // int *p_1 = malloc(3 * sizeof(int)); // memset(p_1, 0, 12); // for (int i = 0; i < 3; i++) { // *(p_1 + i) = arc4random()%(3 - 1 + 1) + 1; // *(p_2 + i) = arc4random()%(3 - 1 + 1) + 1; // } // // //比较 // int result = memcmp(p_1, p_2, 12); // // if (result) { // printf("Failed!"); // }else{ // printf("GOOD!"); // } // // // // // printf("\n=====================静态区======================\n"); static int z = 10; static int y = 20; static int x = 30; printf("%p\n%p\n%p\n",&z,&y,&x); //静态区(全局区) 静态变量和全局变量存储的区域 /* //该内存区分为两个部分,一部分存储已经赋初值的静态变量和全局变量,一部分存储没有赋初值的静态变量和全局变量 //静态变量:全局静态变量和局部静态变量; static int a = 10; //用 static 修饰的变量就是静态变量 1.静态变量如果不赋初值,则默认初值为0; 2.静态变量只能被初始化一次; 3.存在于程序的运行的整个过程,程序结束才释放; */ printf("=====================常量区======================\n"); printf("%p\n%p\n",&"d",&"er"); printf("=====================代码区======================\n"); printf("%p\n%p\n",test,test1); //test为函数名,代表该函数的地址; return 0; }
// Student.h/Student.m
<.h> #import <Foundation/Foundation.h> typedef struct student { char name[20]; char sex; int age; int num; float score; }Student; //打印学生信息 void printStudent(Student *stu,int count); //按姓名排序 void sortStudentByName(Student *stu,int count); <.m> #import "Student.h" //打印学生信息 void printStudent(Student *stu,int count){ for (int i = 0; i < count; i ++) { printf("name:%s,sex:%c,age:%d,num:%d,score:%.2f\n",(stu + i)->name,(stu + i)->sex,(stu + i)->age,(stu + i)->num,(stu + i)->score); } } //按姓名排序 void sortStudentByName(Student *stu,int count){ for (int i = 0; i < count - 1; i++) { for (int j = 0; j < count - i - 1; j++) { if (strcmp((stu + j)->name, (stu + j + 1)->name) > 0) { Student temp = *(stu + j); *(stu + j ) = *(stu + j + 1); *(stu + j + 1) = temp; } } } }