Problem with 2D dynamic allocation of arrays and passing it as parameter - c

I have the following problem:
I am populating a 2D array whose number of rows is the number of files I am reading. Therefore the number of columns in each row corresponds to the bytes of data read from the file.
With this picture in mind I have the following program:
I have to return a byte array of data read from each file and the size of each file. This is what I have:
void fillArrays(unsigned char **array, size_t dataSize[], int *nFiles)
{
printf("Calling fillArrays\n");
int i, j, nrows;
nrows = 3;
*nFiles = nrows; // assuming no. of files to be read = 3
dataSize = (size_t *)malloc(nrows * sizeof(size_t));
array = (unsigned char**)malloc(nrows * sizeof(unsigned char *));
dataSize[0] = 4; // assuming file 1 contains 4 bytes
dataSize[1] = 3; // assuming file 2 contains 3 bytes
dataSize[2] = 1;// assuming file 3 contains 1 bytes
//populating file data into a 2D array. Here for test purpose assuming each file has data = 0x03!!
for(i = 0; i < nrows; i++)
{
array[i] = (unsigned char *) malloc(dataSize[i] * sizeof(unsigned char));
for(j = 0; j < dataSize[i]; j++){
printf("round %d %d\n", i,j);
array[i][j] = 0x03;
printf("array [%d][%d] = %02X\n ", i, j , array[i][j]);
}
//array[i][dataSize[i]]= '\0';
}
}
int main(int argc, char *argv[])
{
unsigned char **fileArray;
int noFiles = 0;
size_t *fileSize;
fillArrays(fileArray,fileSize, &noFiles);
printf("Returned no. of files = %d\n", noFiles);
printf("fileSize[0] = %lu\n", fileSize[0]);
printf("fileSize[1] = %lu\n", fileSize[1]);
printf("fileSize[2] = %lu\n", fileSize[2]);
int j = 0;
for (int i = 0; i < noFiles; i++){
printf("i = %d\n", i);
for (int j = 0; j < fileSize[i]; j++){
printf("Obtained data from file %d : (fileArray [%d][%d]) = %02X\n ", i, i, j , fileArray[i][j]);
//j++;
}
}
return 0;
}
the code is segfaulting in the 'j' loop in the main function. Could someone throw some light?
How can this be done better?
Thanks.

You are passing fileArray by value, so in fillArrays you are modyfing copy of this pointer to pointer, so after executing fillArrays function, fileArray in main function is not affected - it is still uninitialized, you need to pass this variable by reference (pass pointer to fileArray):
fillArrays(&fileArray,fileSize, &noFiles);
then in fillArrays you need to add these modifications:
void fillArrays(unsigned char ***array, size_t dataSize[], int *nFiles)
{
//...
*array = (unsigned char**)malloc(nrows * sizeof(unsigned char *));
//...
(*array)[i] = (unsigned char *) malloc(dataSize[i] * sizeof(unsigned char));
///...
(*array)[i][j] = 0x03;
}

