求怎么得到appendc 开辟内存一段新内存的地址

iOS 指针和内存块 - 简书
iOS 指针和内存块
在OC中如果不注意指针内存块的问题,你可能会遇到一些很奇怪的问题,但是却很难解决,本文将解释一些在OC中你可能需要了解的知识点。
我们来看这段代码:
NSMutableString *str = [@"string1" mutableCopy];
NSMutableString *str2 =
[str appendString:@"__str"];
[str appendString:@"__str2"];
NSLog(@"str1:%@
str2:%@",str,str2);
//输出:str1:string1__str__str2
str2:string1__str__str2
我们可以看到str1和str2已经是相同的,因为
NSMutableString *str2 =
这段代码让str2指向了str1的内存块,也就是说str1和str2现在是对同一块内存的两个指向,你可以说他们是一模一样的,我们来验证这一点:
NSLog(@"str1:%X
str2:%X",str,str2);
//输出:str1:B3D96B60
str2:B3D96B60
我们打印了str和str2的内存块,我们发现的确是一模一样的。
但很多时候我们希望得到的是一个新的对象,那么这个时候我们可以使用“copy,mutableCopy”语法,copy得到一个不可变变量,mutableCopy得到一个可变变量。像这样:
NSMutableString *str = [@"string1" mutableCopy];
NSMutableString *str2 = [str mutableCopy];
[str appendString:@"__str"];
[str appendString:@"__str2"];
NSLog(@"str1:%X
str2:%X",str,str2);
//输出:str1:92F36240
str2:92F36A90
我们用str copy出一个新的对象,然后打印了他们的地址,发现的确是新的一个内存块了。
在这里我们需要注意,所有的字面量语法都是开辟出一个新的内存块,包括@"",@[],@{}。也就是说:
@"" 与[[NSString alloc]init];等价
@[] 与[[NSArray alloc]init];等价
@{} 与[[NSDictionary alloc]init];等价
[@"" mutableCopy]; 与[[NSMutableString alloc] init];等价
[@[] mutableCopy]; 与[[NSMutableArray alloc] init];等价
[@{} mutableCopy]; 与[[NSMutableDictionary alloc] init];等价
也就是说当我们用字面量语法对一个变量赋值时相当于对他重新开辟了内存块,也就是原本的内存块和他是已经没有关系了。
在这里顺便提一下const修饰符;
extern NSString *
extern NSString const *
这是两种不一样的写法,结果肯定也是不一样的,区别也是在于内存块和指针。const修饰符将其后的变量设置为常量。
extern NSString *
当const在星号后时,var变量的内存指针将不能指向其他内存,同时内存块中的内容也将保持不变。
extern NSString const *
而当const在星号前面时,情况就发生变化了,var变量的内存指针同样无法指向其他内存块,但是在这种情况下,var的内存块的内存是可以发生变化的。也就是说下面这种操作是允许的:
NSMutableString const * var = [@"str" mutableCopy];
[var appendString:@"__var"];
NSLog(@"var:%@",var);
//输出:var:str__var
而反过来则是不允许的,关于这部分内容,在本人另一篇文章中有详细的解释:
更多文章请关注:
iOS程序员。
其实我想当个摄影师。
个人域名:java中数据在内存中的状态
时间: 00:08:30
&&&& 阅读:80
&&&& 评论:
&&&& 收藏:0
标签:此文转自csdn,看完瞬间就明白了
首先,我们知道,Java中的数据类型分为两种,基本数据类型和引用数据类型。而基本数据类型,为什么不直接使用他们的包装类呢,例如Integer、Long等等呢?下面是Thinking in Java 中的解释:
有 一系列类需特别对待;可将它们想象成&基本&、&主要&或者&主&(Primitive)类型,进行程序设计时要频繁用到它们。之所以要特别对待,是由于 用new创建对象(特别是小的、简单的变量)并不是非常有效,因为new将对象置于&堆&里。对于这些类型,Java采纳了与C和C++相同的方法。也就 是说,不是用new创建变量,而是创建一个并非句柄的&自动&变量。这个变量容纳了具体的值,并置于堆栈中,能够更高效地存取。
Java决定了每种主要类型的大小。就象在大多数语言里那样,这些大小并不随着机器结构的变化而变化。这种大小的不可更改正是Java程序具有很强移植能力的原因之一。
可以看到,Sun是为了系统的优化,才采用基本的数据类型。
那么,基本数据类型和引用数据类型到底有什么区别呢 ?
下面依然是Thinking in Java中的话:
程序运行时,我们最好对数据保存到什么地方做到心中有数。特别要注意的是内存的分配。有六个地方都可以保存数据:(1) 寄存器。这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部。然而,寄存器的数量十分有限,所以寄存器是根据需要由编译器分配。我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存在的任何踪迹。(2) 堆栈。驻留于常规RAM(随机访问存储器)区域,但可通过它的&堆栈指针&获得处理的直接支持。堆栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。创建程序时,Java编译器必须准确地知道堆栈内保存的所有数据的&长度&以及&存在时间&。这是由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些Java数据要保存在堆栈里&&特别是对象句柄,但Java对象并不放到其中。(3) 堆。一种常规用途的内存池(也在RAM区域),其中保存了Java对象。和堆栈不同,&内存堆&或&堆&(Heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需用new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!(4) 静态存储。这儿的&静态&(Static)是指&位于固定位置&(尽管也在RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static关键字指出一个对象的特定元素是静态的。但Java对象本身永远都不会置入静态存储空间。
(5) 常数存储。常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格
地保护,所以可考虑将它们置入只读存储器(ROM)。
从上面我们就可以看到,基本数据类型的变量,是存放在堆栈中的,我更喜欢直接称之为栈(stack)。而引用数据类型的引用,也就是Thinking in Java所说的句柄,也是直接放在栈里面,而引用数据类型引用的对象,则是放在堆(heap)中的
明白了基本数据类型和引用数据类型在内存中的区别,那么理解下面的问题就和简单了。
一、String对象的创建问题ss
这本是一个简单的问题,无关轻重,大家用天天使用字符串也用的很happy,你们真的了解字符串吗?
大家知道,String的创建有两种形式,一种是直接放在双引号("")中,一种是直接用new的方式创建,那么这两种方式有什么区别呢?
1、String a="abc";
2、String b=new String("abcdef")
上面的两行代码,分别创建了几个对象呢?
还是先说说JVM对字符串是怎么处理的吧。字符串是一个引用数据类型,根据我们上面对java中基本数据类型和引用数据类型的
分析,String对象肯定是存放在堆中的。关键在于,String对象是一个final的常量,JVM为了管理String和高效性,在堆中,会用一个
特殊的字符串池来保存字符串直接量。
所谓的字符串直接量,就是指字符串由字符串、数值常量直接构成,没有变量,也没有方法。
String a="abc";
String b="abc"+10;
String c="abc"+"def";
这样的字符串,JVM在编译的时候就能完全确定这个字符串,就可以在字符串池中创建该字符串,如果字符串池中已经有这样的
String,就让该变量直接指向在字符串池中的该字符串。
而另外一些不是字符串直接量的字符串
String a="abc"+"abc".lenght();
String b=a+"asc";
JVM无法在编译的时候就确定该字符串,就只能在程序运行期间,在堆中非字符串池中的地方开辟内存,存放这样的字符串。
好了,明白JVM对字符串的处理,在来谈谈String对象创建的问题:
(这两行代码是无关的)
1、String a="abc";
2、String b=new String("abcdef");
上面的两个创建字符串的方法到底分别创建了几个对象?
第1行,创建了一个对象,它是一个字符串直接量,直接被创建存放在字符串池中。
第2行,创建了2个对象,"abcdef"本身就是一个字符串直接量,被创建后存放在字符串池中,然后,它又作为一个参数,
传递给了构造器new String(),这样又在堆中非字符串池的地方开辟了块内存,创建了一个字符串对象。
那么,就在问去几个问题,下面的几段代码分别创建了几个对象
1、String a="ab";
2、String b="ab";
3、String d="abcd";
4、String c=a+"cd";
5、String e=new String("abcd")
6、String f="aaa"+"bbb";
第1行,1个、因为字符串池还是空的,不存在字符串"ab",所以在字符串池创建了一个对象"ab"。
第2行,0个、因为字符串池中"ab"已经存在,所以没有创建,直接将b指向"ab";
第3行,1个、因为也是在字符串池中创建了一个"abcd"对象
第4行,2个、先在字符串池中创建"cd",因为采用了变量,所以要在堆中非字符串池中在创建一个对象a+"cd";
第5行,1个、因为字符串池中已经存在"abcd",直接将他作为一个参数传给构造器new一个新的对象。
第6行,1个,因为在编译的时候就能确定f的值,所以只创建一个"aaabbb"到字符串池中;(很多人误解为3个)
在看下面的
final String a="aaa";
final String b="bbb";
String c=a+b;
字符串c对被创建在哪里,字符串池,还是堆中的其他地方,答案是字符串池中,因为a、b是常量,不是变量。
二、String和StringBuffer的区别在Java中,String和StringBuffer,StringBuilder都能表示一个字符串。String的定义是:表示一个字符串常量。那么,看下面的一段代码:String str="abc";str="def";常量,基本数据类型的常量是不可变的,可是我们可以看到,这里所谓的字符串常量str是可变的。这是为什么呢?引用数据类型的常量,指的是引用的对象不可变,而引用,也即句柄是可变的。也就是多,当一个String类型的字符串改变时,实际上是它指向的内存单元发生了改变,原来的内存单元的内容并没有发生改变。 StringBuffer的定义是:表示一个字符串变量。StringBuffer strbuf="abc";这样的初始化是错误的,要想初始化一个StringBuffer类型的字符串必须使用new来初始化,如
由此可见,StringBuffer字符串变量,指的是不仅引用可变,引用的对象也是可变的。下面的两个例子可以很好的说明这个问题。1、
String str1="abc";
String str2=str1;
StringBuffer str3=new StringBuffer("abc");
StringBuffer str4=str3;
str1=str1+str2;
str3=str3.append(str4);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
System.out.println(str4);输出的结果:abcabcabcabcabcabcabc2、public class Test5{
public static void main(String[] args)
String str1="java";
StringBuffer str2=new StringBuffer("java");
test(str1);
test(str2);
System.out.println(str1);
System.out.println(str2);
public static void test(String str)
str=str.replace("j", "i");
public static void test(StringBuffer str)
str.append("c");
}}程序的输出结果为javajavac(String对象的处理确实与其他的对象有所区别,在深度克隆中也有体现,对它的处理更像是对一个基本数据类型的处理。这主要就是因为它是一个常量的原因。
三、==和equals的问题==的含义,如果是比较基本数据类型,那么就是比较数据类型字面值的大小。如果是比较引用数据类型,就是比较它们在内存地址上是否是相同的。而equals方法,是Object的方法之一,所有的java类都有这个方法,区别只是自己有没有重写的问题。如果没有重写,那么也是直接比较内存地址是否相同。重写了,那就要看它们是怎么重写的。看下面的例子
String str1 = "abc";
String str2 = "abc";
String str3=new String("abc");
String str4=new String("abc");
StringBuffer str5=new StringBuffer("abc");
StringBuffer str6=new StringBuffer("abc");
System.out.println("1:"+(str1==str2));
System.out.println("2:"+(str1.equals(str2)));
System.out.println("3:"+(str2==str3));
System.out.println("4:"+(str2.equals(str3)));
System.out.println("5:"+(str3==str4));
System.out.println("6:"+(str3.equals(str4)));
//System.out.println("7:"+(str4==str5));
System.out.println("8:"+(str4.equals(str5)));
System.out.println("9:"+(str5==str6));
System.out.println("10:"+(str5.equals(str6)));输出结果是1:true2:true3:false4:true5:false6:true8:false9:false10:false解释:String对象的初始化有两种方式,前面已经解释了。可见,str1和str2表示的"abc"都是存放在字符串池中,而在字符串池中,这两个"abc"其实是一个内存中的数据,所以str1==str2是true。str1.equals(str2)是true。str3和str4采用的new方式,那么它们对用的字符串"abc"都是在堆中非字符串池中,分别存放在堆中不同的地方,所以str2==str3是false。str3==str4是false。而String和Strinbuffer除了都是直接继承Object之外,并没有其他的直接联系,两者完全是不相干的类。所以才有str4==str5是false、str4.equals(str5)是false。而StringBuffer也根本没有重写从父类继承的equals方法,所以str5==str6是false。str5.equals(str6)是false。
四、数组的问题数组也是一个引用数据类型,Java中的数组是静态的,也就是说,一旦数组初始化完成指定了它的长度,就不能在去改变它的长度。可是,数组也是和String一样的,引用的对象不可变,但是引用是可变的int[] a=new int[5];a代表的是引用,new int[5]才代表引用的对象。也就是说new int[5]这个真正代表数组的对象在内存里面是不能改变所占内存的大小,但是,却可以去改变数组变量a的引用,指向别的数组对象。在来说下数组在Java中的内存分配问题。数组的引用是放在栈中的,而引用的对象是放在堆中的,不管这个数组中的元素是基本数据类型,还是引用数据类型。只要记住一点:在Java中,所有局部变量都是放在栈里面保存的,不管是基本数据类型的变量,还是引用数据类型的变量,都是存储在各自的方法栈区;但引用类型变量所引用的对象,都是放在堆内存中的。值得一说的是,如果是一个引用类型的数组,例如String[] str=new String[6];引用str存放在栈里面,而str指向的堆内存中也是引用,它说指向的引用才真正的指向堆内存中的字符串。
&&国之画&&&& &&
版权所有 京ICP备号-2
迷上了代码!2013年12月 Web 开发大版内专家分月排行榜第三
2013年12月 Web 开发大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。您所在的位置: &
string类的c_str方法使用不当
string类的c_str方法使用不当
刘新浙/刘玲/王超/李敬娜 等
人民邮电出版社
《从缺陷中学习C/C++》第3章库函数问题,本章主要介绍库函数的使用中会遇到的问题。使用库函数可以降低软件开发的难度,提高代码编写的效率。本节为大家介绍string类的c_str方法使用不当。
3.5& string类的c_str方法使用不当
int&main() &{ &&&&&string&str&=&&abcd&; &&&&&const&char&*pcStr&=&str.c_str(); &&&&&printf(&cStr=%s,&pcStr=%p\n&,&pcStr,&pcStr); &&&&&str.append(&efg&); &&&&&const&char&*pcStr2&=&str.c_str(); &&&&&printf(&cStr2=%s,&pcStr2=%p\n&,&pcStr2,&pcStr2); &&&&&return&0; &}&
在语句&str.append(&efg&)&之后,指针pcStr成为&野指针&,可能造成严重后果。
string类的c_str()方法返回的是一个常量指针,它所指向地址的内容是不会改变的。上述代码中,在没有改变str的值之前,指针变量pcStr就是str的首地址,但当通过append函数对str追加了一些内容之后,因为append会先开辟一段新内存,然后再将原来的值复制过来,所以,str的首地址已经发生了改变,而pcStr指向的内存实际上已经被释放,因而pcStr成为&野指针&。
改正的方法是,在将str.c_str()赋值给pcStr之后,不去改变str的值 ;或者当需要改变str的值时,使用strcpy函数把str.c_str返回的内容复制出来,再赋值给pcStr。下面正确代码使用的是第二种方法。
int&main() &{ &&&&&string&str&=&&abcd&; &&&&&char&pcStr[20]; &&&&&strcpy(pcStr,str.c_str()); &&&&&str.append(&efg&); &&&&&return&0; &} &
最好使用strcpy函数来操作string类的c_str方法返回的指针,从而避免带来&野指针&。
&【责任编辑: TEL:(010)】&&&&&&
关于&&的更多文章
Linux之父对C++进行了炮轰,说它是糟糕程序员的垃圾语言,可谓是
本书描述了黑客用默默无闻的行动为数字世界照亮了一条道路的故事。
不同于背包客的极限挑战,不同于徒步者的风沙雪雨,不
复盘是围棋中的一种学习方法,指的是在写完一盘棋之后
在当今快速变化的商业世界里,公司要想保持领先地位,
本书分为4个部分共24章,以插件开发为中心,围绕插件开发主要介绍SWT/JFace的应用、插件扩展点的实现,以及GEF、EMF和RCP的相关
51CTO旗下网站}

我要回帖

更多关于 append 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信