Reallocing and manipulating a 2d-array inside a function - arrays

I am trying to reallocate both elements of a 2D-array and also manipulate the values in the 2D-array within the same function. But I just can't seem to get it to work. On compiling the code doesn't show any errors, but when running it will only ever print the amount of lines I specified as the initial_size at the beginning of the main function.
So it seems that the inner realloc is working fine, as it always prints an entire row once it gets started. But the outer realloc is not working, as it will only print a couple of rows.
Note: The real code takes input of unknown size, from getchar() / scanf(). That is why the realloc functions are inside loops in the function.
Simplified version of the function, with error handling omitted:
void func(int ***A) {
int i, j;
int len = 2;
int len2 = 2;
for (i = 0; i < 10; i++) {
// Check to see if a realloc is needed.
if (i >= len) {
len *= 2;
int **tmp = realloc(*A, len * sizeof(int*));
*A = tmp;
printf("Len1 = %d\n", len);
}
len2 = 2;
for (j = 0; j < 20; j++) {
// Check to see if a realloc is needed.
if (j >= len2) {
len2 *= 2;
int *new_row = realloc((*A)[i], len2 * sizeof(int));
(*A)[i] = new_row;
}
// Assign value.
(*A)[i][j] = i * j;
}
}
}
int main() {
int i, j;
int initial_size = 2;
int **A;
// Malloc with a starting size of 2 (could be any size).
A = malloc(initial_size * sizeof(int*));
for (i = 0; i < initial_size; i++) {
A[i] = malloc(initial_size * sizeof(int));
}
// Call function.
func(&A);
// Print the results, row by row.
for (i = 0; i < 10; i++) {
for (j = 0; j < 20; j++) {
printf("%d, ", A[i][j]);
}
printf("\n");
}
return 0;
}
I have been stuck for a while now, so any help is greatly appreciated :)

When you realloc in the outer loop, you increase the numbers of pointers from two (those created in main) to four.
The value of the two pointers from main are copied to the new memory area.
The value of the two new pointers are indeterminate and that's your problem. You never initialize them by allocating memory - yet you use them in the other loop.
Further, it seems that you realloc the inner array dimensions individually but you only track one length (i.e. len2). That's also a problem.
And the line len2 = 2 between the loops are wrong as you loose information about previously allocated memory.

There are multiple problems in your code:
you reallocate the pointer array but do not initialize the pointers in the newly allocated portion
you only reallocate the first int array pointed to by the pointer array
you do not initialize the newly allocated area in this int array.
Note that 2D-matrices are more idiomatic in C as arrays of arrays, but it is difficult to manipulate such arrays when the outer dimension is not fixed at compile time.
You should use a reallocation function with specified dimensions for the current and target sizes and deal with reallocating and freeing the blocks appropriately. Also avoid triple pointers: just return the potentially reallocated outer array.
#include <stdio.h>
#include <stdlib.h>
int **func(int **A, int rows, int cols, int new_rows, int new_cols) {
int i, j;
/* free the rows that are discarded */
if (new_rows < rows) {
for (i = new_rows; i < rows; i++) {
free(A[i]);
}
}
/* free the outer array if new rows is zero */
if (new_rows == 0) {
free(A);
return NULL;
}
/* reallocate the outer array if required */
if (new_rows != rows) {
A = realloc(A, sizeof(*A) * new_rows);
}
/* reallocate the existing rows */
if (new_cols != cols) {
for (i = 0; i < rows; i++) {
A[i] = realloc(A[i], sizeof(int) * new_cols);
if (new_cols > cols) {
for (j = cols; j < new_cols; j++)
A[i][j] = 0;
}
}
}
/* allocate the new rows (initialized to 0) */
for (i = rows; i < new_rows; i++) {
A[i] = calloc(sizeof(int), new_cols);
}
return A;
}
int main() {
int **A = NULL;
/* reallocate to 10x20 */
A = func(A, 0, 0, 10, 20);
// Print the results, row by row.
for (i = 0; i < 10; i++) {
for (j = 0; j < 20; j++) {
printf("%d, ", A[i][j]);
}
printf("\n");
}
/* reallocate to 0x0 (free the matrix) */
func(A, 10, 20, 0, 0);
return 0;
}
Note that the above code does not check for memory allocation failure. To deal with this possibility, it would be much simpler to allocate a new array and copy the current values, then free the previous matrix if no allocation error occurred. It would also be more efficient to allocate all rows as a single block of memory. Below is an example of this approach:
#include <stdio.h>
#include <stdlib.h>
int **func(int **A, int rows, int cols, int new_rows, int new_cols) {
int i, j;
int **B = NULL;
if (new_rows == rows && new_cols == cols)
return A;
if (new_rows != 0 && new_cols != 0) {
/* allocate the new matrix */
B = malloc(sizeof(*B) * new_rows);
if (B == NULL)
return NULL;
B[0] = calloc(sizeof(int) * new_cols, new_rows);
if (B[0] == NULL) {
free(B);
return NULL;
}
/* initialize the row pointers */
for (i = 1; i < new_rows; i++) {
B[i] = B[i - 1] + new_cols;
}
/* copy the current data */
for (i = 0; i < new_rows && i < rows; i++) {
for (j = 0; j < new_cols && j < cols; i++) {
B[i][j] = A[i][j];
}
}
}
/* free the previous matrix */
if (A != NULL) {
free(A[0]);
free(A);
}
return B;
}
int main() {
int **A = NULL;
int i, j;
/* reallocate to 10x20 */
A = func(A, 0, 0, 10, 20);
if (A == NULL) {
printf("Matrix reallocation failed\n");
return 1;
}
// Print the results, row by row.
for (i = 0; i < 10; i++) {
for (j = 0; j < 20; j++) {
printf("%d, ", A[i][j]);
}
printf("\n");
}
/* reallocate to 0x0 (free the matrix) */
func(A, 10, 20, 0, 0);
return 0;
}

