return 语句之前/期间的 C 分段错误
我在 return 语句之前打印要返回的值,并告诉我的代码打印在函数调用之后立即返回的值。但是,在第一个打印语句之后和第二个打印语句之前,我遇到了分段错误(还值得注意的是,这种情况总是发生在第三次调用该函数时;从来没有第一次或第二次,也从来没有第四次或更晚)。我尝试打印出我正在处理的所有数据,以查看我的代码的其余部分是否做了一些可能不应该做的事情,但到目前为止我的数据看起来不错。这是这个函数:
int findHydrogen(struct Amino* amino, int nPos, float* diff, int totRead) {
struct Atom* atoms;
int* bonds;
int numBonds;
int i;
int retVal;
int numAtoms;
numAtoms = (*amino).numAtoms;
atoms = (struct Atom *) malloc(sizeof(struct Atom) * numAtoms);
atoms = (*amino).atoms;
numBonds = atoms[nPos].numBonds;
bonds = (int *) malloc(sizeof(int) * numBonds);
bonds = atoms[nPos].bonds;
for(i = 0; i < (*amino).numAtoms; i++)
printf("ATOM\t\t%d %s\t0001\t%f\t%f\t%f\n", i + 1, atoms[i].type, atoms[i].x, atoms[i].y, atoms[i].z);
for(i = 0; i < numBonds; i++)
if(atoms[bonds[i] - totRead].type[0] == 'H') {
diff[0] = atoms[bonds[i] - totRead].x - atoms[nPos].x;
diff[1] = atoms[bonds[i] - totRead].y - atoms[nPos].y;
diff[2] = atoms[bonds[i] - totRead].z - atoms[nPos].z;
retVal = bonds[i] - totRead;
bonds = (int *) malloc(sizeof(int));
free(bonds);
atoms = (struct Atom *) malloc(sizeof(struct Atom));
free(atoms);
printf("2 %d\n", retVal);
return retVal;
}
}
正如我之前提到的,我运行它的前两次它工作正常,第三次它打印正确的 retVal 值,然后在到达我调用该函数的位置之前在某处出现段错误,我这样做:
hPos = findHydrogen((&aminoAcid[i]), nPos, diff, totRead);
printf("%d\n", hPos);
I print the value that I'm returning right before my return statement, and tell my code to print the value that was returned right after the function call. However, I get a segmentation fault after my first print statement and before my second (also interesting to note, this always happens on the third time the function is called; never the first or the second, never fourth or later). I tried printing out all of the data that I'm working on to see if the rest of my code was doing something it maybe shouldn't, but my data up to that point looks fine. Here's the function:
int findHydrogen(struct Amino* amino, int nPos, float* diff, int totRead) {
struct Atom* atoms;
int* bonds;
int numBonds;
int i;
int retVal;
int numAtoms;
numAtoms = (*amino).numAtoms;
atoms = (struct Atom *) malloc(sizeof(struct Atom) * numAtoms);
atoms = (*amino).atoms;
numBonds = atoms[nPos].numBonds;
bonds = (int *) malloc(sizeof(int) * numBonds);
bonds = atoms[nPos].bonds;
for(i = 0; i < (*amino).numAtoms; i++)
printf("ATOM\t\t%d %s\t0001\t%f\t%f\t%f\n", i + 1, atoms[i].type, atoms[i].x, atoms[i].y, atoms[i].z);
for(i = 0; i < numBonds; i++)
if(atoms[bonds[i] - totRead].type[0] == 'H') {
diff[0] = atoms[bonds[i] - totRead].x - atoms[nPos].x;
diff[1] = atoms[bonds[i] - totRead].y - atoms[nPos].y;
diff[2] = atoms[bonds[i] - totRead].z - atoms[nPos].z;
retVal = bonds[i] - totRead;
bonds = (int *) malloc(sizeof(int));
free(bonds);
atoms = (struct Atom *) malloc(sizeof(struct Atom));
free(atoms);
printf("2 %d\n", retVal);
return retVal;
}
}
As I mentioned before, it works fine the first two times I run it, the third time it prints the correct value of retVal, then seg faults somewhere before it gets to where I called the function, which I do as:
hPos = findHydrogen((&aminoAcid[i]), nPos, diff, totRead);
printf("%d\n", hPos);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
返回时的分段错误通常表示堆栈损坏。
A segmentation fault while returning is normally an indication of a mangled stack.
很难从这段代码中猜测错误出在哪里(这里几乎每一行代码都可能存在错误) - 可能你在某个地方有缓冲区溢出,但是如果你在 *nix 上,请在下面运行你的程序valgrind,您应该能够很快找到错误。
但这些行看起来很奇怪:
当您丢弃 malloc 返回的指针时,您正在泄漏内存。与
bond
相同,并且在 for 循环中再次出现相同的情况。It's not easy to guess where the error is from this code(there's a potential for bug in just about every line of code here) - likely you have a buffer overrun somewhere, however if you're on a *nix , run your program under valgrind, you should be able to find the error rather quickly.
These lines look odd though:
You're leaking memory, as you discard the pointer returned by malloc. Same thing with
bonds
, and same thing over again inside your for loop.编辑好吧,你左右泄漏内存,但并不完全按照我的想法。固定顺序如下:
具体来说,当您执行以下操作时:
发生的情况是您在步骤 (1) 中分配一些内存并将地址放入
atoms
中。然后,您丢弃该地址,并将原子指向 (2) 中的氨基结构内部的一部分。然后,您分配一个带有单个原子的第二个指针。最后,您调用free
。您以同样的方式对待债券
。您的意思可能是这样的:请注意,如果 Atom 有任何指针组件,您可能需要执行 for 循环并单独复制原子及其内容,然后您必须单独复制它们>返回点免费。
...或者如果您只想从结构中读取原子数据,则可能只是这样:
有关
diff
中的空间量和其他问题的其他答案可能也值得研究。编辑:修复了调用顺序以匹配代码示例。
EDIT Well, you're leaking memory left and right, but not quite in the way I was thinking. Fixed sequence below:
Specifically, when you do:
What is happening is that you are allocating some memory and putting the address in
atoms
in step(1). Then, you toss away that address and instead pointatoms
at part of the inside of youramino
structure in (2). Then you allocate a second pointer with a single atom. Finally, you callfree
on that. You treatbonds
the same way. You probably mean something like this:Note that if an Atom has any pointer components you might want to do a
for
loop and copy the atoms individually along with their contents, which you would then have to individuallyfree
at the return point....or maybe just this if you are only wanting to read the atoms data from the structure:
Other answers talking about the amount of space in
diff
and other issues are probably also worth investigating.EDIT: fixed the sequence of calls to match the code sample.
这里有很多问题。
我注意到的第一件事是您泄漏了内存(您在
(struct Atom *) malloc(sizeof(struct Atom) * numAtoms)
处分配了一些内存,然后用氨基结构);您可以使用(int *) malloc(sizeof(int) * numBonds);
执行相同的操作。其次,您没有对表达式 Bonds[i] - totRead 进行边界检查。
第三,我认为这就是你崩溃的地方,你在这里覆盖你的原子指针:atoms = (struct Atom *) malloc(sizeof(struct Atom)); free(atoms); 这使得原子指向无效内存。
There are a lot of things wrong here.
The first thing I notice is that you're leaking memory (you allocate some memory at
(struct Atom *) malloc(sizeof(struct Atom) * numAtoms)
, then overwrite the pointer with the pointer in the amino structure); you do the same thing with(int *) malloc(sizeof(int) * numBonds);
.Second, you're not bounds-checking the expression
bonds[i] - totRead
.Third, and I think this is where you're crashing, you overwrite your atoms pointer here:
atoms = (struct Atom *) malloc(sizeof(struct Atom)); free(atoms);
which leaves atoms pointing to invalid memory.下面是对部分代码的小重写,以演示内存泄漏:
语句
bonds[i] - totRead
也有可能超出atoms[]
范围,这可能是段错误。Here's a small rewrite of parts of your code to demonstrate the memory leaks:
There's also chance that the statement
bonds[i] - totRead
can be out of theatoms[]
bounds, which could be the segfault.听起来您正在使用 print 语句来调试分段错误:C 中的一大禁忌。
问题是 stdout 在大多数系统上都有缓冲,这意味着分段错误实际上发生的时间比您想象的要晚。使用 printf 无法可靠地确定程序何时出现段错误。
相反,您应该使用像 gdb 这样的调试器,它会告诉您导致分段错误的确切代码行。
如果您不知道如何使用 gdb,这里有一个我通过 Google 找到的快速教程:http://www.cs.cmu.edu/~gilpin/tutorial/
It sounds like you're using print statements to debug segmentation faults: a big no-no in C.
The problem is that stdout is buffered on most systems, which means that the segmentation fault is actually occurring later than you think. It is impossible to reliably determine out when your program is segfaulting using printf.
Instead, you should use a debugger like gdb, which will tell you the exact line of code that is causing the segmentation fault.
If you don't know how to use gdb, here's a quick tutorial I found by Google'ing: http://www.cs.cmu.edu/~gilpin/tutorial/
这很奇怪:
您分配内存,然后立即释放它,并使指针指向未分配的内存。
这行看起来也很危险:
确保你的索引留在数组中。
This is odd:
You allocate memory and then you free it right afterwards and leaving your pointers pointing to unallocated memory.
This line looks also dangerous:
Make sure you stay inside the array with your index.
编辑:去阅读这个 Accessing array value via指针算术与 C 中的下标 它应该帮助您理解什么是指针和数组
这些行实际上对代码的作用没有任何实际的净影响,因此您可以删除它们
这里的 malloc 行是无用的,并且会导致泄漏,因为您将氨基结构中的指针分配给完成后立即进行原子和键。
您应该暂时停止编码,并确保在执行其他操作之前了解指针,因为您显然不了解指针,并且在您了解之前这只会给您带来很多很多痛苦,但是这里是您的代码的一个版本,应该做一些更像你想要的事情:
EDIT: go read this Accessing array values via pointer arithmetic vs. subscripting in C it should help you understand what pointers and arrays are
These lines don't actually have any real net effect on what the code does so you can remove them
The malloc lines here are useless and result in a leak since you assign the pointer from the amino struct to atoms and bonds right after doing it.
You should stop coding for a bit and make sure you understand pointers before you do much else because you clearly don't and it's just going to cause you lots and lots of pain until you do, however here is a version of your code that should do something more like what you want:
文件中是否有
#include
?我想知道您是否收到使用printf()
隐式声明的printf()
调用,因此可能使用了错误的调用约定。您使用的编译器/平台是什么?您从构建中收到任何警告吗?
Do you have an
#include <stdio.h>
in the file? I wonder if you're getting a call toprintf()
that's using an implicit declaration ofprintf()
and therefore might be using the wrong calling convention.What's the compiler/platform you're using? Do you get any warnings from the build?
你写的地方:
我认为你的意图一定是这样的:
也可以写成:
在 C 中,没有内置的 equals (
=
) 运算符来复制数组,就像你想要的那样。相反,您所拥有的会丢失指向已分配内存的指针(以前存储在变量atoms中),然后继续开始循环的第一次迭代,其中atoms指向原子数组的“输入副本”。Part of the problem is that you are calling
free
on memory, but then subsequently you continue to access the pointer to this freed memory. You must not access pointers to freed memory. To avoid this, replace all of your calls to free with:现在,您可以简单地将上述代码剪切并粘贴到程序顶部的某个位置。一个好的位置是在最终的#include 指令之后,但它必须出现在文件级范围内并且在代码中首次使用
free()
之前。重新编译代码后,您会在
free(atom)
后立即发现总线错误和分段违规错误。这是正确的,freeptr()
的目的是导致您的代码立即崩溃,而不是导致您的代码滥用指针并导致难以调试的问题。要最终更正您的内存分配,请务必转置以下行:
其应为:
您使用参数
diff
就好像传入至少包含三 (3) 个元素的数组一样。您应该验证调用者是否传递了足够的内存。When allocating
bonds
, you must allocate memory for not one (1) integer, but as many integers asnumBonds
:或者,对于大多数 C 程序员来说更好:
您需要更正
原子
的分配以分配正确的数量元素。目前,您还只分配大小为sizeof(struct Atom)
的单个内存元素。此类元素的数组需要将一个元素的大小乘以元素的数量。calloc()
函数很好,因为它为您分配一个数组,并将所有元素的内容初始化为零。malloc()
不执行任何操作来初始化返回的内存,并且可能会导致程序中传播不可预测的值。如果您使用malloc()
而不是calloc()
,则必须小心初始化数组元素。即使使用calloc()
,您也必须初始化所有非零元素。请注意,我从
malloc
的返回值中删除了强制转换。如果您正在编写 C 代码,则应该将其编译为 C 代码。除非您在 C++ 模式下进行编译,否则编译器不会抱怨缺少void *
的强制转换。 C 源文件应以.c
文件扩展名结尾,而不是.cpp
。正如 Walter Mundt 指出的那样,您意外地对已分配给指针
atoms
的输入参数之一的成员调用了free()
。您必须自行纠正此问题;上面的freeptr()
不会为你突出显示这个错误。其他人写道,您无法使用 printf() 来可靠地检测程序崩溃的位置。
printf()
的输出被缓冲并且其出现被延迟。最好的选择是使用 gdb 来确定程序崩溃的确切行。如果您编译代码进行调试,则无需学习任何
gdb
命令即可执行此操作。缺少的话,将: 替换
为:
总的来说,我的建议是你暂时不要使用C 语言。如今计算机的速度如此之快,以至于我会质疑为什么您首先考虑使用 C。
别误会我的意思;我喜欢C语言。但 C 并不是万能的。 C 非常适合操作系统、嵌入式系统、高性能计算,以及其他成功的主要障碍是缺乏对计算机器的低级访问的情况。
就您而言,您似乎是一名科学家或工程师。我建议你学习并使用Python。 Python 可以提供易于阅读、易于验证的程序,您可以与其他化学家或工程师共享这些程序。 C 并不适合像 Python 那样快速编写健壮的代码。如果将来出现 Python 速度不够快无法满足您的目的的情况,您可以准备其他解决方案。
Where you have written:
I think your intention must be this:
which could also be written as:
In C there is no built-in equals (
=
) operator to copy arrays as you seem to have intended. What you have instead loses track of the pointer to allocated memory, formerly stored in the variableatoms
, and then proceeds to begin the first iteration of your loop withatoms
pointing into the "input copy" of the atoms array.Part of the problem is that you are calling
free
on memory, but then subsequently you continue to access the pointer to this freed memory. You must not access pointers to freed memory. To avoid this, replace all of your calls to free with:For now you can simply cut-and-paste the above code somewhere at the top of your program. A good place is after the ultimate
#include
directive, but it must occur at file-level scope and prior to your first use offree()
in the code.After recompiling your code, you will find Bus Errors and Segmentation Violation faults immediately after you
free(atom)
. This is correct and the purpose offreeptr()
is to lead your code to an immediate crash rather than the current situation where your code is misusing pointers and leading to problems which are very difficult for you to debug.To finally correct your memory allocations, definitely transpose the lines:
which should read:
You use the argument
diff
as though you are passing in an array of at least three (3) elements. You should verify that the caller is passing enough memory.When allocating
bonds
, you must allocate memory for not one (1) integer, but as many integers asnumBonds
:or, better for most C coders:
You will need to correct the allocation of
atoms
to allocate a correct number of elements. Currently, you also are allocating only a single memory element of sizesizeof(struct Atom)
. An array of such elements requires that you multiply the size of one element by the number of elements.The
calloc()
function is nice because it allocates an array for you, and initializes the content of all elements to zero.malloc()
does nothing to initialize the returned memory, and can result in unpredictable values propagating in your program. If you usemalloc()
rather thancalloc()
, you must take care to initialize the array elements. Even when usingcalloc()
, you must initialize any non-zero elements.Notice that I removed the cast from the return value of
malloc
. If you are writing C code, you should be compiling it as C code. The compiler will not complain about the lack of a cast fromvoid *
unless you are compiling in a C++ mode. C source files should end in.c
file extensions, not.cpp
.As Walter Mundt pointed out, you are accidentally calling
free()
on a member of one of your input parameters, which you have assigned to the pointeratoms
. You will have to correct this on your own; the abovefreeptr()
will not highlight this mistake for you.Others have written that you cannot use
printf()
to reliably detect where your program is crashing. The output fromprintf()
is buffered and its appearance is delayed.Your best bet is to use
gdb
to determine the exact line at which your program crashes. You won't have to learn anygdb
commands to do this if you compile your code for debugging.Lacking that, replace:
with:
Overall, my suggestion is that you not use the C language for the time being. Computers are so fast these days that I would question why you have considered C in the first place.
Don't get me wrong; I love the C language. But C is not for everything. C is great for operating systems, embedded systems, high-performance computing, and for other cases where the main obstacle to success is lack of low-level access to the computing machinery.
In your case, you seem to be a scientist or engineer. I recommend you learn and use Python. Python lends itself to easily read, easily verified programs which you can share with your fellow chemists or engineers. C does not lend itself to quickly writing robust code as Python does. In that unlikely future event that Python is not fast enough for your purposes, there are other solutions which you will then be ready for.