s在窗体中声明为tstrings;procedure TForm1.Button1Click(Sender: TObject);
begin
    Memo1.Lines:=NineNineMultiTable;
    s.Free;  <-这里能够正确执行
end;function TForm1.NineNineMultiTable:TStrings;
var
    i,j:Integer;
    cs: string;
begin
    i:=1;
    s:=TStringList.Create;
    s.BeginUpdate;
    for i := 1 to 9 do
    begin
        j:=1;
        cs:='';
        while (j<=i) do
        begin
            cs:= cs + '  ' + IntToStr(j)+'× '+IntToStr(i)+'='+IntToStr(j*i);
            Inc(j);
            if (i<j) then
            begin
                s.Add(cs);
                s.Add('');
            end;
        end;
    end;
    s.EndUpdate;
    Result:=s;
    //s.Free;<-放这里则不能执行,对象被释放掉了
end;谁能解释一下放在这两个地方的区别在哪儿?本来想把s的定义放在函数内部,因为是临时对象,但就因为这个问题放窗体里了。

解决方案 »

  1.   

    你放在函數內部的話,對象被你釋放了,MEMO1.lines  從哪裏加載這個 TStringList 呢??
      

  2.   


    //s放在函数内部就行了
    function TForm1.AddContent:TStrings;
    begin
      Result:=TStringList.Create;  Result.Add('111');end;procedure TForm1.btn1Click(Sender: TObject);
    begin
      memo.Lines:=AddContent;
    end;
      

  3.   

    既然要做为返回值,还没等返回,就被你释放了怎么行.
    帮你改改逻辑,s做为临时变量,由调用方面负责创建和释放.
    procedure TForm1.Button1Click(Sender: TObject);
    var
      s: TStrings;
    begin
      s := TStringList.Create; {创建}
      NineNineMultiTable(s); {操作}
      Memo1.Lines := s; {使用}
      s.Free; {用完才释放}
    end;procedure TForm1.NineNineMultiTable(out s: TStrings);
    var
      i, j: Integer;
      cs: string;
    begin
      s.BeginUpdate;
      for i := 1 to 9 do
      begin
        j := 1;
        cs := '';
        while (j <= i) do
        begin
          cs := cs + '  ' + IntToStr(j) + ' × ' + IntToStr(i) + ' = ' + IntToStr(j * i);
          Inc(j);
          if (i < j) then
          begin
            s.Add(cs);
            s.Add('');
          end;
        end;
      end;
      s.EndUpdate;
    end;
      

  4.   

    NineNineMultiTable的返回结果是对s的一个引用,你释放掉s,那Result也就over了,如果你非要这样做的话,可以把s复制给Result,当着这很不好
      

  5.   

    NineNineMultiTable的作用是在栈中创建一个指针引用,而后在堆中创建一个空间存储StringList的内容,因为栈数据是系统自动清理的,当出此过程后栈引用指针就会被重置,而堆数据是由用户来人工处理(WIN32平台下的程序都是这样,.NET或JAVA有回收机制)。
    这时memo.Lines:=NineNineMultiTable,memo.lines就接管了TStringlist创建的引用,使用memo.lines就能访问在局部过程中创建的堆内存了!
    有了这个依据,我想楼主自己想想就应该能明白了!
      

  6.   

    可是我还有个问题是button1click最后不是执行s.free;了吗?那么在界面上memo1的内容应该消失了才对,可是情况不是这样的,所以很纳闷儿
      

  7.   

    TMemo显示的文本存放在自己的内存空间里.这么跟你解释吧,TMemo把s里的文本抄了一遍然后写在自己的显示框里.所以不会受s释放的影响.
      

  8.   

    7楼a:= b;
    b:= '';
    那a也等于''吗??发现问得好怪喔.
      

  9.   

    可是代码是这样写的Memo1.Lines:=NineNineMultiTable;这不是指针的传递吗?
    如果象楼上JPEXE所说,那s.free放在两个地方都可以才对呀?
    JPEXE在4楼的回复给我很好的思路,谢谢!
      

  10.   

    不好意思,我回答错误,2楼的代码有内存泄露!//Memo的源代码
    FLines: TStrings;procedure SetLines(Value: TStrings);procedure TCustomMemo.SetLines(Value: TStrings);
    begin
      FLines.Assign(Value);//进行对象的深度复制
    end;
      

  11.   

    可是代码是这样写的Memo1.Lines:=NineNineMultiTable;这不是指针的传递吗? 
    -----------------------
    这个不是简单的指针传递,刚开始我也被迷惑了,是将TStringList进行对象clone的过程
      

  12.   

    像这类情况,到底是指针?引用?还是值拷贝?楼主应该多亲自试试,自然就知道了,实践才是硬道理.另外,Delphi的VCL都是有源码的,有不明白的地方时,完全可以跟进入源码看看到底是怎么操作的,就什么疑惑都没有了.
      

  13.   

      1.要达到你的目的返回s.text就可以,s.text是string类型的,这样就可以把s当局部变量了。
      2.有疑问是因为你不了解lines属性。看看TMemo.Lines属性的代码:     property Lines: TStrings read FLines write SetLines;    procedure TCustomMemo.SetLines(Value: TStrings);
       begin
        FLines.Assign(Value);
       end;   FLines是TStrings类型,所以看它的Assign方法procedure TStrings.Assign(Source: TPersistent);
    begin
      ....
      AddStrings(TStrings(Source));  ...
      inherited Assign(Source);
    end;  最后看AddStrings的实现: 发现是内容复制,S.free是不会影响memo.lines的内容。procedure TStrings.AddStrings(Strings: TStrings);
    var
      I: Integer;
    begin
      BeginUpdate;
      try
        for I := 0 to Strings.Count - 1 do
          AddObject(Strings[I], Strings.Objects[I]);
      finally
        EndUpdate;
      end;
    end;
      

  14.   


    界面上的内容不显示,只是UI的展示问题。
       Memo1.Lines:=NineNineMultiTable;
       s.Free;  <-这里能够正确执行
    实际已经将Memo1.Lines给Free了,程序退出时是要出错的。正确的做法,应类似4楼