Related

Dynamic memory allocation for two-dimensional arrays

I want to allocate memory for a two-dimensional array (matrix) and write the sums of the diagonals in a separate one-dimensional array. So my code has an array of pointers to pointers,
int N, ** matrix = NULL;
matrix = (int**) malloc(sizeof(int*) * N);
I fill it and then I create an array to store the sums of the diagonals,
int diag = 2 * N - 1;
int *diagonals = NULL;
diagonals = (int*)malloc(sizeof(int) * diag);
but when I want to write a value into an array, something goes wrong, the values just don't get written into the array; I don't know why.
Here is my code:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main() {
srand(time(NULL));
int N, ** matrix = NULL;
printf("Input the number of rows\n");
scanf_s("%d", &N);
printf("\n");
// Memory allocation for the array of pointers to pointers
matrix = (int**) malloc(sizeof(int*) * N);
if (matrix != NULL)
{
for (int i = 0; i < N; i++)
*(matrix + i) = (int*)malloc(sizeof(int) * N);
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
matrix[i][j] = rand() % 14 - 4;
printf("%d\t", matrix[i][j]);
}
printf("\n");
}
printf("\n");
int diag = 2 * N - 1;
int *diagonals = NULL;
diagonals = (int*)malloc(sizeof(int) * diag);
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
diagonals[i+j] += matrix[i][j];;
}
}
for (int i = 0; i < diag; i++) {
printf("diagonals[%d] - %d\n",i, *(diagonals+i));
}
}
else
printf("Not enough memory.. oops..\n");
}
The content of diagonals is allocated with malloc() which does not initialize the memory. You should use calloc() which initializes the memory with zeros:
diagonals = calloc(diag, sizeof *diagonals);
The following loop assumes that each element of diagonals was initialized to zero, but you performed no such initialization. As a result, they are uninitialized and will contain whatever value happens to be sitting in the newly-allocated memory.
diagonals = malloc(sizeof(int) * diag);
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
diagonals[i+j] += matrix[i][j];;
}
}
You have several options for zero-initialization:
Use memset to zero the memory, after allocation:
diagonals = malloc(sizeof(int) * diag);
memset(diagonals, 0, sizeof(int) * diag);
Initialize values in a loop:
diagonals = malloc(sizeof(int) * diag);
for (int i = 0; i < diag; i++) diagonals[i] = 0;
Allocate with calloc:
diagonals = calloc(diag, sizeof(int));
Note that in all cases, you should be checking the result of allocation. If it fails and returns NULL, you should not attempt to access memory via that pointer.
It does not answer the question but I would suggest using real 2D arrays instead of arrays of pointers. To dynamically allocate the 2D array you need to use a pointer to array.
int (*matrix)[N] = malloc(N * sizeof(*matrix));
You will have only one allocation and one free. Fever levels of indirection.

Understanding Array of pointers

I am doing something like this;
int main()
{
int *b[2], j;
for (j = 0; j < 2; j++)
{
b[j] = (int *)malloc(12 * sizeof(int));
}
return 0;
}
Please tell me what this instruction really means? And how can I pass this array of pointers to a function to access values like *(B[0]+1),*(B[1]+1) etc?
int main(void)
{
int *b[2], j; // initialization of an array of pointers to integers (size = 2)
for (j = 0; j < 2; j++) // for each of the pointers
{
b[j] = malloc(12 * sizeof (int)); // allocate some space = 12 times size of integer in bytes (usually 4)
}
return 0;
}
If you want to pass this array to a function you can just pass b
foo(b);

