BCB2010 关于char* 的小问题

tulipcaicai 2011-06-21 10:57:26
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Label1->Caption = Edit1->Text;
AnsiString str;
char *str1;
String str2;
str = Edit1->Text;
str1 = Edit1->Text.t_str();
Label2->Caption = str1;
str2 = str1;
Label3->Caption = str2;

}


为什么 在执行完这一句后
Label2->Caption = str1;


str1的值变成1了?
...全文
1067 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
aidame 2013-01-19
  • 打赏
  • 举报
回复
//慎用 .c_str()/.t_str()/.w_str() 的返回值。特别是不要 char *p = str.c_str(); 这样使用。 ccrun说得太好了,这是教训中的教训哪!
tulipcaicai 2011-07-05
  • 打赏
  • 举报
回复
明白了,谢谢各位。结贴!
microheart 2011-07-01
  • 打赏
  • 举报
回复
str1 = Edit1->Text.t_str();
BCB的相关书箱讲到AnsiString类时,都会强调不要直接使用t_str()的返回结果的啊!再次帮楼主强调一下,哈哈!
勉励前行 2011-06-30
  • 打赏
  • 举报
回复
String str2 = str1;//調用拷贝构造函数, 但拷贝构造函数並沒有復制字符串,只是增加字符串引用數
str1 = "other" ;//這裡構造新的字符串,但並沒有將舊的字符串析構,因為引用數 > 0 , 所以 str2 指向依然有效。
勉励前行 2011-06-30
  • 打赏
  • 举报
回复
String str1 = "New Text" ;
String str2 = str1; // str2 沒有直接復制字符串, 而且共用了.

if(str1.c_str() == str2.c_str())//這時兩個指針指向同樣的內存
ShowMessage("共用");
else
ShowMessage("不共用");

str1 = "other" ;//寫時復制一份。不影響str2
if(str1.c_str() == str2.c_str())//此時內存已經不同 了

Bosman 2011-06-28
  • 打赏
  • 举报
回复
7.注意 String 对象的引用机制.String 类采用写时复制的方法来提高复制时的效率,写代码时要时刻注意这一点.
String str1 = "New Text" ;
String str2 = str1; //此时,str2 str1 共用一个字符串

我对这个有怀疑.特验证了一下,也证实怀疑的正确性:

改变str1内容,对str2不会影响.很明显,如果两个String变量共用一个字符串,那么会给使用者带来无限的出错机率.c++ builder不会愚蠢到这般地步.str2=str1最多是调用拷贝构造函数而已.
周药师 2011-06-23
  • 打赏
  • 举报
回复
对于复制的时候尽量使用strcpy()、_tcscpy(), 不要直接返回给指针
如果一个函数要求char*,wchar_t *参数,可以使用c_str() ; t_str()方法;
比如:

#include <TCHAR.h>
#include <stdio.h>

TCHAR c[20];
String s="你好";
_tcscpy(c,s.t_str()); //_tcscpy()

char c1[20];
AnsiString s1="1234";
strcpy(c1,s1.c_str()); //strcpy()

char c2[100];
AnsiString s3 = "Hello World!";
sprintf(c2,"%s", s3.c_str());//printf()


这样不会出错,因为函数调用c_str(),t_str()返回的是一个临时指针的参数,不能对其进行操作

所以建议除了函数需要求使用char*,wchar_t *参数时,其余的地方坚决不用
ccrun.com 2011-06-23
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 tulipcaicai 的回复:]
报了8条错误:....
[/Quote]

这是因为我在的测试工程中,_TCHAR映射为wchar_t,String格式化的时候,常量字符串就是wchar_t *的。而你的应用中,工程选项中的_TCHAR映射为char, 所以报类型不匹配。这个和我要解释的东西其实没多大关联。

9楼大牛PPower解释的灰常清楚了。
勉励前行 2011-06-23
  • 打赏
  • 举报
回复
1、分清对象的生命期,是否临时对象.对于有属性的BCB来说,更是要注意这一点.
String str = Edit1->Text ;
wchar_t *p1 = str.c_str();
wchar_t *p2 = Edit1->Text.c_str();
这里会有多个对象产生,
1) str 这个被声明的对象 及 p1 p2 两个指针,在函数中均是局部变量
2) Edit1->Text 调用该属性,会返回一个临时对象.
3) C++ 被人批的其中一个原因就是很容易不恰当地产生多余的临时对象,造成效率低下.

2.注意属性带来的不确定性.为了程序安全可靠,我们调用属性,就认为是调用一个函数的返回值(右值).
值得我们注意的是并非调用所有的String属性都会产生一个临时对象,这要看该属性是如何实现的,调用 Edit1->Text 是产生一个临时对象的.一般来说,属性声明为
read = GetXXXX 这种方式的均产生一个临时对象, read = FText 类型的,则没有产生额外的对象,
调用Edit1->Text.c_str();相当于 Edit1->GetText().c_str();

3. 一个指向临时对象内部的指针是无意义的
wchar_t *p2 = Edit1->Text.c_str();//这个就是无意义的野指针.
4.在对象的生命期内,使用指向其内部的指针是可以的
wchar_t *p1 = str.c_str();//这个是可以的,在str 的生命还没结束前是可用的.
5.用指针得时刻注意内存的变化.
String str = Edit1->Text ;
wchar_t *p1 = str.c_str();
str = "New Text" ; //此时,内存已变化,指针p1已无意义.
6.慎用指针,特别注意不要破坏对象的内存布局.
str = "New Text" ;
wchar_t *p1 = str.c_str();
*(p1+2) = 0 ; //这个写操作破坏了对象的内存布局,使对象对内存的解析产生不确定性
ShowMessage(str);
ShowMessage(str+"为什么这个串不会被显示.");
c_str()本应返回的是一个 const 指针,但因为种种原因,BCB并没有如此实现.

