4

当我运行尝试释放此结构中的任何内容时,我遇到了问题。首先是标题中的结构定义:

    typedef struct{
int* rType;
unsigned long int numCols;
char* rString;  //The literal string, NULL delimited
int rsSize;     //The size of the string, since NULLS can't be used to find the string end
int* colsIndex; //Where each new column starts in rString
long* iColVals;   //integer version of the column
double* dColVals; //double precision value of column
}  row_t ;

然后在这里可以创建结构的实例:

row_t* delimitLine(char* line, char* delimList, char delimListSize)
{
row_t* thisRow;
.
.
.
//Make a place for this stuff in memory
thisRow = (row_t*) malloc(sizeof(row_t));
if(thisRow==NULL) return NULL;
.
.
.
thisRow->rString = line;

//Make Row Mem

    //colsIndex
    thisRow->colsIndex = (int*) malloc(numCols*sizeof(int));
    if(thisRow->colsIndex==NULL) return NULL;   

    //rType
    thisRow->rType = (int*) malloc(numCols*sizeof(int));
    if(thisRow->rType==NULL) return NULL;   

    //iColVals
    thisRow->iColVals = (long*) malloc(numCols*sizeof(long));
    if(thisRow->iColVals==NULL) return NULL;    

    //dColVals
    thisRow->dColVals = (double*) malloc(numCols*sizeof(double));   
    if(thisRow->dColVals==NULL) return NULL;    
.
.
.
return thisRow;

那么这里是如何创建“线”的:

char* RBreadLine(fifo_t* fifo)
{
char* outbuf = NULL;
.
.
.
outbuf = (char*) malloc(sizeof(char)*(cnt+1));
.
.
.
return outbuf;
}

最后调用顺序:

main()
{
row_t* row = NULL;
.
.
.
while(kg>=0)
{
//test condition to exit loop not shown
line = RBreadLine(fifo);
.
.
.

 row = delimitLine(line, delimList, delimListSize);
//some code to manipulate the row data here
 printRow(row);
 rowDestructor(row);



}

}

当我注释掉对 rowDestructor 的调用时,程序按预期运行,但如果我尝试释放任何东西,程序就会崩溃。我已经尝试评论除了 struct 的单个成员之外的所有行,但仍然会崩溃,所以我在这里做错了。

这个想法是有一个大型文本文件处理程序,它可以逐行读取并让我做一些事情来操作行数据,然后 printRow() 输出最终结果。

简单的测试用例是输出从 delimitLine 函数出来的值(它只是分配内存并用数据填充行结构)。

当这个过程完成后,我应该释放内存并重新开始。如果我不调用析构函数,则该程序按预期工作,而是在每次新调用 RBreadLine() 和 delimitLine() 时简单地孤立这些指针。

如果我调用 rowDestructor(),则程序在第一行之后崩溃(在第一次调用 rowDestructor() 时):

 Now to start outputting line
    1)  2)  3)  4)  5)  6)  7)  8)  9)  10)  (-10)63.116722551236001948     0       0       0       0       1       1       1       1       1       0    1

    Aborted (core dumped)

也许我对 malloc() 或 free() 有一些不明白的地方,但似乎如果我可以从 struct 成员访问有效数据而不会出现错误并且不会导致崩溃,那么 free 应该能够释放具有被malloc'd。

也许我只是通过到处传递这些指针来做坏事(比如将指向“line”的指针传递给将其分配给结构成员的函数),但在我看来,这一切都很好。我知道结构的每个成员都被 malloc 了,所以我应该能够在我向上工作时释放它,然后释放结构。然后我可以将另一个指针转储到行结构上并再次执行。

我这样做的原因是因为我希望能够处理非常大的数据集。这是一个程序的结构重写,它曾经用 fread 将它全部加载到内存中,然后处理它,但是我的一些数据集导致计算机内存不足......所以我将求助于块处理方法.