Problem with allocating multiplication table

I need to write a program that will allocate the memory for multiplication table. The problem is that single call of malloc, calloc and realloc is limited to 80 bytes and I don't know how to allocate memory stage by stage.
If anyone could help me I would be grateful.
Here is what I have tried already. It works if I allocate the memory for 400 bytes in one call.
int main()
{
int row = 10;
int col = 10;
int w=0;
int k=0;
int *tab = (int *)malloc(row*col*sizeof(int));
if(tab == NULL)
{
printf("Failed to allocate memory");
return 8;
}
int i=0;
for (w=0; w<row; w++)
{
for(k=0; k<col; k++)
{
*(tab+w*col+k) = ++i;
}
}
for (w=0; w<row; w++){
for(k=0; k<col; k++){
printf("%3d ", *(tab+w*col+k) );
}
printf("\n");
}
free(tab);
return 0;
}
Nested mallocs() are what you'll need to use. But, be careful, because you'll also need to use several frees()!
// 80 bytes
int** table = malloc(row * sizeof(int*));
for (int i = 0; i < row; i++) {
// 80 bytes
table[i] = malloc(col * sizeof(int));
}
// The 6th element in the first row is set to 5.
table[0][5] = 5;

How to make a function returning a dynamically-allocated two-dimensional array?

I am trying to return a contiguous memory allocated array from a function but I keep on receiving errors.
Compiler returns a warning saying return from incompatible pointer type [-Wincompatible-pointer-types]
Can someone tell me what I am doing wrong?
int *test() {
size_t rows, cols;
// assign rows and cols
rows = 3;
cols = 3;
int count = 0;
int (*arr)[cols] = malloc(sizeof *arr * rows);
if (arr) {
// do stuff with arr[i][j]
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; j++) {
arr[i][j] = count;
count++;
}
/* code */
}
}
return arr;
}
int main() {
size_t rows, cols;
// assign rows and cols
rows = 3;
cols = 3;
int count = 0;
int (*arr)[cols] = malloc(sizeof *arr * rows);
arr = test();
int i = 0;
int j = 0;
for (i = 0; i < rows; ++i) {
for (j = 0; j < 3; ++j)
printf("%d ", arr[i][j]);
printf("\n");
}
free(arr);
}
it should return a 2D array but returns an error and am using gcc on ubuntu
Your allocation function is fine, except for a few details:
you should pass rows and cols as arguments
you should use type size_t for i and j and iterate to rows and cols instead of hard coded bounds.
you should use parentheses in malloc(sizeof *arr * rows); for readability:
malloc(sizeof(*arr) * rows);
you should return &arr[0][0] or arr[0] for type correctness.
The problem is you cannot define the return type of test to be pointer to 2D array of a parametric second dimension. Hence the type error on the assignment arr = test(); cannot be fixed. You can work around this shortcoming by casting the return value to (int (*)[cols]) or simply (void *).
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int *test(size_t rows, size_t cols) {
int (*arr)[cols] = malloc(sizeof(*arr) * rows);
if (arr) {
// initialize the matrix
size_t count = 0;
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
arr[i][j] = count;
count++;
}
/* code */
}
return &arr[0][0];
}
return NULL;
}
int main() {
// assign rows and cols
size_t rows = 3;
size_t cols = 3;
int (*arr)[cols] = (int (*)[cols])test(rows, cols);
if (arr) {
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
free(arr);
}
return 0;
}
Output:
0 1 2
3 4 5
6 7 8
If all what you need is
to return a contiguous memory allocated array from a function
You can ignore this answer.
If what you are trying to do is to model a bidimensional container (like a matrix) using a dynamically allocated contiguous block of memory, you could define a struct and pass that around:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct {
int rows, cols;
int values[]; // I'm using a Flexible Array Member here.
} iMat;
iMat *alloc_matrix(int rows, int columns)
{
assert(rows > 0 && columns > 0);
iMat *tmp = malloc(sizeof *tmp + sizeof *(tmp->values) * rows * columns);
if (tmp)
{
tmp->rows = rows;
tmp->cols = columns;
}
return tmp;
}
void fill_matrix_iota(iMat *m, int start)
{
if ( m )
for (size_t i = 0, n = m->rows * m->cols; i < n; ++i)
m->values[i] = start + i;
}
void print_matrix(iMat *m, int width)
{
if (m)
{
for (int i = 0, k = 0; i < m->rows; ++i)
{
for(int j = 0; j < m->cols; ++j, ++k)
{
printf("%*.d", width, m->values[k]);
}
putchar('\n');
}
}
}
iMat *make_transposed(iMat *m)
{
if ( !m )
return NULL;
iMat *tmp = alloc_matrix(m->cols, m->rows);
if ( tmp )
{
for (int i = 0; i < m->rows; ++i)
{
for(int j = 0; j < m->cols; ++j)
{
tmp->values[j * m->rows + i] = m->values[i * m->cols + j];
}
}
}
return tmp;
}
int main(void)
{
iMat *a = alloc_matrix(3, 4);
if (!a)
exit(EXIT_FAILURE);
fill_matrix_iota(a, 1);
print_matrix(a, 3);
iMat *b = make_transposed(a);
if (!b)
{
free(a);
exit(EXIT_FAILURE);
}
putchar('\n');
print_matrix(b, 3);
free(b);
free(a);
return EXIT_SUCCESS;
}