7.注意 String 对象的引用机制.String 类采用写时复制的方法来提高复制时的效率,写代码时要时刻注意这一点.
String str1 = "New Text" ;
String str2 = str1; //此时,str2 str1 共用一个字符串
String str3 = str1.c_str(); //此时,str3没有与 str2 str1 共用一个字符串,是另外分配内存,并做字符串复制了.
wchar_t *p1 = str2.c_str();
*p1 = 'A' ; //这个操作,同时修改了 str1 str2 , 因为str1 str2 是共用这块内存的

写时复制,为我们带来了效率,但同是也带来了内存管理的复杂性,当操作指针时,要慎重.

最后,因为以上种种原因, 建议慎用 c_str() ; t_str();data() ; 等函数,而t_str()则更是离谱,调用它,可能字符串会因此改变,我们在编程中,最怕的就是可能会变化,但不一定会变. 所以更要慎用.
tulipcaicai 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 ccrun 的回复:]

简单例程:
String strText = "abc";

// 记录String对象的.c_str()返回指针
wchar_t *p = strText.c_str();

// 显示出p所指向的信息
ShowMessage(String().sprintf(TEXT("p 长度: %d, 内容: %s"), wcslen(p), p));

// 重新给String对象赋……
[/Quote]

我在BCB2010试着做了,还是有错误。妖哥能不能给点这方面的资料,我想系统的学一下,从BCB2007转过来有点不大适应这宽字符集了。

报了8条错误:

[BCC32 Error] Unit1.cpp(25): E2034 Cannot convert 'const char *' to 'const wchar_t *'
Full parser context
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
[BCC32 Error] Unit1.cpp(25): E2342 Type mismatch in parameter 'format' (wanted 'const wchar_t *', got 'const char *')
Full parser context
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
[BCC32 Error] Unit1.cpp(33): E2034 Cannot convert 'const char *' to 'const wchar_t *'
Full parser context
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
[BCC32 Error] Unit1.cpp(33): E2342 Type mismatch in parameter 'format' (wanted 'const wchar_t *', got 'const char *')
Full parser context
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
[BCC32 Error] Unit1.cpp(37): E2034 Cannot convert 'const char *' to 'const wchar_t *'
Full parser context
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
[BCC32 Error] Unit1.cpp(37): E2342 Type mismatch in parameter 'format' (wanted 'const wchar_t *', got 'const char *')
Full parser context
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
[BCC32 Error] Unit1.cpp(40): E2034 Cannot convert 'const char *' to 'const wchar_t *'
Full parser context
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
[BCC32 Error] Unit1.cpp(40): E2342 Type mismatch in parameter 'format' (wanted 'const wchar_t *', got 'const char *')
Full parser context
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
Unit1.cpp(18): parsing: void _fastcall TForm1::Button1Click(TObject *)
ccrun.com 2011-06-22
  • 打赏
  • 举报
回复
简单例程:
String strText = "abc";

// 记录String对象的.c_str()返回指针
wchar_t *p = strText.c_str();

// 显示出p所指向的信息
ShowMessage(String().sprintf(TEXT("p 长度: %d, 内容: %s"), wcslen(p), p));

// 重新给String对象赋个值
strText = "defghijklmn";

// 再次Show出p的信息,按理说,应该是显示新的"defghijklmn"
// 但是结果显示仍然是"abc",也就是说p仍然指向上一次显示的内容
// 而这块内存区域有可能被别的数据覆盖
ShowMessage(String().sprintf(TEXT("p 长度: %d, 内容: %s"), wcslen(p), p));

// 正确的值应该是:
p = strText.c_str();
ShowMessage(String().sprintf(TEXT("str 长度: %d, 内容: %s"), strText.Length(), p));

// 建议直接使用String对象的.c_str(),尽量不要把这个指针赋给p然后在后面的代码中再使用p
ShowMessage(String().sprintf(TEXT("str 长度: %d, 内容: %s"), strText.Length(), strText.c_str()));


以上代码适用于C++Builder2009/2010/XE,因为2009以后的版本中String映射为UnicodeString,所以String对象的.c_str()返回的是wchar_t *类型的值,如果要返回char *数据,可以用AnsiString强制转换再通过.c_str()获取。
wangcftxz 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 ccrun 的回复:]

慎用 .c_str()/.t_str()/.w_str() 的返回值。特别是不要 char *p = str.c_str(); 这样使用。
[/Quote]
请问妖哥能否给个例子 这样更容易理解
谢谢
ccrun.com 2011-06-22
  • 打赏
  • 举报
回复
慎用 .c_str()/.t_str()/.w_str() 的返回值。特别是不要 char *p = str.c_str(); 这样使用。
缘中人 2011-06-22
  • 打赏
  • 举报
回复
这样试试
AnsiString ansistr;
ansistr = AnsiString(Edit1->Text);
str1 = ansistr.c_str();
开始领悟 2011-06-22
  • 打赏
  • 举报
回复
char str1[256]="";
strcpy(str1, Edit1->Text.c_str());
bigfog 2011-06-22
  • 打赏
  • 举报
回复
对,是这样的
char *str1 = Edit1->Text.t_str();//返回的只是临时指针,当这行结束,指针就结束了
Label2->Caption = str1; //这句就是错误的,恰好内存中的临时变量还没被破坏
//下一行就出错

应该改成
wchar_t *str1 = Edit1->Text.t_str();//就好多了


纯冰糖 2011-06-22
  • 打赏
  • 举报
回复
设置断点调试一下啊

13,825

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