一旦我可以成功释放一行,然后我可以通过创建 row_t** 来构建它,我可以使用 FIFO 缓冲区概念将行循环到 row_t**,然后我可以向前和向后查找文本文件合理的数量(例如应用 FIR 滤波器),但不需要将整个文件加载到内存中。

例如,行 FIFO 会将这些新的 row_t* 结构存储到 row_t** 上,并且在填充循环缓冲区并开始覆盖旧指针后释放旧的结构......这就是我要处理的地方。

我认为对这个问题有一个答案将是我对 malloc() 和 free() 理解的一个突破,或者可能澄清一些关于指针和结构的东西。

感谢您的任何意见。

编辑:我很抱歉忽略了我的问题中最重要的部分:

void rowDestructor(row_t* thisRow)
{
    //rString
    free(thisRow->rString);

    //colsIndex
    free(thisRow->colsIndex);   

    //rType
    free(thisRow->rType);   

    //iColVals
    free(thisRow->iColVals);    

    //dColVals
    free(thisRow->dColVals);

    //finally kill the whole thing
    free(thisRow);
}

而且,由于其他人提到了编译器标志,这就是我正在使用的:

gcc  -Wall laproc.c utils.c csvsurgeon.c -lm -o csv-surgeon

(laproc.c 是我需要与数学库链接的特定信号处理代码,在此示例中,我已将其简化为不调用这些函数以排除它们的位置)

我正在使用这个版本的 gcc:

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-cygwin/4.5.3/lto-wrapper.exe
Target: i686-pc-cygwin
Configured with: /gnu/gcc/releases/respins/4.5.3-3/gcc4-4.5.3-3/src/gcc-4.5.3/configure --srcdir=/gnu/gcc/releases/respins/4.5.3-3/gcc4-4.5.3-3/src/gc
c-4.5.3 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/lib --datadir=/usr/share --localstatedir=/var --sysco
nfdir=/etc --datarootdir=/usr/share --docdir=/usr/share/doc/gcc4 -C --datadir=/usr/share --infodir=/usr/share/info --mandir=/usr/share/man -v --with-g
mp=/usr --with-mpfr=/usr --enable-bootstrap --enable-version-specific-runtime-libs --libexecdir=/usr/lib --enable-static --enable-shared --enable-shar
ed-libgcc --disable-__cxa_atexit --with-gnu-ld --with-gnu-as --with-dwarf2 --disable-sjlj-exceptions --enable-languages=ada,c,c++,fortran,java,lto,obj
c,obj-c++ --enable-graphite --enable-lto --enable-java-awt=gtk --disable-symvers --enable-libjava --program-suffix=-4 --enable-libgomp --enable-libssp
 --enable-libada --enable-threads=posix --with-arch=i686 --with-tune=generic --enable-libgcj-sublibs CC=gcc-4 CXX=g++-4 CC_FOR_TARGET=gcc-4 CXX_FOR_TA
RGET=g++-4 GNATMAKE_FOR_TARGET=gnatmake GNATBIND_FOR_TARGET=gnatbind --with-ecj-jar=/usr/share/java/ecj.jar
Thread model: posix
gcc version 4.5.3 (GCC)

也许这是我的问题......我已经重新编译了以下其他 gcc 版本:

Using built-in specs.
COLLECT_GCC=C:\Program Files\CodeBlocks\MinGW-newer\bin\gcc.exe
COLLECT_LTO_WRAPPER=c:/program files/codeblocks/mingw-newer/bin/../libexec/gcc/mingw32/4.5.2/lto-wrapper.exe
Target: mingw32
Configured with: ../../src/gcc-4.5.2/configure --build=mingw32 --enable-languages=c,c++,ada,fortran,objc,obj-c++ --enable-threads=win32 --enable-libgo
mp --enable-lto --enable-fully-dynamic-string --enable-libstdcxx-debug --enable-version-specific-runtime-libs --with-gnu-ld --disable-nls --disable-wi
n32-registry --disable-symvers --disable-werror --prefix=/mingw32tdm --with-local-prefix=/mingw32tdm --enable-cxx-flags='-fno-function-sections -fno-d
ata-sections' --with-pkgversion=tdm-1 --enable-sjlj-exceptions --with-bugurl=http://tdm-gcc.tdragon.net/bugs
Thread model: win32
gcc version 4.5.2 (tdm-1)

