473,387 Members | 1,483 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

User Defined 2d Arrays

6
I want to know how to malloc for a 2d array. I have the code for a single dimension array.

int size;
int* array;

array = (int*)malloc(size*sizeof(int));

the user will input a number for 2 variables so size1 and size2. One amount for the columns and one for the rows. With the code above its only for one of these.
Feb 15 '07 #1
14 5740
Follow the link http://www-ee.eng.hawaii.edu/~tep/EE...on2.1.2.2.html



I want to know how to malloc for a 2d array. I have the code for a single dimension array.

int size;
int* array;

array = (int*)malloc(size*sizeof(int));

the user will input a number for 2 variables so size1 and size2. One amount for the columns and one for the rows. With the code above its only for one of these.
Feb 15 '07 #2
Ganon11
3,652 Expert 2GB
I want to know how to malloc for a 2d array. I have the code for a single dimension array.

int size;
int* array;

array = (int*)malloc(size*sizeof(int));

the user will input a number for 2 variables so size1 and size2. One amount for the columns and one for the rows. With the code above its only for one of these.
You can use a double pointer. The code will be, I think (I haven't used malloc):

Expand|Select|Wrap|Line Numbers
  1. int size1;
  2. int size2;
  3. int** array;
  4.  
  5. // Get sizes from user
  6.  
  7. array = (int**)malloc(size1 * sizeof(int*)); // Creates an array of int pointers
  8. for (int i = 0; i < size1; i++)
  9.    array[i] = (int*)malloc(size2 * sizeof(int)); // Each int* is an array of pointers
Feb 15 '07 #3
AdrianH
1,251 Expert 1GB
You can use a double pointer. The code will be, I think (I haven't used malloc):

Expand|Select|Wrap|Line Numbers
  1. int size1;
  2. int size2;
  3. int** array;
  4.  
  5. // Get sizes from user
  6.  
  7. array = (int**)malloc(size1 * sizeof(int*)); // Creates an array of int pointers
  8. for (int i = 0; i < size1; i++)
  9.    array[i] = (int*)malloc(size2 * sizeof(int)); // Each int* is an array of pointers
Yes this will work, and referencing is done like this:
Expand|Select|Wrap|Line Numbers
  1. array[i][j]
Where i is between 0 and size1-1 and j is between 0 and size2-1.

However, I think what kvbreddy was trying to get at is that you could use instead of a 2D array is a 1D array with a struct containing 2 elements. Depending on what your goal is, each has its uses.

The struct has no chance of overrunning the end of the array on the 2nd dimension, because there is no numerical index required, only members. If this is a concern, then a 1D array of a struct may be the answer.

2D arrays are only necessary if you are going to require indexing a cell in it given 2D coordinates.

Hope this helps.


Adrian
Feb 15 '07 #4
willakawill
1,646 1GB
I want to know how to malloc for a 2d array. I have the code for a single dimension array.

int size;
int* array;

array = (int*)malloc(size*sizeof(int));

the user will input a number for 2 variables so size1 and size2. One amount for the columns and one for the rows. With the code above its only for one of these.
Hi. You don't need to use 2d arrays. You can do the same thing with 1d arrays using the following:

Expand|Select|Wrap|Line Numbers
  1. int cols = 10;
  2. int rows = 20;
  3. int i, j;
  4. int answ;
  5. int *ar = 0;
  6.  
  7. ar = (int*)malloc(cols*rows*sizeof(int));
  8. for (i = 0; i<10; i++)
  9.    for (j = 0; j<20; j++)
  10.       answ = ar[i + (cols * j)];
Feb 15 '07 #5
Ganon11
3,652 Expert 2GB
You can use a 1d array, but that makes accessing elements very tedious - using array[i] from 0 to 254 instead of array[i][j] from 0 to 24, for example.
Feb 15 '07 #6
AdrianH
1,251 Expert 1GB
You can use a 1d array, but that makes accessing elements very tedious - using array[i] from 0 to 254 instead of array[i][j] from 0 to 24, for example.
I agree with Gannon11, if using a 1D array to house 2 elements per index, I'd recommend a struct unless your application requires a 2D array, in which case, don't do the job of the compiler. Its purpose is to try and make you life easier, not harder. :) Unless you are going to start casting to a 2D array type, then you are getting really advanced, and probably beyond what this person wants.


Adrian
Feb 15 '07 #7
willakawill
1,646 1GB
I agree with Gannon11, if using a 1D array to house 2 elements per index, I'd recommend a struct unless your application requires a 2D array, in which case, don't do the job of the compiler. Its purpose is to try and make you life easier, not harder. :) Unless you are going to start casting to a 2D array type, then you are getting really advanced, and probably beyond what this person wants.


