当我尝试释放这个结构中的任何内容时出现问题。首先是头文件中的结构定义:
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的调用注释掉时,程序按预期运行,但是如果尝试释放某些东西,则会崩溃。我已经尝试注释掉除结构体中的单个成员之外的所有行,并仍然崩溃,所以在这里做错了什么。
这个程序的想法是有一个大型文本文件处理程序,逐行读取并让我做一些操纵行数据的事情,然后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的内存。也许我只是在到处传递这些指针(比如将指向“line”的指针传递给分配给struct成员的函数),但在我的想法中,这一切都得到了很好的解决。我知道struct的每个成员都被malloc了,所以在我从下往上工作时应该能够释放所有内容然后释放struct。然后我可以再把另一个指针放到row struct上,再次开始工作。 我这样做的原因是因为我想要能够处理极大的数据集。这是一个结构性重写程序,它过去使用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”使用错误的目录)。
我希望已经包含了足够的内容,让人们清楚我在使用malloc分配指针后正在做什么,现在我已经包含了rowDestructor()代码。感谢到目前为止的评论。
如果我的C实现本质上有任何问题,我希望能解决它。同时,我将清理开发环境,并确保正确路径到所有组件,看看能否获得更好的结果。
rowDestructor
的代码在哪里? - Joshua Taylormalloc
函数的返回值转换为其他类型,因为这样会掩盖一些微妙的错误;(2)不要乘以sizeof(char)
,因为它从不需要且只会让代码变得混乱。 - paxdiablo-Wall
)编译您的代码,并修复代码,直到没有更多的警告弹出。然后使用符号(对于GCC为-g
)进行编译,并使用Valgrind运行应用程序。修复代码,直到Valgrind不再给出任何警告/错误。 - alk