your array and dataSize are local to fillArrays function and
allocating memory to them inside fillArrays will not affect the arrays inside main.
// Allocates the memory to local variables
dataSize = (size_t *)malloc(nrows * sizeof(size_t));
array = (unsigned char**)malloc(nrows * sizeof(unsigned char *));
Hence you need to use pointer to pointer to char* for fileArray and
pointer to size_t* for fileSize.
Your prototype will become as below.
void fillArrays(unsigned char ***array, size_t **dataSize, int *nFiles)
And you call the function as below.
fillArrays(&fileArray,&fileSize, &noFiles);
Sample code:
void fillArrays(unsigned char ***array, size_t **dataSize, int *nFiles)
{
printf("Calling fillArrays\n");
int i, j, nrows;
nrows = 3;
*nFiles = nrows; // assuming no. of files to be read = 3
*dataSize = (size_t *)malloc(nrows * sizeof(size_t));
*array = (unsigned char**)malloc(nrows * sizeof(unsigned char *));
(*dataSize)[0] = 4; // assuming file 1 contains 4 bytes
(*dataSize)[1] = 3; // assuming file 2 contains 3 bytes
(*dataSize)[2] = 1;// assuming file 3 contains 1 bytes
//populating file data into a 2D array. Here for test purpose assuming each file has data = 0x03!!
for(i = 0; i < nrows; i++)
{
(*array)[i] = (unsigned char *) malloc((*dataSize)[i] * sizeof(unsigned char));
for(j = 0; j < (*dataSize)[i]; j++){
printf("round %d %d\n", i,j);
(*array)[i][j] = 0x03;
printf("array [%d][%d] = %02X\n ", i, j , (*array)[i][j]);
}
//array[i][dataSize[i]]= '\0';
}
}
int main(int argc, char *argv[])
{
unsigned char **fileArray;
int noFiles = 0;
size_t *fileSize;
fillArrays(&fileArray,&fileSize, &noFiles);
printf("Returned no. of files = %d\n", noFiles);
printf("fileSize[0] = %lu\n", fileSize[0]);
printf("fileSize[1] = %lu\n", fileSize[1]);
printf("fileSize[2] = %lu\n", fileSize[2]);
int j = 0;
for (int i = 0; i < noFiles; i++){
printf("i = %d\n", i);
for (int j = 0; j < fileSize[i]; j++){
printf("Obtained data from file %d : (fileArray [%d][%d]) = %02X\n ", i, i, j , fileArray[i][j]);
//j++;
}
}
return 0;
}
Alternate approach:
I suggest you to not have pointer to pointer to char* as parameter instead you just return the filled array from fillArrays as below.
char** fillArrays(size_t **dataSize, int *nFiles)
{
printf("Calling fillArrays\n");
int i, j, nrows;
char **array = NULL;
nrows = 3;
*nFiles = nrows; // assuming no. of files to be read = 3
*dataSize = (size_t *)malloc(nrows * sizeof(size_t));
array = (unsigned char**)malloc(nrows * sizeof(unsigned char *));
(*dataSize)[0] = 4; // assuming file 1 contains 4 bytes
(*dataSize)[1] = 3; // assuming file 2 contains 3 bytes
(*dataSize)[2] = 1;// assuming file 3 contains 1 bytes
//populating file data into a 2D array. Here for test purpose assuming each file has data = 0x03!!
for(i = 0; i < nrows; i++)
{
array[i] = (unsigned char *) malloc((*dataSize)[i] * sizeof(unsigned char));
for(j = 0; j < (*dataSize)[i]; j++){
printf("round %d %d\n", i,j);
array[i][j] = 0x03;
printf("array [%d][%d] = %02X\n ", i, j , array[i][j]);
}
//array[i][dataSize[i]]= '\0';
}
return array;
}
and you call the function as below.
fileArray = fillArrays(&fileSize, &noFiles);

Related

I have a problem when i'm printing char** array

I'm working with grap.
My graph is a structure like this
typedef struct{
int order; // number of node
int **mat; // matrix graphe
}graphe;
I'm working on school project and I need to build a set of binary's number from 0 to N (where is the order of the graph)
Actually I did this, it's working. When I'm printing the final variable, it displays all declinaison of binary number (000, 001, 010, 011, etc...)
char** construireSousEnsemble(graphe g){
int size = pow(2, g.order);
char** D = (char**)malloc(sizeof(char*)*g.order-1);
for (int i = 0; i < size; i++){
D[i] = (char*)malloc(g.order-1);
char buffer[g.order-1];
char tmp[g.order-1];
char final[g.order-1];
for (int j = g.order-1; j >= 0; j--){
int bin = (i >> j)&1;
sprintf(buffer, "%d", bin);
snprintf(tmp, sizeof(tmp), "%s", buffer);
strcat(final, tmp);
if (j == 0){
strcpy(D[i], final);
//printf("%s\n", D[i]);
//printf("%d | %s\n", i, D[i]);
memset(final, 0, sizeof(final)); // reset the zone
}
}
//printf("\n");
}
return D;
}
But in the main function, when I'm calling the function like this:
char** zones = construireSousEnsemble(g);
But when I'm printing the content with zones, I have this:
So I'm a bit lost.
This example is for a 3 nodes graph. If I have a 4 nodes, the weird symbol increase and I won't have 0001 or 0010 etc.., same with 5 or 6 nodes.
So my question is, why is this happening?
By the way, I'm not confortable with C so maybe I made some mistakes.
Thank you all :)
Here is the solution (posting if for the future)
char ** construireSousEnsemble(graphe g){
int size = pow(2, g.order);
char **D = (char **) malloc (sizeof (char *) * size);
char buffer[g.order];
char final[g.order];
for (int i = 0; i < size; i++) {
D[i] = (char *)malloc(g.order + 1);
final[0] = 0;
for (int j = g.order - 1; j >= 0; j--) {
int bin = (i >> j) & 1;
sprintf (buffer, "%d", bin);
strcat (final, buffer);
}
strcpy (D[i], final);
}
return D;
}