Adrian
I can understand that the use of
Expand|Select|Wrap|Line Numbers
  1. ar[i + (cols * j)];
Seems so much more cumbersome than
Expand|Select|Wrap|Line Numbers
  1. ar[i][j];
when there does not appear to be any good reason for it.
In fact there is a big difference in how a single dimension and a 2d array are written to a binary file in a single pass as in ostream::write
Only single dimension binary files are compatible with vb binary input output for example
It is also much simpler to allocate memory for a single dimension as demonstrated and much more efficient particularly working with the array sizes I have in my current project.
Anyway, horses for courses. Whatever works :)
Feb 15 '07 #8
nmadct
83 Expert
It's true that a 1D array is more efficient than a 2D array, and the inefficiency of the 2D array increases with the size of the first index. For small arrays this probably isn't a big deal but it's good to know when you're making the decision. Here's a program that illustrates how you can build a 2D array from a 1D array, it will show how to do it and hopefully also help illustrate how 2D arrays work in C.

The program allocates a block of memory with one call to malloc, then constructs a 2D array in that space, with the cells containing numbers counting from 1 to 128. Then, it copies that array onto another block of memory that has already been initialized with all of its bits set. Finally, the results are printed from the second block of memory, and it then doubles back and prints the last integer in the allocated block.

