OC内存管理

分析一下C中容易出错的内存代码

#import <Foundation/Foundation.h>


int main(int argc, const char * argv[]) {

    @autoreleasepool {

        

        char *s = "Gello World!";//s是放在只读数据段

        s[0] = 'H';//只读数据段是不能被修改的,所以该操作是错的!

        //修改为 char s[]="Gello World";是对的!

        printf("%s\n",s);        

    }

    return 0;

}


第二个错题:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_memory(char *p, int capacity) {
    p = malloc(sizeof *p * capacity);
}
int main() {
   char *str = NULL;//由于这里str本身就是指针所以要操作str必须传入的是
   //二重指针,正确代码参见以下
   get_memory(str, 100);   
   strcpy(str, "Hello, world!");  
   printf("%s\n", str); 
   return 0;
}

第二题的正确代码:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

void get_memory(char **p,int capacity){

//指针的第二个作用就是申请堆空间

*p = malloc (sizeof **p * capacity);

}

//指针的第一个用途就是实现跨栈操作

void swap (int *a,int *b){

int temp = *a;

*a = *b;

*b = temp;

}

//任何时候希望通过函数调用修改传入的参数(对调用者产生影响)

//那就不能只传参数的值而是要传参数的地址

//如果传入的参数本身就是指针。那么就要使用指向指针的指针

//指针的第一个用途就是实现跨栈操作

int main(){

int a=9;int b=0;

swap(&a,&b);//传的是ab的地址

printf("%d %d\n",a,b);

char *str = NULL;

get_memory(&str,100);

if(str){//如果空间申请成功

strcpy(str,"Hello,world");

printf("%s\n", str);

free(str);//堆空间不会随着栈的消失而消失需要手动释放;

str = NULL;//如果以后还要用str,不置空的话使用str可能失败表面产生野指针

}

return 0;

}

注意事项:前面为str申请了堆空间,一定要记得三个操作:

1.判断申请空间是否成功(加上if判断语句)if(str)

2.手动free释放掉空间;free(p);

3.将指针置空避免产生野指针!!str == null;


 常见内存错误第三题;

#include <stdio.h>
char *get_memory() 
{    
char str[] = "hello, world";    
return str;
}
int main() {    
char *str = get_memory();    
printf("%s\n", str);    
return 0;
}

正确的代码修改:

#include <stdio.h>
char *get_memory() 
{    
char *str = "hello, world";    
return str;
}
int main() {    
char *str = get_memory();    
printf("%s\n", str);    
return 0;
}

注意: char str[] = "hello world"

c的数组是放在栈空间的,一个函数只能返回占空间的值而不能返回栈空间的地址


常见内存错误第四题:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_memory(int capacity) {    
char *str = malloc(sizeof *str * capacity);    
return str;
}
int main() {    
char *str = get_memory(100);   
 strcpy(str, "Hello, world!");    
 printf("%s\n", str);
return 0;
}

修改后的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_memory(int capacity) {    
char *str = malloc(sizeof *str * capacity);    
return str;
}
int main() {    
char *str = get_memory(100);   
if(str){
 strcpy(str, "Hello, world!");    
 printf("%s\n", str);
 free(str);
 str  = NULL;
 }
return 0;
}

注意:申请空间后一定要判断,然后释放掉空间,最后将指针置空!!


  为了解决上述问题,在Objective-C中引入了引用计数的概念。Objective-C中每个类都是NSObject子类,因此每个对象都有一个内置的计数器,这个计数器称为引用计数(Reference Count),也称保留计数(Retain Count)。所谓Objective-C的内存管理,就是要维护引用计数器正确+1和-1,当引用计数器为0时,对象正确释放。在Objective-C中,每个对象就如同一个QQ讨论组,当有人创建讨论组时,讨论组人数为1(对象创建);每有一个人加入讨论组,该讨论组的人数+1(使用retain增加引用计数),每有一个人离开讨论组,该讨论组的人数-1(使用release减少引用计数);如果讨论组的人数为0,则自动解散


OC中管理内存的相关方法:

retain:增加对象的引用计数;

release:减少对象的引用计数

autorelease:在自动释放池块结束时候减少对象的引用计数

retainCount: 引用计数的数量;

注意:::一般都使用ARC模式不要随便使用MRC模式!!!

//ARC模式下要正确书写属性的修饰符

//和内存管理相关的属性修饰符是:

//strong -对象指针一般都使用strong,表示对引用计数+1(默认值)

//weak -

//1. 如果对象存在循环引用的(a关联bb也关联a)ab有一方必须使用weak破环

//2.一个对象的生命周期不由你自己的代码管理,也应该使用weak

//3.如果属性是一个协议指针也应该使用weak;

//copy -

//1.确保NSStringNSarrayNSdectionaryNSData

//不可变类型的指针的确指向一个不可变对象;

//2.如果属性是一个block类型的变量必须用copy;

//assign

//1.基本数据类型(就是非对象指针类型,包括结构体和枚举)都用assign

//整型,字符型,枚举,浮点型,结构体,联合体,实型;

//2.如果属性是对象指针,assign相当于weak;

//不要在C的结构体中使用对象指针。因为无法进行内存管理;












转载于:https://my.oschina.net/luhoney/blog/646236

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值