Removing duplicate elements in array without sorting - wrong output

I have been trying to write a function to remove duplicate elements in an array of ints without sorting it.
For that task, I created a function named removeDuplicateElements, which gets an array and its string, and returns a new dynamically allocated array, which is a copy of the original array with removal of all duplicates elements. This function also returns by reference the size of the new array.
I also used in my code functions which build a dynamic array and print it.
Here is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
void printArray(int *arr, int size);
int *buildArray(int size);
int *removeDuplicateElements(int *arr, int size, int *newSize);
void main() {
int size,newSize;
int *arr;
int *newArr;
printf("please enter a number for the size of array: ");
scanf("%d", &size);
printf("\nenter %d numbers: ", size);
arr = buildArray(size);
printf("\nthe array after removing the duplicate elements is: ");
newArr = removeDuplicateElements(arr, size, &newSize);
printArray(newArr, newSize);
free(newArr);
free(arr);
}
/* this function removes all duplicate elements in a given array */
int *removeDuplicateElements(int *arr, int size, int *newSize) {
int *newArr;
int count = size, i, j;
/* finding the new size of the original array with removal its duplicate elements */
for (i = 1; i < size; i++) {
for (j = 0; j < size; j++)
if (arr[i] == arr[j] && i != j) {
count--;
break;
}
}
newArr = (int*)malloc(count * sizeof(int)); /* dynamically allocating the new array */
count = 1;
newArr[0] = arr[0];
/*adding the elements in the new array without changing the order*/
for (i = 1; i < size; i++) {
for (j = 0; j < size; j++) {
if (arr[i] == arr[j] && i != j) {
break;
}
if (j == size - 1) {
newArr[count] = arr[i];
count++;
}
}
}
*newSize = count; /* updating the size of the new array */
return newArr; /* returning the address of new array */
}
void printArray(int *arr, int size) {
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
int *buildArray(int size) {
int i;
int *arr = (int*)malloc(size * sizeof(int));
if (!arr) {
printf("ERROR! Not enough memory!\n");
exit(1);
}
for (i = 0; i < size; i++)
scanf("%d", &arr[i]);
return arr;
}
I get a wrong output for that code, and I dont understand why
For instance, for the following array with size=5 :1 1 3 1 3
I get the wrong output 1, whereas the expected outout is
1 3.
Any help would be appreciated.
You're firstly calculating the size of the new array incorrectly. For your example input, when you're looking at the first 3, it scans the whole array to see how many 3's there are and finds there are 2 and concludes it's a duplicate. It then does the exact same thing for the 2nd 3. So you end up with the size of the new array as 1.
Instead of scanning the whole array, you only want to scan the array for the elements preceding the one you're checking. So something like this.
for(i=1;i<size;i++)
{
for (j = 0; j < i; j++)
if (arr[i] == arr[j])
{
count--;
break;
}
}
And for the code that fills the new array has the same problem
for(i=1;i<size;i++)
{
for (j = 0; j < i; j++)
if (arr[i] == arr[j])
{
break;
}
if(j==i)
{
newArr[count++]=arr[i];
}
}
There is an alternative way of doing it, ofcourse it involves modifying the original array but this is just an alternative. Basically it involves crossing off the duplicate element by replacing it with a maximum value like 0xFFFF.
int* removeDuplicateElements(int *arr, int size, int *newSize)
{
int *newArr;
int count = size, i, j;
int index = 0;
/*finding the new size of the original array with removal its duplicate elements*/
for(i=0;i<size;i++)
{
for (j = i+1; j < size; j++)
if (arr[i] == arr[j] && arr[i] != 0xFFFF)
{
count--;
arr[j] = 0xFFFF;
}
}
printf("Size is %d \n", count);
newArr = (int*)malloc(count * sizeof(int)); /*dynamically allocating the new array*/
for(i=0;i<size;i++)
{
if(arr[i] != 0xFFFF)
newArr[index++] = arr[i];
}
*newSize = count; /*updating the size of the new array*/
return newArr; /*returning the address of new array*/
}

Resources