Converting Static 2D Array to Dynamic Array in C

We were asked to convert 2D static array to dynamic array. So I will need to create an array of pointers in which every pointer points to a different row. I have written this code but my code breaks when i=1 on line *(dynamicStr[i] + v) = rowStr[v]; Additionally, if I enable free(ptr); section my debugger gets stuck there for 6 or 7 times and then contiunes.
EDIT: In the end, I solved the problem with appying the answers #dodooft and #Viktor Terziev gave.
#include <stdio.h>
#include <stdlib.h>
void toDynamic(int x,int y, char toDyna[x][y]);
void toDynamic2(int x,int y, char toDyna[x][y]);
int main()
{
char toDyna[7][12] = {
"JOHN",
"MARK",
"PIERCEPIERCE",
"20",
"ROSIE",
"ALEX",
"MARLYN"
};
int x = 7;
int y = 12;
toDynamic2(x, y, toDyna);
return 0;
}
void toDynamic2(int x,int y, char toDyna[x][y]){
char *dynamicStr[x];
int rowToCheck = 0;
int size;
char *ptr;
int c;
for(int i = 0; i < x; i++){
printf("i: %d\n",i);
c = 0;
size = strlen(toDyna[rowToCheck]);
ptr = (char*) malloc(size * sizeof(char));
for(int j = 0; j < y; j++){
if(toDyna[i][j] != '\0'){
*(ptr+c) = toDyna[i][j];
c++;
} else{
break;
}
}
*(ptr+size) = '\0';
printf(" ");
char rowStr[size];
for(int v = 0; v < size; v++){
rowStr[v] = *(ptr+v);
printf("Added Char: %c\n", rowStr[v]);
*(dynamicStr[i] + v) = rowStr[v];
}
//free(ptr);
//printf("\n%s\n", rowStr);
//dynamicStr[i] = &rowStr;
rowToCheck++;
}
for(int i = 0; i < x; i++){
printf("%s\n", dynamicStr[i]);
}
}
EDIT: This is the working verion of the code:
#include <stdio.h>
#include <stdlib.h>
char** toDynamic(int x,int y, char toDyna[x][y]);
void free2DArray(int x, char **dynamicStr);
int main()
{
char toDyna[7][12] = {
"JOHN",
"MARK",
"PIERCEPIERCE",
"20",
"ROSIE",
"ALEX",
"MARLYN"
};
int x = 7;
int y = 12;
char **dynamicArr;
dynamicArr = toDynamic(x, y, toDyna);
free2DArray(x, dynamicArr);
return 0;
}
char** toDynamic(int x,int y, char toDyna[x][y]){
printf("Q2\n");
char **dynamicStr;
int rowToCheck = 0;
int size;
int c;
dynamicStr = (char*)malloc(x * sizeof(char*));
for(int i = 0; i < x; i++){
dynamicStr[i] = (char*)malloc(y * sizeof(char));
c = 0;
size = strlen(toDyna[rowToCheck]);
char *ptr = (char*) malloc((size + 1) * sizeof(char));
for(int j = 0; j < y; j++){
if(toDyna[i][j] != '\0'){
*(ptr+c) = toDyna[i][j];
c++;
} else{
break;
}
}
*(ptr+size) = '\0';
dynamicStr[i] = ptr;
rowToCheck++;
}
for(int i = 0; i < x; i++){
printf("%s\n", dynamicStr[i]);
}
printf("----------------------------\n");
return dynamicStr;
}
void free2DArray(int x, char **dynamicStr){
printf("Q3\n");
for(int i = 0; i < x; i++){
free(dynamicStr[i]);
printf("dynamicStr %d freed\n", i);
}
free(dynamicStr);
printf("dynamicStr array freed\n");
printf("----------------------------\n");
}
You define dynamicStr as an array of char pointers, when you are trying to assign a value to it with *(dynamicStr[i] + v) = rowStr[v]; you are basically copying the value of rowStr[v] to the address that is pointed by dynamicStr[i] + v. That address is not defined in your code, so you got a segfault.
If you are trying to fill dynamicStr with pointers to new arrays with dynamic memory, you should try something like
dynamicStr[i] = ptr;
where ptr is the pointer returned by the malloc call to the i-th row. Also, as you are working with strings you can use strcpy to copy the data from the static array to the dynamic one.
Its much easier than you think, please refer to strcpy documentation and strlen documentation, and (if you use my code) don't forget to free your memory.
char * * toDynamic2(size_t n, size_t m, char strings[n][m])
{
char * * arr = malloc(n * sizeof(char*));
for(size_t i = 0; i < n; ++i)
{
size_t size = strlen(strings[i]);
arr[i] = malloc((size + 1) * sizeof(char));
strcpy(arr[i], strings[i]);
}
for(size_t i = 0; i < n; ++i)
{
printf("%s\n", arr[i]);
}
return arr;
}