还有另一个版本

Using built-in specs.
Target: mingw32
Configured with: ../../gcc-4.4.1/configure --prefix=/mingw --build=mingw32 --enable-languages=c,ada,c++,fortran,objc,obj-c++ --disable-nls --disable-w
in32-registry --enable-libgomp --enable-cxx-flags='-fno-function-sections -fno-data-sections' --disable-werror --enable-threads --disable-symvers --en
able-version-specific-runtime-libs --enable-fully-dynamic-string --with-pkgversion='TDM-2 mingw32' --enable-sjlj-exceptions --with-bugurl=http://www.t
dragon.net/recentgcc/bugs.php
Thread model: win32
gcc version 4.4.1 (TDM-2 mingw32)

使用 4.4.1 版本,它会在运行中的不同点出现段错误。在几次运行中,它甚至在没有段错误的情况下通过了一次,所以也许我遇到了编译器问题。因为我有 cygwin,所以编译器可能是混合实用程序和链接器(使用“/bin”的错误目录)。

既然我已经包含了 rowDestructor() 代码,我希望我已经包含了足够的内容来清楚地说明我正在使用这些 malloc 指针做什么。感谢到目前为止的评论。

如果我的 C 实现本身有任何问题,我想修复它。与此同时,我将清理我的开发环境,看看是否可以通过确保所有组件的正确路径来获得更好的结果。

4

1 回答 1

3

事实证明我的记忆管理很好(难怪我把头发拔掉了)。我在 Linux 上编译了这个程序,很快发现在分配内存时出现“off by one”错误,因此我访问了一些超出范围的内存。程序故障在 Linux 机器上立即出现,而 Windows 会在终止程序之前让程序运行一段时间。

对于那些感兴趣的人来说,这就是问题所在:

 row_t* delimitLine(char* line, char* delimList, char delimListSize)
{
//<Analyze "line" to count number of data fields>
.
.
.

这就是它的完成方式:

//Populate Row Data 
thisRow->numCols = numCols+1;   

这就是它的固定方式:

//Populate Row Data 
numCols+=1;
thisRow->numCols = numCols; 

这是一个关于为什么这是一个问题的提示

.
.
.
    //colsIndex
    thisRow->colsIndex = (int*) malloc(numCols*sizeof(int));
    if(thisRow->colsIndex==NULL) return NULL;   

    //rType
    thisRow->rType = (int*) malloc(numCols*sizeof(int));
    if(thisRow->rType==NULL) return NULL;   

    //iColVals
    thisRow->iColVals = (long*) malloc(numCols*sizeof(long));
    if(thisRow->iColVals==NULL) return NULL;    

    //dColVals
    thisRow->dColVals = (double*) malloc(numCols*sizeof(double));   
    if(thisRow->dColVals==NULL) return NULL;

thisRow->numCols 稍后在程序中用于访问内存,而内存已分配有“numCols”,这将比程序尝试访问的元素少一个元素。

显然,错误的内存访问给 free() 释放此内存带来了一些麻烦。有趣的是,在 Linux 机器上,这会立即产生分段错误,这就是我能够更轻松地将其归零的原因。

我可以将此归结为了解到,有时在提出问题时,即使发布“不相关”的代码也很重要。

我自己解决了,但感谢大家的意见。没有人指出明显的“有你的缺陷”这一事实促使我更深入地挖掘,并评论未在此处发布的代码部分。

于 2013-06-19T17:47:07.137 回答