The copying is done just to demonstrate that the numbers we've written exactly fill the space that was allocated. If we'd allocated too much memory then you'd see that when we print the last integer in the block, it's not the right value. If we'd allocated too little, then the end of the block wouldn't get copied at all. (If writing off the end of the allocated block didn't happen to crash your program already, that is.)

Expand|Select|Wrap|Line Numbers
  1. #include <stdio.h>
  2. #include <memory.h>
  3. #include <malloc.h>
  4.  
  5. int main()
  6. {
  7.         int i, j;
  8.         int size = 16*sizeof(int*) + 8*16*sizeof(int);
  9.  
  10.         /* Allocate 2 blocks of memory. Give the
  11.           second one some extra space. */
  12.         int **original = (int**) malloc(size + 256);
  13.         int **fresh = (int**) malloc(size + 256);
  14.  
  15.         if (original==NULL || fresh==NULL)
  16.                 return 1;
  17.  
  18.         int count = 1;
  19.         for (i=0; i < 16; i++)
  20.         {
  21.                 /* Make the first index values point to blocks
  22.                   of the appropriate size */
  23.                 original[i] = (int*)(original + 16) + i*8;
  24.  
  25.                 /* now fill in the numbers,
  26.                   counting up 1 each time */
  27.                 for (j=0; j < 8; j++)
  28.                 {
  29.                         original[i][j] = count;
  30.                         count++;
  31.                 }
  32.         }
  33.  
  34.         /* initialize the memory that fresh points to, then copy
  35.            the contents of original into fresh */
  36.         memset(fresh, 0xFF, size+256);
  37.         memcpy(fresh, original, size);
  38.  
  39.         for (i=0; i < 16; i++)
  40.         {
  41.                 /* have to set this pointers to point into THIS
  42.                  block now */
  43.                 fresh[i] = (int*)(fresh + 16) + i*8;
  44.                 for (j=0; j < 8; j++)
  45.                 {
  46.                         printf("%02d ", fresh[i][j]);
  47.                 }
  48.                 putchar('\n');
  49.         }
  50.         printf("Last number: %d\n",
  51.           *((int*)((char*)original + size) - 1));
  52.         return 0;
  53. }
  54.  
I'm pretty sure this program is correct for any platform and any version of C, but I'm not 100% sure. That's the other reason I did the copying part: to prove correctness. Once you start making assumptions about the way that a compiler handles pointers, you're usually heading into dangerous waters, although I think in this case you're safe because standard C requires this implementation of 2D arrays. If you do this kind of thing, at least make sure your comments explain what you were thinking!
Feb 15 '07 #9
AdrianH
1,251 Expert 1GB
I'm pretty sure this program is correct for any platform and any version of C, but I'm not 100% sure. That's the other reason I did the copying part: to prove correctness. Once you start making assumptions about the way that a compiler handles pointers, you're usually heading into dangerous waters, although I think in this case you're safe because standard C requires this implementation of 2D arrays. If you do this kind of thing, at least make sure your comments explain what you were thinking!
I've looked briefly at this and it is definitely interesting. You are using double pointers to simulate a 2D array (this is how C first did this) that is 16x8. There is defiantly nothing wrong with this, but you can see how much code you need to write and the potential for error in writing it. Because of the general pattern you are showing however, you are on your way to writing a general library for 2D arrays, so if you really want to do this right, you may want to setup an interface to create, access, copy and delete the array.

A few things I saw, that caught my eye that I found confusing were:
Expand|Select|Wrap|Line Numbers
  1.         int size = 16*sizeof(int*) + 8*16*sizeof(int);
  2.  
I see where 16*sizeof(int*) came from, but where did 16 in 8*16*sizeof(int) come from? The first 8 represents the number of elements in that dimention, the sizeof(int) represents the size of the int, but the 16?

Expand|Select|Wrap|Line Numbers
  1.         /* Allocate 2 blocks of memory. Give the
  2.           second one some extra space. */
  3.         int **original = (int**) malloc(size + 256);
  4.         int **fresh = (int**) malloc(size + 256);
  5.  
What are the additional 256 bytes for?

Also, if you wanted to, instead of using the older style of C arrays, you can use the newer ones that allow you to generate them on the stack. These are passed by reference and are more memory and possibly more processing efficient as they are allocated in one block with no intermediate pointers. Indexing to an element will cause a calculation to be made to determine the offset to the element in question.

But care must be taken when passing these arrays in C, since you may pass one with a different 2nd or higher dimension which would then make the compiler calculate the offset to the element that you are trying to indexing to incorrectly. This problem doesn't exist in C++ due to the strong type system it employs.

Here is an example of its usage:
Expand|Select|Wrap|Line Numbers
  1. #define SIZE_X1 10
  2. #define SIZE_X2 20
  3. #define SIZE_Y1  5
  4. #define SIZE_Y2  6
  5.  
  6. /* NOTE: The first dimension can be variable as it doesn't change the offset       */
  7. /*       calculation. However, you may run off the end of the 1st dimension without*/
  8. /*       knowing the upper array bound.                                            */
  9. void set(int array[][SIZE_Y1], int x, int y, int value)
  10. {
  11.   /* use array just like a regular array */
  12.   array[x][y]=value;
  13. }
  14.  
  15. int main()
  16. {
  17.   int array1[SIZE_X1][SIZE_Y1] = {}; /* The = {} means to have it initialise the */
  18.   int array2[SIZE_X2][SIZE_Y1] = {}; /* array's elements to the default value.   */
  19.   int array3[SIZE_X2][SIZE_Y2] = {}; /* For int's, that value is 0.              */
  20.   set(array1, 1, 0, 9); /* Valid */
  21.   set(array2, 1, 0, 9); /* Valid */
  22.   set(array3, 1, 0, 9); /* Invalid, but would compile under C with wrong results */
  23.                         /* Will not compile under C++ due to strong typing. */
  24.   return 0;
  25. }
  26.  
One could pass the dimension of the array to get the compiler to calculate the correct offset, but this notation is valid only in C, not C++, and allows you to pass the wrong dimensional size.

Expand|Select|Wrap|Line Numbers
  1. #define SIZE_X1 10
  2. #define SIZE_X2 20
  3. #define SIZE_Y1  5
  4. #define SIZE_Y2  6
  5.  
  6. /* NOTE: The first dimension can be variable as it doesn't change the offset       */
  7. /*       calculation. However, you may run off the end of the 1st dimension without*/
  8. /*       knowing the upper array bound.                                            */
  9. /* NOTE: This notation (specifying size of array by preceding variable dimension)  */
  10. /*       is valid only in C.                                                       */
  11. void set(int sizeY, int array[][sizeY], int x, int y, int value)
  12. {
  13.   /* use array just like a regular array */
  14.   array[x][y]=value;
  15. }
  16.  
  17. int main()
  18. {
  19.   int array1[SIZE_X1][SIZE_Y1] = {}; /* The = {} means to have it initialise the */
  20.   int array2[SIZE_X2][SIZE_Y1] = {}; /* array's elements to the default value.  */
  21.   int array3[SIZE_X2][SIZE_Y2] = {}; /* For int's, that value is 0 */
  22.   set(SIZE_Y1, array1, 1, 0, 9);   /* Valid */
  23.   set(SIZE_Y1, array2, 1, 0, 9);   /* Valid */
  24.   set(SIZE_Y2, array3, 1, 0, 9);   /* Valid */
  25.   set(SIZE_Y2+1, array3, 1, 0, 9); /* invalid but will compile with wrong results */
  26.   return 0;
  27. }
  28.  
To make this work under C++, use a template which is far safer than the C version:

Expand|Select|Wrap|Line Numbers
  1. #define SIZE_X1 10
  2. #define SIZE_X2 20
  3. #define SIZE_Y1  5
  4. #define SIZE_Y2  6
  5.  
  6. /* NOTE: The first dimension can be variable as it doesn't change the offset       */
  7. /*       calculation. However, you may run off the end of the 1st dimension without*/
  8. /*       knowing the upper array bound.                                            */
  9. /* NOTE: Templates are valid only in C++.                                          */
  10. template<int sizeY>
  11. void set(int array[][sizeY], int x, int y, int value)
  12. {
  13.   /* use array just like a regular array */
  14.   array[x][y]=value;
  15. }
  16.  
  17. int main()
  18. {
  19.   int array1[SIZE_X1][SIZE_Y1] = {}; /* The = {} means to have it initialise the */
  20.   int array2[SIZE_X2][SIZE_Y1] = {}; /* array's elements to the default value.  */
  21.   int array3[SIZE_X2][SIZE_Y2] = {}; /* For int's, that value is 0 */
  22.   set(array1, 1, 0, 9);   /* Valid */
  23.   set(array2, 1, 0, 9);   /* Valid */
  24.   set(array3, 1, 0, 9);   /* Valid */
  25.   return 0;
  26. }
  27.  
One thing I have not figured out yet with these types of multi-dimensional arrays is if you can pass it back from a function, if you can create on of these on the heap and point at it, or if you can cast to one. If anyone has any answers to these questions, please post.

Oh and under C99 standard, you can also declare the array without the dimensions being a constant (i.e. make a dynamic array). However, the easy initialisation doesn’t work. This is probably because if you specified the actual contents of the array how is the compiled programme to respond if the dynamic array size is smaller than the initialisers specified? So you have to initialise the array yourself. g++ allows for dynamic arrays as well, but it is a gnu extension and not part of the current C++ spec.

Expand|Select|Wrap|Line Numbers
  1.  
  2. /* NOTE: The first dimension can be variable as it doesn't change the offset       */
  3. /*       calculation. However, you may run off the end of the 1st dimension without*/
  4. /*       knowing the upper array bound.                                            */
  5. void set(int array[][SIZE_Y1], int x, int y, int value)
  6. {
  7.   /* use array just like a regular array */
  8.   array[x][y]=value;
  9. }
  10.  
  11. int main()
  12. {
  13.   int sizeX1 = 10;
  14.   int sizeX2 = 20;
  15.   int sizeY1 = 5;
  16.   int array1[sizeX1][sizeY1]; /* The = {} doesn’t work for dynamically    */
  17.   int array2[sizeX2][sizeY1]; /* allocated arrays.                        */
  18.   set(array1, 1, 0, 9); /* Valid */
  19.   set(array2, 1, 0, 9); /* Valid */
  20.   return 0;
  21. }
  22.  
Boy, I certainly learned a lot from what I just said. :) Some of that I had to test and research as I didn’t actually know all of that when I started.


