Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
I get a segmentation error when I try to free memory. Any ideas. thanks
Code:
char **** allocate_memory (char ****array)

{
	
int i,j,k;
	
	
if( (array = (char ****) calloc(2500,sizeof(char***))) == NULL)
{	
	printf("no memory");
	return(0);
}	
for( i = 0; i <2000; i++)
{
	if ((array[i] = (char ***) calloc(5, sizeof(char**))) == NULL)
	{
		printf("no memory");
		return(0);
	}
	
	for( j = 0; j < 5; j++)
	{
		if ((array[i][j] = (char **) calloc(45, sizeof(char*))) == NULL)
		{
			printf("no memory");
			return(0);
		}
		
		for( k = 0; k < 45; k++)
		{
			if ((array[i][j][k] = (char *) calloc(8, sizeof(char))) == NULL)
			{
				printf("no memory");
				return(0);
			}
		}
	}
}
	return ((char ****) array);
}




void freearrays( char ****array)
{
	int i, j,k;
	
	for (i = 0; i < 2500;i ++)
	{
		for(j = 0; j < 5; j ++)
		{	
			for (k = 0; k < 45; k++);
				free(array[i][j][k]);
			free(array[i][j]);
		
		}
		free(array[i]);
	}
	
	free(array);
	
}int main (int argc, const char * argv[]) {
    // insert code here...
	
//	char  line[1000], listname[50], tmp[1024];
	
	int i4, i5, m;
	int i,j,k;
	char filename[50];
	FILE *fp; //, *action;
	
	
/*	if (atoi (argv[0]) == 0)
	{
		printf("you forgot the date\n");
		return(0);
	}
 */	
	Caverages = allocate_memory((char****)Caverages);
	Paverages = allocate_memory((char****)Paverages);
		freearrays((char ****)Paverages);
	freearrays((char ****)Caverages);
 
In your allocation you make enough room for 2500 char***s, but then only allocate and assign 2000. Then when you free, you try to access elements past 2000, free uninitialized pointers, etc. Also, you don't show where your arrays are declared, so you may or may not need to free array itself.

-Lee
 
freeing memory

Thanks. I defined pages (#define pages 2000) so that I don't have to worry about all keeping everything the same. It seems to work.
 
Where, and how, are 'Caverages' and 'Paverages' declared?

What are their intended internal structure?

Assuming your 'allocate_memory' function is correct your 'freearrays' functions has an semi-colon misplaced. Here it is reformatted - see if you can spot it?

Code:
void freearrays( char ****array)
{
    int i, j, k;

    for (i = 0; i < 2500; i++)
    {
        for (j = 0; j < 5; j++)
        {
            for (k = 0; k < 45; k++)
                ;

            free(array[i][j][k]);
            free(array[i][j]);

        }

        free(array[i]);
    }

    free(array);
}
 
This is a memory allocation nightmare.

It looks like you're trying to create a 2500-by-5-by-45 array of 8-character strings. Why allocate all the columns, rows, etc. individually when you can just allocate it in one block?

Code:
array = calloc(2500*5*45*8, sizeof(char));

If you just want to be able to access each string like array[j][k], this should be fine.

And for God's sake, make a typedef. Quadruple pointers are almost always a sign that things are very wrong. The better solution is to declare your multi-dimensional array as a one-dimensional array and use a macro to compute an (x,y,z) triple into a linear index.
 
freeing memory

If I do that can I still address an element in the array as array[j][k] or do I have to use array[2000*i + 5*j + 45*k]?
 
Doug,

Please answer the question that keeps getting asked and we can give you a useful answer.

What is the format of the data that is being stored/accessed. We need to know your "intent".
 
You'd have to use array[2000*i + 5*j + 45*k]. C doesn't allow you to allocate multidimensional arrays with malloc(), since the size of an array must be constant at runtime in order for the x[j][k] notation to work.

Since you know the array's size, you could just create a macro to compute the index for you, like this:

Code:
#define INDEX(i,j,k) ((2000*i)+(5*j)+(45*k))

Then you'd use it like so:
Code:
array[INDEX(1,2,3)] = something;

What you did in your previous example was allocate an array of pointers, with each pointer pointing to other arrays of pointers, etc. While this method would allow you to access elements via x[j][k] notation, the overhead of accessing an element this way is huge because the computer has to follow a chain of 3 pointers to get to the contents.

Somewhat related: 99% of the time, you'll never need anything more than a double pointer. (e.g. for an array of strings). Triple pointers are usually only used to pass or refer to arrays of strings (double pointers) by reference. Anything more than that usually means there's a better way to solve your problem. :p
 
What you did in your previous example was allocate an array of pointers, with each pointer pointing to other arrays of pointers, etc. While this method would allow you to access elements via x[j][k] notation, the overhead of accessing an element this way is huge because the computer has to follow a chain of 3 pointers to get to the contents.


the computation involved is pretty negligible. The compromises should be understood, but I think the simplicity of accessing the elements is worth it. In some cases it is not.

-Lee

edit: back when farmerdoug started asking about this some of the compromises were discussed:
https://forums.macrumors.com/threads/844474/

edit 2: I just checked out the x86 ASM. Each dimension costs about 4 instructions. Two moves, a bit shift, and a load from memory. The memory cost is also worth considering, but overall if the app is not memory or CPU starved, I value programmer time over execution time as long as optimal runtime is not a requirement.
 
freeing memory

The requirements on my programming skills have never pushed me to consider many or all of the issues being raised here. In addition, memory and speed seem to be increasing at a far greater rate than I can use. The speed of C with Snow Leopard is just so incredible. I am constantly amazed.

I have some third party libraries that require the array[i*dim1 + j*dim2 ...]
but I prefer array[j][k] - habit and its visually easier to read.

lloyddean: as far as the type of data, I'm not sure why it would matter but in this case, I am reading csv files from which I am storing reduced and calculated data in 3d arrays of strings. The arrays have to be searched to find certain equal elements for further calculations.
 
Each dimension costs about 4 instructions. Two moves, a bit shift, and a load from memory.

That's pretty much the same thing as "each dimension costs a load from memory". Unless it's in the L2 cache and the load is hoisted, that load will be the majority of the execution time for those 4 instructions.

I suspect a decent optimizing compiler will transform array[j][k] accesses in a loop into something else anyway if it's worthwhile.
 
All this talk of optimization and instruction counts strikes me as premature.

The OP hasn't said anything about a speed problem. In fact, the only comment about speed is that "memory and speed seem to be increasing at a far greater rate than I can use."

The problems the OP is having are all related to C's manual memory management (calloc/free), its primitive representation for strings, and one additional problem of evaluating strings as expressions at runtime (if I understand that problem correctly). All of those suggest using a higher-level language than plain ordinary C, IMNSHO.
 
lloyddean: as far as the type of data, I'm not sure why it would matter but in this case, I am reading csv files from which I am storing reduced and calculated data in 3d arrays of strings. The arrays have to be searched to find certain equal elements for further calculations.

Doug,

You're still not stating the full nature of the data structures you're trying to work with. I believe you're confused and thus not able to state your problems sufficiently that we can understand it, leaving us confused as to how to assist you.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.