Where you have written:
/* Allocate new space for a copy of the input parameter "Atoms" */
atoms = (struct Atom *) malloc(sizeof(struct Atom) * numAtoms);
/* Immediately lose track of the pointer to that space, once was stored
in atoms, now being lost. */
atoms = (*amino).atoms;
I think your intention must be this:
/* Allocate new space for a copy of the input parameter "Atoms" */
atoms = (struct Atom *)malloc(sizeof(struct Atom) * numAtoms);
/* Copy the input parameter into the newly-allocated memory. */
for (i = 0; i < numAtoms; i++)
atoms[i] = (*amino).atoms[i];
which could also be written as:
/* Allocate new space for a copy of the input parameter "Atoms" */
atoms = (struct Atom *)malloc(sizeof(struct Atom) * numAtoms);
/* Copy the input parameter into the newly-allocated memory. */
memcpy(atoms, (*amino).atoms, sizeof(struct Atom) * numAtoms);
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 variable atoms
, and then proceeds to begin the first iteration of your loop with atoms
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:
#ifdef free
# undef free
#endif
#define free(f) freeptr(&f)
void freeptr(void **f)
{
/* This function intentionally segfaults if passed f==NULL, to alert
the programmer that an error has been made. Do not wrap this code
with a check "if (f==NULL)", fix the problem where it is called.
To pass (*f==NULL) is a harmless 'no-op' as per the C standard
free() function.
If you must access the original, built-in free(), use (free)() to
bypass the #define macro replacement of free().
*/
(free)(*f); /* free() must accept NULL happilly; this is safe. */
*f = NULL; /* Set the pointer to NULL, it cannot be used again. */
}
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 of free()
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 of freeptr()
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:
bonds = (int *) malloc(sizeof(int));
free(bonds);
which should read:
free(bonds);
bonds = (int *) malloc(sizeof(int));
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 as
numBonds
:
free(bonds);
bonds = (int *) malloc(sizeof(int) * numBonds);
or, better for most C coders:
free(bonds);
/* The calloc function performs the multiplication internally, and
nicely zero-fills the allocated memory. */
bonds = calloc(numBonds, sizeof(int));
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 size sizeof(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 use malloc()
rather than calloc()
, you must take care to initialize the array elements. Even when using calloc()
, 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 from void *
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 pointer atoms
. You will have to correct this on your own; the above freeptr()
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 from printf()
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 any gdb
commands to do this if you compile your code for debugging.
Lacking that, replace:
printf("Program ran to point A.\n");
with:
fprintf(stderr, "Program ran to point A.\nPress return.\n");
fflush(stderr); /* Force the output */
fflush(stdin); /* Discard previously-typed keyboard input */
fgetc(stdin); /* Await new input */
fflush(stdin); /* Discard unprocessed input */
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.