How I can implement a 2-dimensional array with different column sizes dynamically in C?
I tried many ways to implement a 2-dimensional array dynamically with different column sizes in c but I can't get it.
Please tell me one suggestion...
CodePudding user response:
first of all read the row size(here row size is r) then declare the two dimensional array & one dimensional array as like:int a[r][100],n[r]; and then,read one dimensional array elements(these are nothing but a different column sizes),finally read the two dimensional array elements.
CodePudding user response:
//Hemanth you can find the below code,
#include <stdio.h>
#include <stdlib.h>
int main() {
int row = 2, col = 3; //number of rows=2 and number of columns=3
int *arr = (int *)malloc(row * col * sizeof(int));
int i, j;
for (i = 0; i < row; i )
for (j = 0; j < col; j )
*(arr i*col j) = i j;
printf("The matrix elements are:\n");
for (i = 0; i < row; i ) {
for (j = 0; j < col; j ) {
printf("%d ", *(arr i*col j));
}
printf("\n");
}
free(arr);
return 0;
}
//let me know if you are still finding any problems with it.
CodePudding user response:
Here is a solution that creates a struct representing such an array, with the relevant operations on it (create, get and set element).
It's like a class in C : There is a constructor, a destructor, and access functions. The array type itself is called struct jagged_col_arr_ST
. There is no way to retain the normal array indexing with square brackets: C does not allow us to define our own operators, e.g. operator[](jagged_col_arr_ST)
. The data structure in the array is by necessity column-oriented, so the column would have to be the first index anyway. Access to elements therefore is through the function JCA_get_elem(arr, rowInd, colInd)
which must get an array (by value, see below) and the two indexes for row and column. In C , this would be a member function, and the array parameter would be implicit (and a pointer).
Because the array type itself holds very little data (a size and a pointer) it is more a handle than an object holding data. It can be passed around by value which saves us a dynamic allocation in the "factory function" create_jagged_col_arr()
: We simply return the entire struct. The same is true for individual columns. That's a bit unusual — traditional C would always pass structures by pointer (and that was in fact the only way to pass structs in the original K&R C). In C a factory like this is often used to provide objects of different derived types at runtime, which must be returned by means of a pointer to base class, which in turn requires dynamic initialization. But there is no polymorphism in C anyway.
Additionally, modern computers love to work on independent data in parallel because they have many cores; pointers, which are aliases — that is, a way to share memory access — get in the way of that. Interestingly, because the actual data is not copied, we can work with copied objects just as with the original: All copies are "shallow" and refer to the same data. Of course you should not call JCA_dispose()
for an array and a copy of that same array.
Most functions are prefixed with JCA_
(for "jagged columns array") because function names like getElem()
might collide with other names in larger projects.
OK, here is the header for the struct and its functions:
jagged_col_array.h
#include <stdint.h> // size_t
/// <summary>
/// A column with its size and a pointer to the dynamically allocated data
/// </summary>
struct JCA_col_ST { size_t mColSz; int* mColDataPtr; };
/// <summary>
/// The array structure, holding a pointer to a dynamically
/// allocated array of colum structures plus the column count
/// </summary>
struct jagged_col_arr_ST
{
size_t mNumCols;
struct JCA_col_ST* mCols;
};
/// <summary>
/// Return a jagged array with the given number of columns that have
/// the sizes given in the array the pointer points to.
/// </summary>
/// <param name="numCols">the number of columns the new array should have</param>
/// <param name="colSizes">the numbers of elements in each of those columns</param>
struct jagged_col_arr_ST create_jagged_col_arr(size_t numCols, size_t* colSizes);
size_t JCA_getNumCols(struct jagged_col_arr_ST arr);
size_t getNumRows(struct jagged_col_arr_ST arr, size_t colInd);
/// <summary>
/// return the element in the given position.
/// </summary>
/// <param name="arr">The array to obtain the element from</param>
/// <param name="row">The row of the desired element</param>
/// <param name="col">The column of the desired element</param>
/// <returns></returns>
int JCA_get_elem(struct jagged_col_arr_ST arr, size_t rowInd, size_t colInd);
/// <summary>
/// return the element in the given position.
/// </summary>
/// <param name="arr">The array in which to set the value of the element</param>
/// <param name="row">The row of the target element</param>
/// <param name="col">The column of the target element</param>
/// <param name="val">The new value of the target element</param>
/// <returns></returns>
void JCA_set_elem(struct jagged_col_arr_ST arr, size_t rowInd, size_t colInd, int val);
/// <summary>
/// Delete the dynamically allocated data.
/// </summary>
/// <param name="arr"></param>
void JCA_dispose(struct jagged_col_arr_ST arr);
Here is the implementation:
jagged_col_array.c
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h> // debatable
#include "jagged_col_arr.h"
/// <summary>
/// Return a structure that has the given column size
/// and points to the corresponding amount of memory
/// </summary>
/// <param name="colSz">The size the column should have</param>
struct JCA_col_ST create_JCA_col_ST(size_t colSz)
{
struct JCA_col_ST newCol;
newCol.mColSz = colSz;
newCol.mColDataPtr = colSz ? malloc(colSz * sizeof(int)) : 0;
if (newCol.mColSz && !newCol.mColDataPtr)
{
fprintf(stderr, "Out of memory");
exit(2);
}
return newCol;
}
/// <summary>
/// Return a jagged array with the given number of columns that have
/// the sizes given in the array.
/// </summary>
/// <param name="numCols">the number of columns the new array should have</param>
/// <param name="colSizes">the number of elements in each of those columns</param>
struct jagged_col_arr_ST create_jagged_col_arr(size_t numCols, size_t* colSizes)
{
struct jagged_col_arr_ST newArr;
newArr.mNumCols = numCols;
newArr.mCols = numCols
? (struct JCA_col_ST*)malloc(numCols * sizeof(struct JCA_col_ST))
: 0;
if (newArr.mNumCols && !newArr.mCols)
{
fprintf(stderr, "Out of memory");
exit(2);
}
for (size_t colInd = 0; colInd < numCols; colInd )
{
newArr.mCols[colInd] = create_JCA_col_ST(colSizes[colInd]);
}
return newArr;
}
size_t JCA_getNumCols(struct jagged_col_arr_ST arr) { return arr.mNumCols; }
size_t getNumRows(struct jagged_col_arr_ST arr, size_t colInd)
{
if (colInd >= arr.mNumCols)
{
fprintf(stderr, "Column index %uz out of bounds", colInd);
exit(1);
}
return arr.mCols ? arr.mCols[colInd].mColSz : 0; // empty columns are not allocated at all.
}
/// <summary>
/// return the colum struct at the given index.
/// </summary>
static struct JCA_col_ST JCA_getCol(struct jagged_col_arr_ST arr, size_t colInd)
{
if (colInd >= arr.mNumCols)
{
fprintf(stderr, "Column index %uz out of bounds", colInd);
exit(1);
}
return arr.mCols[colInd];
}
/// <summary>
/// return the element in the given position.
/// </summary>
/// <param name="arr"></param>
/// <param name="row"></param>
/// <param name="col"></param>
/// <returns></returns>
int JCA_get_elem(struct jagged_col_arr_ST arr, size_t rowInd, size_t colInd)
{
if (colInd >= arr.mNumCols)
{
fprintf(stderr, "Column index %uz out of bounds", colInd);
exit(1);
}
struct JCA_col_ST col = JCA_getCol(arr, colInd);
if (rowInd >= col.mColSz)
{
fprintf(stderr, "Row index %uz out of bounds for column %uz", rowInd, colInd);
exit(1);
}
return col.mColDataPtr[rowInd];
}
void JCA_set_elem(struct jagged_col_arr_ST arr, size_t rowInd, size_t colInd, int val)
{
if (colInd >= arr.mNumCols)
{
fprintf(stderr, "Column index %uz out of bounds", colInd);
exit(1);
}
struct JCA_col_ST col = JCA_getCol(arr, colInd);
if (rowInd >= col.mColSz)
{
fprintf(stderr, "Row index %uz out of bounds for column %uz", rowInd, colInd);
exit(1);
}
col.mColDataPtr[rowInd] = val;
}
void JCA_dispose(struct jagged_col_arr_ST arr)
{
// null pointers are OK to "free".
for (size_t colInd = 0; colInd < arr.mNumCols; colInd )
{
free(arr.mCols[colInd].mColDataPtr);
}
free(arr.mCols);
}
And here is an example use:
variable-colum-sizes.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdint.h> // size_t
#include <stdlib.h> // malloc
#include "jagged_col_arr.h"
void print_arr(struct jagged_col_arr_ST arr)
{
// We'll buffer each printed line because we only know that it was empty
// after we have visited it. But we don't want to print anything
// after the last line.
char* linePrintBuf = malloc(arr.mNumCols * 3 1); // 3 per column, plus terminating 0
if (!linePrintBuf)
{
fprintf(stderr, "Out of memory");
exit(2);
}
int lastRowHadData = 1;
// We don't know how many rows the longest column has. We must try each and check.
// We do this on the fly.
for (size_t rowInd = 0; lastRowHadData; rowInd )
{
size_t linePrintPos = 0;
lastRowHadData = 0; // potentially; if not, corrected in inner loop
for (size_t colInd = 0; colInd < arr.mNumCols; colInd , linePrintPos =3)
{
if (rowInd < getNumRows(arr, colInd))
{
sprintf(linePrintBuf linePrintPos, "=", JCA_get_elem(arr, rowInd, colInd));
lastRowHadData = 1;
}
else
{
sprintf(linePrintBuf linePrintPos, " . ");
}
}
if (lastRowHadData)
{
printf("%s\n", linePrintBuf);
}
}
free(linePrintBuf);
}
int main()
{
size_t colSizes[] = { 3,7,1,0,10 };
struct jagged_col_arr_ST arr
= create_jagged_col_arr(sizeof colSizes / sizeof *colSizes, colSizes);
// Initialize all elements in the array with an integer
// reflecting its row and column position.
for (size_t colInd = 0; colInd < JCA_getNumCols(arr); colInd )
{
for (size_t rowInd = 0; rowInd < getNumRows(arr, colInd); rowInd )
{
JCA_set_elem(arr, rowInd, colInd, rowInd*10 colInd);
}
}
print_arr(arr);
JCA_dispose(arr);
}
The output looks like this:
0 1 2 . 4
10 11 . . 14
20 21 . . 24
. 31 . . 34
. 41 . . 44
. 51 . . 54
. 61 . . 64
. . . . 74
. . . . 84
. . . . 94