Function allocate and modify many (more than one) arrays in C [duplicate]

This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Closed 2 years ago.
A C function can modify more than one variable by an illusion of pass-by-reference (a pass-by-value of address as explained by Ely), e.g.:
#include <stdio.h>
void function(int *pa, int *pb) {
*pa *= *pa;
*pb *= *pb;
}
int main(void) {
int a = 1, b = 2;
function(&a, &b);
printf("a = %d\nb = %d\n", a, b);
return 0;
}
which outputs
a = 1
b = 4
It is also possible to modify a whole range of variables by returning a pointer to an array, e.g.:
#include <stdlib.h>
#include <stdio.h>
int *function(int *ptr_size) {
int n = 6; // arbitrary ptr_size
int *array = (int *)malloc(n * sizeof(int));
for (int i = 0; i < n; ++i)
array[i] = i * i;
//
*ptr_size = n;
return array;
}
int main(void) {
int size = 0;
int *array = function(&size);
printf("size = %d\n", size);
for (int i = 0; i < size; ++i)
printf("array[%d] = %d\n", i, array[i]);
free(array);
array = NULL;
return 0;
}
which outputs :
size = 6
array[0] = 0
array[1] = 1
array[2] = 4
array[3] = 9
array[4] = 16
array[5] = 25
But what if I want a function that modify more than one (dynamic allocated) array ?
I tried this
#include <stdlib.h>
#include <stdio.h>
void function(int *array, int *ptr_asize, int *brray, int *ptr_bsize) {
int size = 6;
array = (int *)malloc(size * sizeof(int));
brray = (int *)malloc(size * sizeof(int));
for (int i = 0; i < size; ++i) {
array[i] = i * i;
brray[i] = i * i * i;
}
*ptr_asize = size;
*ptr_bsize = size;
}
int main(void) {
int asize, bsize;
int *array, *brray;
function(array, &asize, brray, &bsize);
// array
printf("asize = %d\n", asize);
for (int i = 0; i < asize; ++i)
printf("array[%d] = %d\n", i, array[i]);
free(array);
array = NULL;
// brray
printf("bsize = %d\n", bsize);
for (int i = 0; i < bsize; ++i)
printf("brray[%d] = %d\n", i, brray[i]);
free(brray);
brray = NULL;
//
return 0;
}
but it makes a segmentation fault.
That is not very surprising, how main would know about how much memory has been allocated to array and brray?
So my question is: is it possible in C that a function allocate and modify more than one array, and those changes remain in main?
PS: A solution would be to allocate a new abrray that contains both array and brray (int **function(...) { ... return abrray; }), but I would like to know if it is possible to a function to modify two (or more) arrays, and that changes remain in main.
Pass a pointer to pointer, like this:
void func(int** array, int** brray, size_t size_a, size_t size_b) {
*array = malloc(size_a * sizeof(int));
*brray = malloc(size_b * sizeof(int));
}
Call it like:
int *arr, *brr;
func(&arr, &brr, 2, 5);
As explained by iTs.SL4y3r, it is possible by passing pointer to pointer.
Here is a minimal working example :
#include <stdlib.h>
#include <stdio.h>
void function(int **array, int *ptr_asize, int **brray, int *ptr_bsize) {
int size = 6;
*array = malloc(size * sizeof(int));
*brray = malloc(size * sizeof(int));
for (int i = 0; i < size; ++i) {
(*array)[i] = i * i;
(*brray)[i] = i * i * i;
}
*ptr_asize = size;
*ptr_bsize = size;
}
int main() {
int asize, bsize;
int *array, *brray;
function(&array, &asize, &brray, &bsize);
// array
printf("asize = %d\n", asize);
for (int i = 0; i < asize; ++i)
printf("array[%d] = %d\n", i, array[i]);
free(array);
array = NULL;
// brray
printf("bsize = %d\n", bsize);
for (int i = 0; i < bsize; ++i)
printf("brray[%d] = %d\n", i, brray[i]);
free(brray);
brray = NULL;
//
return 0;
}
which outputs :
asize = 6
array[0] = 0
array[1] = 1
array[2] = 4
array[3] = 9
array[4] = 16
array[5] = 25
bsize = 6
brray[0] = 0
brray[1] = 1
brray[2] = 8
brray[3] = 27
brray[4] = 64
brray[5] = 125

