当我尝试释放这个结构中的任何东西时,我遇到了一个问题。首先是头部中的结构定义:
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;下面是"line“是如何创建的:
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的mem。
也许我只是通过到处传递这些指针来做一些不好的事情(就像将指向"line“的指针传递给一个函数,该函数将其赋值给一个struct成员),但在我看来,这一切都被考虑得很好。我知道结构的每个成员都被malloc了,所以我应该能够在我工作的过程中释放所有的东西,然后释放结构。然后,我可以将另一个指针转储到row结构上,并再次执行它。
我这样做的原因是因为我希望能够处理非常大的数据集。这是对一个程序的结构化重写,这个程序过去是用fread将所有数据加载到内存中,然后处理它,但我的一些数据集导致计算机耗尽memory...so,我将求助于块处理方法。
一旦我可以成功地释放一行,那么我就可以在此基础上构建一个row_t**,我可以使用先进先出缓冲区的概念将行循环到row_t**上,这将允许我以合理的量向前和向后查找文本文件(比如应用FIR过滤器),但不需要将整个文件加载到内存中。
例如,行FIFO会将这些新的row_t*结构存储到row_t**上,然后在填满循环缓冲区并开始覆盖旧的pointers...this之后释放旧的结构。
我认为有了这个问题的答案将是我对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版本中,它将在运行过程中的不同点出现故障。在几次运行中,它甚至成功通过了一次,没有出现seg错误,所以可能我遇到了编译器问题。因为我有cygwin,所以编译器可能是内部混合的实用程序和链接器(使用错误的“/bin”目录)。
既然我已经包含了rowDestructor()代码,我希望我已经包含了足够的内容,可以清楚地说明我正在对这些错误定位的指针做什么。感谢你到目前为止的评论。
如果我的C实现本身就有什么问题,我想要修复它。同时,我将清理我的开发环境,看看是否可以通过确保所有组件的正确路径来获得更好的结果。
发布于 2013-06-20 01:47:07
事实证明,我的内存管理是很好的(难怪我费了很大劲)。我在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机器上,这产生了一个直接的分段错误,这就是为什么我能够更容易地专注于这个问题。
我可以将此归结为学习到,有时当提出问题时,甚至发布“无关”的代码也是很重要的。
我自己解决了这个问题,但还是要感谢大家的投入。事实上,没有人指出一个显而易见的“你的缺陷”,这促使我更深入地挖掘,并评论这里没有张贴的代码部分。
https://stackoverflow.com/questions/16952314
复制相似问题