Adrian
Feb 16 '07 #10
nmadct
83 Expert
A few things I saw, that caught my eye that I found confusing were:
Expand|Select|Wrap|Line Numbers
  1.         int size = 16*sizeof(int*) + 8*16*sizeof(int);
  2.  
I see where 16*sizeof(int*) came from, but where did 16 in 8*16*sizeof(int) come from? The first 8 represents the number of elements in that dimention, the sizeof(int) represents the size of the int, but the 16?
The first part is a list of 16 pointers.
The second part is a 16x8 matrix containing the actual integer values. That's where this comes from: 8*16*sizeof(int)

Expand|Select|Wrap|Line Numbers
  1.         /* Allocate 2 blocks of memory. Give the
  2.           second one some extra space. */
  3.         int **original = (int**) malloc(size + 256);
  4.         int **fresh = (int**) malloc(size + 256);
  5.  
What are the additional 256 bytes for?
The additional 256 isn't necessary. It's just there because I was hypothesizing that my method might not be correct, and if that's the case then my array might take up more space than the memory I allocated. I didn't actually expect that to happen, though. The testing mechanism allows the correctness to be demonstrated with a few small tweaks to the code, however.

Also, if you wanted to, instead of using the older style of C arrays, you can use the newer ones that allow you to generate them on the stack. These are passed by reference and are more memory and possibly more processing efficient as they are allocated in one block with no intermediate pointers. Indexing to an element will cause a calculation to be made to determine the offset to the element in question.
That's very convenient, didn't know that.