Dynamic multidimensional array on the heap

I want to create a function which can allocate a multidimensional array on the heap with only one call to malloc. (Pointer array) So a function call would look like this:
size_t dim[2] = {2, 4};
int **_2darray = alloc_array(sizeof(int), dim, 2);
// ^ should be the "same" as:
int __2darray[2][4];
What I have so far is the SIZE computation of the whole block needed to hold the array and the pointers:
void *alloc_array(size_t element_size, size_t dimensions[static 1], size_t ndims)
{
unsigned char *DATA = NULL;
size_t SIZE = 0;
size_t multiplicators[ndims];
// Calculate for each dimension the multiplier
// SIZE 3d array: (N1 * sizeof(T **) + (N1 * N2 + sizeof(T *) + (N1 * N2 * n3 + sizeof(T))
// ^- first mulitplier ^ second multiplier ^ third multiplier
for (size_t i = 0; i < ndims; ++i) {
multiplicators[i] = dimensions[i];
for (size_t j = 0; j < i; ++j) {
multiplicators[i] *= dimensions[j];
}
}
SIZE = 0;
for (size_t dimI = 0; dimI < ndims; ++dimI) {
size_t mulval = multiplicators[dimI];
// The elements are in the "last" dimension
if (dimI+1 == ndims) {
SIZE += element_size * mulval;
} else {
// All other elements are pointers to the specific element
SIZE += sizeof(void *) * mulval;
}
}
DATA = malloc(SIZE);
return DATA;
}
So by now the SIZE calculation works. But now I'm stuck with setting the pointers to the right element. I know it's easy with dealing with static dimensions but I want this to be done with dynamic dimensions.
#include <stdlib.h>
#include <stdio.h>
void fill_array_pointers (void** pointers, char* elements,
size_t element_size, size_t total_elements_size,
size_t dimensions[], size_t ndims)
{
if (ndims == 2)
{
size_t i;
for (i = 0; i < dimensions[0]; ++i)
{
pointers[i] = elements + i * element_size * dimensions[1];
}
}
else
{
size_t i;
size_t block_size = total_elements_size / dimensions[0];
for (i = 0; i < dimensions[0]; ++i)
{
pointers[i] = pointers + dimensions[0] + i * dimensions[1];
fill_array_pointers (pointers + dimensions[0]
+ i * dimensions[1],
elements + block_size * i,
element_size, block_size,
dimensions+1, ndims-1);
}
}
}
void* alloc_array (size_t element_size, size_t dimensions[],
size_t ndims)
{
size_t total_elements_size = element_size;
int i;
// total size of elements
for (i = 0; i < ndims; ++i)
total_elements_size *= dimensions[i];
// total size of pointers
size_t total_pointers_size = 0;
int mulval = 1;
for (i = 0; i < ndims-1; ++i)
{
total_pointers_size += dimensions[i] * sizeof(void*) * mulval;
mulval *= dimensions[i];
}
size_t total_size = total_pointers_size;
size_t oddball = total_pointers_size % element_size;
// really needs to be alignof but we don't have it
if (oddball) total_size += (element_size - oddball);
total_size += total_elements_size;
void* block = malloc (total_size);
void** pointers = block;
char* elements = (char*)block + total_size - total_elements_size;
fill_array_pointers (pointers, elements, element_size,
total_elements_size, dimensions, ndims);
return block;
}
Test drive:
int main ()
{
size_t dims[] = { 2, 3, 4 };
int*** arr = alloc_array(sizeof(int), dims, 3);
int i, j, k;
for (i = 0; i < dims[0]; ++i)
for (j = 0; j < dims[1]; ++j)
for (k = 0; k < dims[2]; ++k)
{
arr[i][j][k] = i*100+j*10+k;
}
for (i = 0; i < dims[0]*dims[1]*dims[2]; ++i)
{
printf ("%03d ", (&arr[0][0][0])[i]);
}
printf ("\n");
free (arr);
}
This will not work for multidimensional char arrays on systems where sizeof(char*) != sizeof(char**); such systems exist but are rare. Multidimensional char arrays are pointless anyway.
The test runs cleanly under valgrind.
This is more an intellectual exercise than anything else. If you need maximum performance, don't use arrays of pointers, use a flat array and ugly but efficient explicit index calculations. If you need clear and concise code, you are probably better off allocating each level separately.

