保存和堆栈溢出

Posted

技术标签:

【中文标题】保存和堆栈溢出【英文标题】:Saving and Stack Overflows 【发布时间】:2009-03-30 16:34:23 【问题描述】:

我在 Delphi 中保存各种大型数据库类型时遇到问题。它包含一个 TItem 的数组 [1..3500],而 TItem 又包含两个数组 [1..50] 和 [1..20]。除非我将变量设置为指针并使用下面的 GetMem、FreeMem 命令,否则我会出现堆栈溢出,但是我无法保存它。代码如下。

procedure TDatabase.SaveDB;  
var  
 TempDB: ^TSaveDB;  
 K, X: integer;  
 sComment, sTitle, sComposer, sISDN, sCategory: string;  
begin  
GetMem(TempDB, SizeOf(TSaveDB));  

TempDB.CatCount := fCategoryCount;  
TempDB.ItemCount := fItemCount;  

for K := 1 to fCategoryCount do  
 TempDB.Categories[K] := fCategories[K];  

for K := 1 to fItemCount do  
 begin  
  fItems[K].ReturnSet(sTitle, sComposer, sCategory, sISDN, sComment);  
  with TempDB.Items[K] do  
   begin  
    Title := sTitle;  
    Composer := sComposer;  
    Category := sCategory;  
    ISDN := sISDN;  
   end;  

  TempDB.Items[K].Comments[1] := Copy(sComment, 1, 255);  
   Delete(sComment, 1, 255);  
  TempDB.Items[K].Comments[2] := Copy(sComment, 1, 255);  
   Delete(sComment, 1, 255);  
  TempDB.Items[K].Comments[3] := Copy(sComment, 1, 255);  
   Delete(sComment, 1, 255);  
  TempDB.Items[K].Comments[4] := Copy(sComment, 1, 255);  
   Delete(sComment, 1, 255);  

  TempDB.Items[K].KeyWCount := fItems[K].GetKeyCount;  

  for X := 1 to fItems[K].GetKeyCount do  
   TempDB.Items[K].Keywords[X] := fItems[K].GetKeywords(X);  
 end;

AssignFile(DBSave, fSaveName);  
 Rewrite(DBSave);  
  Write(DBSave, TempDB);  
Closefile(dBSave);  

FreeMem(TempDB, sizeof(TSaveDB));  
end;  

【问题讨论】:

【参考方案1】:

使用 GetMem 或 SetLength 或 TList/TObjectList 并一次将一个 TSaveDB 写入文件。或者 更改文件类型并使用 BlockWrite 一次将其全部写入。甚至更好:使用 TFileStream。

【讨论】:

【参考方案2】:

您的问题出在“写”语句中。用任意指针做事会导致各种奇怪的行为。如果你使用 TFileStream 而不是当前的方法重写它,你会容易得多。

【讨论】:

【参考方案3】:

扩展梅森的答案:

从不读取或写入指针,句点。要从中获得任何合理的结果需要很大的运气,而在现实世界中,当您不只是再次运行程序时,成功的几率会从无穷小变为零。

相反,您需要读取和写入指针指向的内容。

另外请注意,任何长度未在声明中命名的字符串都是指针,除非您在兼容模式下运行,将“string”转换为“string[255]”——此模式仅适用于与我们仅有的字符串时编写的非常古老的代码兼容。

由于您似乎只是将整个内容写出来,因此没有理由玩具有固定大小记录的游戏。只需将每个字段写入流,在写入字符串本身之前写入字符串的长度,以便您可以正确加载它。文件会更小,不会被截断。

另外,正如他所说,使用 tFileStream。旧格式用于保留在磁盘上的记录文件,在这种情况下没有理由使用它。

【讨论】:

很好的答案。只写入尽可能多的字段不仅会减小文件大小,而且还会防止代码在违反数据类型中的硬编码限制之一时崩溃。 他似乎正在将其复制到 String[255],因此结果是截断,而不是崩溃。 @Loren:这不是我的意思——如果 fItemCount > High(fItems) 或 fCategoryCount > High(Categories),OP 代码中会发生什么?它会崩溃。没关系,除了 0、1 和无穷大之外的限制是任意的。为什么只有 3500 项?为什么最大评论长度是 1220? 3500 限制是在程序范围内施加的,它不会在保存例程中被破坏。评论将剪辑到 1220,但不会崩溃。 我的意思是 1) 从发布的代码中看不出总是遵守限制,并且 2) 任何任意限制(不遵循技术限制)都是不好的。

以上是关于保存和堆栈溢出的主要内容,如果未能解决你的问题,请参考以下文章

什么是堆栈溢出?

(原创)攻击方式学习之 - 缓冲区溢出(Buffer Overflow)

怎么解决 LINUX 堆栈溢出内存的问题

函数 堆栈溢出

怎么防止堆栈溢出

堆栈溢出一般是由啥原因导致的?