Thanks, I learned some stuff from your post also.
Feb 17 '07 #11
AdrianH
1,251 Expert 1GB
The first part is a list of 16 pointers.
The second part is a 16x8 matrix containing the actual integer values. That's where this comes from: 8*16*sizeof(int)


The additional 256 isn't necessary. It's just there because I was hypothesizing that my method might not be correct, and if that's the case then my array might take up more space than the memory I allocated. I didn't actually expect that to happen, though. The testing mechanism allows the correctness to be demonstrated with a few small tweaks to the code, however.
Ahh, I definatly see what you did. Definatly better to put into a set of functions. Too easy to screw it up. I wrote one library set, but I just realised that I probably shouldn't post it. I don't think I we are allowed post the code to answer the question. What Ganon11 did in post 3 was to clear up the syntax, not show a general library. We are not here to do other people's (possibly students) work.

So to get back to the original question:
I want to know how to malloc for a 2d array. I have the code for a single dimension array.

int size;
int* array;

array = (int*)malloc(size*sizeof(int));

the user will input a number for 2 variables so size1 and size2. One amount for the columns and one for the rows. With the code above its only for one of these.
Ganon11 post 3 in this thread was correct, sweet and simple.


Adrian
Feb 17 '07 #12
jmw080
6
Thank all of you for your help. Now that i have a better understanding of this i know what to do : ) The reason i was using a 2d array was because i did have to use a coordinate system for plotting data. I was just trying to save memory by allowing the user to define the space needed rather than making a very large element so that i would never have an overflow.
Feb 18 '07 #13
Ganon11
3,652 Expert 2GB
Glad to see you got it!
Feb 18 '07 #14
AdrianH
1,251 Expert 1GB
Great. Glad to be of service.


Adrian
Feb 19 '07 #15

Sign in to post your reply or Sign up for a free account.

Similar topics

0
by: Shailesh | last post by:
Hello, I want to set up some USER DEFINED METRICS in 10g. The restriction with USER DEFINED METRICS, is the query (or function ) monitoring that metrics should return only 1 value. I want to...
13
by: dawatson833 | last post by:
I have several stored procedures with parameters that are defined with user defined data types. The time it takes to run the procedures can take 10 - 50 seconds depending on the procedure. If I...
2
by: David Emme | last post by:
Access 97 I have a number of SELECT statements which contain references to user-defined VBA functions. These typically work as expected, but occasionally, on one user's machine or another,...
4
by: Angel | last post by:
I'm trying to call a DLL function that receives as parameter a user-defined structure created by the company that made the dll. When I call the function from my main form, I call...
3
by: chreo | last post by:
I have user-defined function in MSSQL which returns Table (with 10 columns) (sorry for Polish names) CREATE FUNCTION PACZKI_Z_AKCJI (@AKCJA_ID int) RETURNS TABLE RETURN SELECT TOP 100...
1
by: abcabcabc | last post by:
I write an application which can let user define own date format to input, How to convert the date string to date value with end-user defined date format? Example, User Defined Date Format as...
17
by: Steve R. Hastings | last post by:
I have been studying Python recently, and I read a comment on one web page that said something like "the people using Python for heavy math really wish they could define their own operators". The...
2
by: Jonathan Daugherty | last post by:
Hello, I'm trying to write a PL/PgSQL function whose sole parameter is an array whose element type is a type that I've created. For example: CREATE TYPE test_type AS (x bigint, y bigint); ...
3
by: Hallvard B Furuseth | last post by:
I'm wondering how to design this: An API to let a request/response LDAP server be configured so a user-defined Python module can handle and/or modify some or all incoming operations, and later...
6
by: p4willi | last post by:
I've defined two arrays in a Module called PubVars Public Type LinesRec CORRECT As Integer QUESTION As String PROC As Integer PAY As Integer End Type Public Lines_Array() As...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.