How to create a variable sized array, pass a variable 2d array to a function and return another 2d array?

How do you create an 2d array with variable size, pass that variable array, and return a new 2d array of different dimensions? I've been working on this for hours and I can't find a solution. I managed to create an array of pixel values for a PGM image, but now I'm trying to "rotate" the array, but this is getting incredibly complex since my compiler won't let me declare a variable-sized object.Thank you so much to those who answer.
This is the statement that calls the function. Somebody told me to use malloc since you can't create an array with variable size.
char *SpunArray = malloc(image->x * image->y * sizeof(PGMPixel));
SpunArray = Rotate90Array(image->x, image->y, CreatedArray);
This is the function:
//char * Rotate90Array(int x, int y, char *array[x][y] )
char * Rotate90Array(int x, int y, char *array )
{
printf("\nLine 179");
// These have to be swapped because the image is being rotated
char *RotatedArray = malloc(x * y * sizeof(char));
printf("\nLine 182");
int u = x - 1;
int v = y - 1;
int i = 0;
int j = 0;
printf("\nLine 187");
char *ptr;
printf("\nLine 189");
for (i = 0; i < x; i++)
{
printf("\nLine 192");
*ptr = RotatedArray[i];
printf("\nLine 194");
for (j = 0; j < y; j++)
{
printf("\nLine 197");
// *ptr = *(array[u-j][i]);
*(ptr+((j*x)+(u-i))) = *(array+((i*y)+j));
printf("\nLine 200");
ptr++;
printf("\nLine 202");
}
}
printf("\nLine 205");
return RotatedArray;
}
I'm using the MingGW gcc, and windows 8 if that helps.
You have a memory leak. Why do you creating two arrays instead one?
Do like this:
char *SpunArray = malloc(image->x * image->y * sizeof(PGMPixel));
Rotate90Array(image->x, image->y, CreatedArray, SpunArray);
void Rotate90Array(int width, int height, char *array, char *RotatedArray)
{
int i = 0;
int j = 0;
for (i = 0; i < width; i++)
{
for (j = 0; j < height; j++)
{
// check this line on correct
RotatedArray[i * height + j] = array[j * width + width - i - 1];
}
}
}
I think this code can work as expect:
char * Rotate90Array(int x, int y, char *array )
{
printf("\nLine 179");
// These have to be swapped because the image is being rotated
char *RotatedArray = malloc(x * y * sizeof(char));
printf("\nLine 182");
int u = x - 1;
int v = y - 1;
int i = 0;
int j = 0;
printf("Line 187\n");
char *ptr;
printf("Line 189\n");
ptr = RotatedArray; //I add this line
for (i = 0; i < x; i++)
{
printf("Line 192\n");
// *ptr = RotatedArray[i]; //I delete this line
printf("Line 194\n");
for (j = 0; j < y; j++)
{
printf("Line 197\n");
// *ptr = *(array[u-j][i]);
*(ptr+((j*x)+(u-i))) = *(array+((i*y)+j));
printf("Line 200\n");
// ptr++; // I delete this line
printf("Line 202\n");
}
}
printf("Line 205\n");
return RotatedArray;
}

Resources