Thread: dynamic allocation from 1 instead of zero

  1. #1
    Registered User
    Join Date
    Mar 2009
    Posts
    114

    dynamic allocation from 1 instead of zero

    Hi there,

    I would like to allocate memory for 1d and 2d arrays in such a way that the starting index is not 0 but 1.
    NR has functions to do so, but I don't want to use them because I am writing a small code that may be put in the internet and NR is not open source.

    I do not necessarily need such allocation, and I could work fine with a 0-index standard C allocation, but given that I may need to couple my arrays with fortran, I'd rather work on allocation than on looping.

    The standard allocation 0-indexed is clearly the following:

    Code:
    void iarray2d(int **mat, long nrows, long ncols, int index)
    {
    	//nrows = number of rows
    	//ncols = ncolumns
    	//index = 1 if you want allocation in the fortran way starting from 1
    	//index = 0 if you want the standard C allocation way starting from 0
    	
    	long i;
    
    	//Malloc pointers to rows
    	mat=(int **) malloc((size_t)(nrows*sizeof(int*)));
    	if (!mat) printf("Matrix MAT could not be allocted");
    
    	for(i=0; i<=nrows; i++)
    		mat[i] = malloc((size_t)(ncols*sizeof(int*)));
    
    }
    I hope to find someone willing to help. I am not a C hardcore programmer, although I use C whenever I code something.

    I appreciate,
    Best,
    cfd

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The "easy" way is to just add index to nrows and n - that will waste sizeof(int *) + ncols * sizeof(int) bytes, but it makes it very easy to do. To save some memory (if ncols is large), add index to nrows in the first malloc, set mat[0] = NULL before the for-loop, then do the for loop from index to ncols+index. That means you are only wasting sizeof(int*), which is probably ok.

    Why not make ncols and nrows of the type size_t instead of long? That would remove the cast in malloc. And you shouldn't need a cast for the result of the first malloc either.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Mar 2009
    Posts
    114
    Quote Originally Posted by matsp View Post
    add index to nrows in the first malloc, set mat[0] = NULL before the for-loop, then do the for loop from index to ncols+index. That means you are only wasting sizeof(int*), which is probably ok.

    Mats
    Hi Mat, thanks for replying. When you say to add index to nrows, does it mean that the call to malloc as
    Code:
    mat=(double **) malloc((size_t)(nrows*sizeof(double*)));
    is allocating from 0 to nrows originally, and what I'd be doing by adding index is allocating one more (if index is 1) element? Then, by "NULLING" mat[0], I am free the memory of from the allocation of mat[0] ? Am I understanding it right?

    Then, to reply to

    Why not make ncols and nrows of the type size_t instead of long? That would remove the cast in malloc. And you shouldn't need a cast for the result of the first malloc either.
    Mats
    I do it because I was used to allocate arrays (dimensions in general) with size_t instead of a regular type; would you suggest to not use size_t? What would the difference be?

    thank you again
    cfd

  4. #4
    Registered User
    Join Date
    Mar 2009
    Posts
    114
    Quote Originally Posted by matsp View Post
    The "easy" way is to just add index to nrows and n - that will waste sizeof(int *) + ncols * sizeof(int) bytes, but it makes it very easy to do. To save some memory (if ncols is large), add index to nrows in the first malloc, set mat[0] = NULL before the for-loop, then do the for loop from index to ncols+index. That means you are only wasting sizeof(int*), which is probably ok.

    Why not make ncols and nrows of the type size_t instead of long? That would remove the cast in malloc. And you shouldn't need a cast for the result of the first malloc either.

    --
    Mats
    Me again Mat,

    this is what I came out following your suggestions:

    Code:
    void iarray2d(int **mat, long nrows, long ncols, int index)
    {
    	//nrows = number of rows
    	//ncols = ncolumns
    	//index = 1 if you want allocation in the fortran way starting from 1
    	//index = 0 if you want the standard C allocation way starting from 0
    	
    	long i;
    
    	//Malloc pointers to rows
    	mat=(int **) malloc((size_t)((nrows+index)*sizeof(int*)));
    	if (!mat) printf("Matrix MAT could not be allocted");
    	
    	for(i=0; i<index; i++)
    		mat[i] = NULL;
    
    	for(i=0+index; i<=nrows+index; i++)
    		mat[i] = malloc((size_t)(ncols*sizeof(int*)));
    
    return;
    }
    did I understand it right? What should I change to make it better in terms of efficiency and to trat also a very large number of elements?

    Thanks again

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    This is what I'm suggesting.
    Code:
    mat= malloc((nrows+index)*sizeof(double*));
    Setting mat[0] = NULL will simply meant that if, for some reason, the code tries to access mat[0][x] later on, it will fail, rather than do something random that may or may not crash (and may or may not launch nuclear missiles, make the aeroplane fall out of the sky, etc).
    Of course, if index is zero, then you will overwrite the mat[0] with a memory allocation. If it's 1, then you get no memory allocated for that bit, so it remains NULL and thus will be "obvious" if it's accidentally used.

    Re size_t
    Code:
    void iarray2d(int **mat, size_t nrows, size_t ncols, int index)
    There should be no reason to use "long" here - size_t is the same size as long (in Linux at least, if you are using Windows it isn't in 64-bit versions of Windows - but then you probably still want size_t rather than long in those cases, as it will allow you to allocate more than 4GB of memory).

    By the way, size_t _IS_ a regular type - it's just specifically defined to match the largest allocation you can possibly make.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Registered User
    Join Date
    Mar 2009
    Posts
    114
    Great, thank you very much Mat,

    In what do you work, if it's possible to know?

    I appreciate
    Best regards

    cfd

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    In mobile phone operating systems I do work, as Yoda say would. [Sorry for taking the mickey about your English grammar].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Registered User
    Join Date
    Mar 2009
    Posts
    114
    No prob!
    Best

    cfd

  9. #9
    Registered User
    Join Date
    Mar 2009
    Posts
    114
    Quote Originally Posted by matsp View Post
    This is what I'm suggesting.
    Code:
    mat= malloc((nrows+index)*sizeof(double*));
    Setting mat[0] = NULL will simply meant that if, for some reason, the code tries to access mat[0][x] later on, it will fail, rather than do something random that may or may not crash (and may or may not launch nuclear missiles, make the aeroplane fall out of the sky, etc).
    Of course, if index is zero, then you will overwrite the mat[0] with a memory allocation. If it's 1, then you get no memory allocated for that bit, so it remains NULL and thus will be "obvious" if it's accidentally used.

    Re size_t
    Code:
    void iarray2d(int **mat, size_t nrows, size_t ncols, int index)
    There should be no reason to use "long" here - size_t is the same size as long (in Linux at least, if you are using Windows it isn't in 64-bit versions of Windows - but then you probably still want size_t rather than long in those cases, as it will allow you to allocate more than 4GB of memory).

    By the way, size_t _IS_ a regular type - it's just specifically defined to match the largest allocation you can possibly make.

    --
    Mats
    To conclude, the following function should be the working solution, shouldn't it?

    Code:
    void darray2d(double **mat, size_t nrows, size_t ncols, int index)
    {
    	//nrows = number of rows
    	//ncols = ncolumns
    	//index = 1 if you want allocation in the fortran way starting from 1
    	//index = 0 if you want the standard C allocation way starting from 0
    	
    	long i;
    
    	//Malloc pointers to rows
    	mat= malloc((nrows+index)*sizeof(double*));
    	if (!mat) printf("Matrix MAT could not be allocted");
    	
    	for(i=0; i<index; i++)
    		mat[i] = NULL;
    
    	for(i=0; i<=nrows; i++)
    		mat[i] = malloc((ncols+index)*sizeof(double*));
    
    return;
    }
    and freed like this:
    Code:
    void free_iarray2d(int **mat, size_t nrows, size_t ncols, int index)
    {
    	long i;
    	
    	for(i=index; i<=nrows+index-1; i++)
    		free(mat[i]);
    		
    	free(mat);
    
    return;
    }
    Now though, if the arguments are of type size_t, can I pass nrows and ncols of type INT without getting unwanted warnings?


    thank you for helping
    Last edited by cfdprogrammer; 04-28-2009 at 03:25 AM.

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    To start from the back:
    Not sure what your compiler will do if you pass an int to size_t - some do OK, others whine and moan like crazy. But why would it be a (signed) int? Will you EVER need to have negative values as index? If so, it's a problem for your current code anyways. So, I'd say the code is wrong if it's using a signed integer as the number of rows/columns.

    Now for the actual code...
    Code:
    	for(i=0; i<index; i++)
    		mat[i] = NULL;
    Is index EVER going to be something other than 0 or 1? If so, you need this loop. Otherwise, you could simply do:
    Code:
    	mat[0] = NULL;
    without any for/if/while etc - it's faster to just set that value than to validate if you need to set it or not by checking index.


    Code:
    	for(i=index; i<=nrows+index; i++)
    		mat[i] = malloc((ncols+index)*sizeof(double*));
    You should also check that mat[i] is not NULL - you could run out of memory at ANY time.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User
    Join Date
    Mar 2009
    Posts
    114
    Quote Originally Posted by matsp View Post
    To start from the back:
    Not sure what your compiler will do if you pass an int to size_t - some do OK, others whine and moan like crazy. But why would it be a (signed) int? Will you EVER need to have negative values as index? If so, it's a problem for your current code anyways. So, I'd say the code is wrong if it's using a signed integer as the number of rows/columns.
    Great, this hint will improve my programming skills. Never though of this in this way.

    Now for the actual code...

    Code:
    	for(i=index; i<=nrows+index; i++)
    		mat[i] = malloc((ncols+index)*sizeof(double*));
    You should also check that mat[i] is not NULL - you could run out of memory at ANY time.
    How should do this check? Isn't the check being done by allocating inside the loop?

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    No, if you fail to allocate inside the loop, you need an additional statement of
    Code:
    if (!mat[i]) ...
    .
    Note that you would also have to deal with the fact that you would then leak memory, unless you immediately exit under those circumstances. Also, you would probably best leave the function if the malloc fails, both at the first and the second stage.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Mar 2009
    Posts
    114
    Quote Originally Posted by matsp View Post
    No, if you fail to allocate inside the loop, you need an additional statement of
    Code:
    if (!mat[i]) ...
    .
    Note that you would also have to deal with the fact that you would then leak memory, unless you immediately exit under those circumstances. Also, you would probably best leave the function if the malloc fails, both at the first and the second stage.

    --
    Mats
    This would be my correction then; what do you think?

    Code:
    mat= malloc((nrows+index)*sizeof(double*));
    	if (!mat){
    		printf("Matrix MAT could not be allocted");
    		exit(1);
    	}
    	
    	mat[0] = NULL;
    
    	for(i=index; i<nrows+index; i++){
    		mat[i] = malloc((ncols+index)*sizeof(double*));
    		if (!mat[i]){
                        printf("Matrix MAT could not be allocted\ The exec. will Exit now\n");
    		    exit(1);
                    }
    	}
    thanks for the patience!
    Last edited by cfdprogrammer; 04-28-2009 at 04:25 AM.

  14. #14
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    still don't see the point of the first for-loop - are you really saying that index can be 2, 3, 14 or 4186, rather than what your comment says: 0 for C style, 1 for Fortran style arrays.

    You are missing the braces around your if inside the loop.

    EXIT() is not a standard function. exit() is.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #15
    Registered User
    Join Date
    Mar 2009
    Posts
    114
    Yes, sorry, I got rid of the first loop but after I had posted the reply; index won't be anything different from 0 or 1.

    Yes, thanks about the brackets; wrote it in a hurry to have a check with you.

    I imagine there should be no check (!mat) in freeing the memory, correct?

    This helped me a lot!

    Best
    cfd

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pointer to array with dynamic allocation
    By cfdprogrammer in forum C Programming
    Replies: 22
    Last Post: 04-07-2009, 09:56 AM
  2. Difference between straight and dynamic allocation?
    By darsunt in forum C++ Programming
    Replies: 10
    Last Post: 06-04-2008, 05:47 PM
  3. Dynamic memory allocation.
    By HAssan in forum C Programming
    Replies: 3
    Last Post: 09-07-2006, 05:04 PM
  4. Dynamic allocation (I thought it would crash)
    By Baaaah! in forum C Programming
    Replies: 16
    Last Post: 11-30-2005, 05:10 PM
  5. Dynamic memory allocation
    By amdeffen in forum C++ Programming
    Replies: 21
    Last Post: 04-29-2004, 08:09 PM