As an exercise, I am trying to build a 2 dimensional array of random integers. I want to assign the random numbers by iterating through the array using pointer arithmetic.
I think I'm having trouble with the following For loop, which I lifted from p268 of C Programming by King.
int *p;
for (p = &a[0][0]; p <= &a[NUM_ROWS-1] [NUM_COLUMNS - 1]; p++)
I'm trying to use a similar loop in a program of my own but the program doesn't seem to assign any values.
#include <stdio.h>
#include <stdlib.h>
int ** make_array(int in_size );
void read_array( int ** a, int n);
int main(void){
int size;
int **p;
size = 5;
p = make_array( size );
read_array( p, size );
return 0;
}
int ** make_array( int in_size ) {
int i, *p, **a;
srand ((unsigned)time(NULL));
a = malloc(in_size * sizeof(int*));
for (i = 0; i < in_size ; i++) {
a[i] = malloc( in_size * sizeof(int));
}
for (p = &a[0][0]; p <= &a[in_size -1 ][in_size - 1]; p++) {
*p = rand() % 10;
}
return a;
}
void read_array( int **a, int n ) {
int i, *p;
for (p = &a[0][0] ; p <= &a[n - 1][n - 1]; p++)
printf("%d ", *p );
}
Now I know I could loop through it pretty easily with nested for loops, this seemed like an elegant way to loop through an array. Any idea what I'm doing wrong?
int *p;
for (p = &a[0][0]; p <= &a[NUM_ROWS-1] [NUM_COLUMNS - 1]; p++)
is valid in two cases:
(1) when 'a' is defined as two dimensional array e.g. int a[NUM_ROWS][NUM_COLUMNS]. In this case, memory chunk is contiguous and hence, it is valid to use pointer variable to iterate through the 2D array elements.
(2) Modify your make_array() function as follows to allocate contiguous chunk of memory to use the above mentioned method.
int ** make_array( int in_size )
{
int i, *p, **a;
int *big_chunk;
srand ((unsigned)time(NULL));
a = (int **)malloc(in_size * sizeof(int*));
big_chunk = (int *)malloc(in_size * in_size * sizeof(int)); <-- change done here
for (i = 0; i < in_size ; i++)
{
a[i] = big_chunk + i * insize; <-- change done here
}
/* Other code */
}
In your original make_array() function, malloc() does not guarantee contiguous memory chunks in successive iteration of malloc() call. Hence, using pointer to iterate through the 2D array elements will not be correct. e.g. once 'p' reaches a[0][in_size-1] then p = &a[0][in_size] will be different than a[1] -> malloc address for 2nd row.
As you have learned, in C, there are no 2D arrays. There are only ways to simulate indexing for 2D arrays. These fall into two categories, (1) creating an array of pointers to arrays, and (2) creating a normal sequential array and using index arithmetic to reference elements in 2D manner. In each case the arithmetic can be thought of in terms of total number of elements in your array (or size of the array) and the number of columns you want to simulate (or the stride) of the array. Knowing the size and stride of the array, with careful indexing, you can use your C - 1D array as a 2D array. To help finish lifting any issues that remain concerning the two types and the use of pointers and indexes, consider the following:
Array of Pointers to type
First, when you are using an array of pointers to type (e.g. int **array) you allocate ROWS number of pointers to COLS sized arrays of type (essentially you have ROWS number of COLS sized arrays.) Then by dereference, you can index your elements as a 2D array (e.g. array[0][x] where 0 <= x < COLS reads all in the array pointed to by the first pointer, array[1][x], the second pointer, and so on...).
To allocate your array of pointers to type, you allocate ROWS number of pointers (where ROWS are equivalent to the size/stride):
int **array = NULL;
...
array = xcalloc (size/stride, sizeof *array);
(note: xcalloc is just a function using calloc with error checking to validate allocation)
After allocating your ROWS number of pointers, you allocate a separate column-array of COLS (or stride) number of elements for each original pointer.
for (i = 0; i < size/stride; i++)
array[i] = xcalloc (stride, sizeof **array);
After you allocate your array of pointers to type, you will use two loops to fill/manipulate your data in your array:
for (i = 0; i < size/stride; i++)
for (j = 0; j < stride; j++)
array[i][j] = rand() % 1000;
You can access any individual member with simple array[i][j] syntax. Remember you simply consider size/stride as your ROWS and stride as your COLS, so if you are computing the value of ROWS and COLS you could write the above as:
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
array[i][j] = rand() % 1000;
Linear Array Treated as 2D Array
Since you are using a traditional sequential 1D array to hold you data in this case, Declaring and allocating the array is trivial:
int *array = NULL;
...
array = xcalloc (size, sizeof *array);
note: to access the elements of the array in a simulated 2D fashion, you must store the values in the array using the same logic you will use to access the values, which from the loop standpoint will be exactly the same as you did in the pointers to arrays case above. The only differece will be the computation of the index:
for (i = 0; i < size/stride; i++)
for (j = 0; j < stride; j++)
array[i * stride + j] = rand() % 1000;
Here, a closer look at just how you are simulating array[i][j] access is needed. NOTE: the index for the array:
array[i * stride + j] = rand() % 1000;
When you have a linear 1D array of elements, the indexing that allows you to treat and access values in 2D fashion is given by array[i * stride + j] where i and j represent ROWS and COLS.
Putting all this into a couple of examples will show you just how all the pieces fit together:
Example - Array of Pointers to type
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void *xcalloc (size_t n, size_t s);
int main (int argc, char **argv) {
int **array = NULL;
int size = argc > 1 ? (int)strtol(argv[1], NULL, 10) : 36;
int stride = argc > 2 ? (int)strtol(argv[2], NULL, 10) : 6;
int i,j;
/* test valid size/stride */
if (size < stride || size % stride) {
fprintf (stderr, "error: invalid stride '%d' for %d element array.\n",
stride, size);
return 1;
}
srand (time(NULL)); /* initialize seed */
/* alloc array of pointers to array of integers in memory */
array = xcalloc (size/stride, sizeof *array);
/* allocate arrays of integers */
for (i = 0; i < size/stride; i++)
array[i] = xcalloc (stride, sizeof **array);
/* fill with random values */
for (i = 0; i < size/stride; i++)
for (j = 0; j < stride; j++)
array[i][j] = rand() % 1000;
/* printing in simulated 2D format */
printf ("\n printing (%d x %d) array\n\n",
size/stride, stride);
for (i = 0; i < size/stride; i++) {
for (j = 0; j < stride; j++)
printf (" %4d", array[i][j]);
putchar ('\n');
}
/* print a particular element array[1][2] */
if (stride > 1)
printf ("\n array[1][1] in (%d x %d) array : %d\n\n",
size/stride, stride, array[1][1]);
/* free allocated memory */
for (i = 0; i < size/stride; i++)
free (array[i]);
free (array);
return 0;
}
/** xcalloc allocates memory using calloc and validates the return.
* xcalloc allocates memory and reports an error if the value is
* null, returning a memory address only if the value is nonzero
* freeing the caller of validating within the body of code.
*/
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0)
{
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
return memptr;
}
Example Use/Output
$ ./bin/array_stride_2d 12 2
printing (6 x 2) array
535 68
45 815
348 480
417 151
443 789
267 738
array[1][1] in (6 x 2) array : 815
$ ./bin/array_stride_2d 12 3
printing (4 x 3) array
841 195 147
870 18 892
624 516 820
250 769 532
array[1][1] in (4 x 3) array : 18
$ ./bin/array_stride_2d 12 4
printing (3 x 4) array
116 275 740 510
625 122 386 623
624 879 970 396
array[1][1] in (3 x 4) array : 122
$ ./bin/array_stride_2d 12 6
printing (2 x 6) array
543 631 562 504 307 940
932 75 225 662 181 990
array[1][1] in (2 x 6) array : 75
Example - Linear Array Treated as 2D Array
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void *xcalloc (size_t n, size_t s);
int main (int argc, char **argv) {
int *array = NULL;
int size = argc > 1 ? (int)strtol(argv[1], NULL, 10) : 36;
int stride = argc > 2 ? (int)strtol(argv[2], NULL, 10) : 6;
int i,j;
/* test valid size/stride */
if (size < stride || size % stride) {
fprintf (stderr, "error: invalid stride '%d' for %d element array.\n",
stride, size);
return 1;
}
srand (time(NULL)); /* initialize seed */
/* alloc array of size sequential in memory */
array = xcalloc (size, sizeof *array);
/* fill with random values */
for (i = 0; i < size/stride; i++)
for (j = 0; j < stride; j++)
array[i * stride + j] = rand() % 1000;
/* printing in simulated 2D format */
printf ("\n printing (%d x %d) array\n\n",
size/stride, stride);
for (i = 0; i < size/stride; i++) {
for (j = 0; j < stride; j++)
printf (" %4d", array[i * stride + j]);
putchar ('\n');
}
/* print a particular element array[1][2] */
if (stride > 1)
printf ("\n array[1][1] in (%d x %d) array : %d\n\n",
size/stride, stride, array[1 * stride + 1]);
free (array);
return 0;
}
/** xcalloc allocates memory using calloc and validates the return.
* xcalloc allocates memory and reports an error if the value is
* null, returning a memory address only if the value is nonzero
* freeing the caller of validating within the body of code.
*/
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0)
{
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
return memptr;
}
Use/Output
$ ./bin/array_stride_1d 12 2
printing (6 x 2) array
220 155
755 51
427 270
691 597
982 995
4 444
array[1][1] in (6 x 2) array : 51
$ ./bin/array_stride_1d 12 3
printing (4 x 3) array
990 837 473
153 10 337
139 940 444
768 625 457
array[1][1] in (4 x 3) array : 10
$ ./bin/array_stride_1d 12 4
printing (3 x 4) array
617 943 444 396
38 357 103 441
646 416 40 586
array[1][1] in (3 x 4) array : 357
$ ./bin/array_stride_1d 12 6
printing (2 x 6) array
364 61 373 723 994 849
793 332 913 991 999 373
array[1][1] in (2 x 6) array : 332
Memory Error Check
$ valgrind ./bin/array_stride_1d 12 6
==21560== Memcheck, a memory error detector
==21560== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==21560== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==21560== Command: ./bin/array_stride_1d 12 6
==21560==
printing (2 x 6) array
359 841 728 356 563 487
626 58 823 270 860 896
array[1][1] in (2 x 6) array : 58
==21560==
==21560== HEAP SUMMARY:
==21560== in use at exit: 0 bytes in 0 blocks
==21560== total heap usage: 1 allocs, 1 frees, 48 bytes allocated
==21560==
==21560== All heap blocks were freed -- no leaks are possible
==21560==
==21560== For counts of detected and suppressed errors, rerun with: -v
==21560== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Hopefully this has been helpful for your learning that there are basically two schemes for treating arrays as 2D arrays in C. You can even be more creative and create dimensional arrays well beyond 2D, just note the index computation quickly become a bit more involved. Even at the 2D level, you can get quite a bit more out of these methods, like row and column vectors, upper/lower matrices, matrix arithmetic, etc. Let me know if you have any questions.
Related
Just having an issue here with SIGSEV.
The role of this program is to build a matrix of n * n, which is the first command line argument, and then furthermore fills out the matrix from integers sourced from command line arguments.
The output then consists of the main diagonal of this matrix summed together
Example:
1 2 3
4 5 6
7 8 9
1 + 5 + 9 = 15
Sample input:
./file-name 3 1 2 3 4 5 6 7 8 9
Sample output:
15
However I'm very confused, as it works with all matrices under size 5, but once I go over, I get this address boundary error. Anyone know why?
Error:
fish: Job 1, './file-name 5...' terminated by signal SIGSEV (Address boundary error)
Code:
/* Description: Takes integer arguments from command line
* First argument signafies matrix's size, (n * n)
* Remaining arguments fill matrix.
* Then the main diagonal of the matrix is summed
* and outputted
* Input: Multiple integers as cmd line arguments, first signifies
* matrix size (n * n)
* Output: A single integer, the sum of the diagonals
*
*/
// Includes
#include <stdio.h>
#include <stdlib.h>
// Function Prototypes
void fill_matrix(int **matrix, int n, char **argv);
int sum_diag_matrix(int **matrix, int n);
// Main Function
int main(int argc, char **argv) {
// Take cmd line args
int n = atoi(argv[1]);
// Assign and allocate double pointer enough memory for matrix of size n
int **matrix = (int **) malloc(n * sizeof(int));
// Assign pointers inside double pointer of matrix enough memory for vector of size n
for ( int i = 0; i < n; ++i ) {
*(matrix + i) = (int *) malloc(n * sizeof(int));
}
// Call fill_matrix function to fill our matrix from cmd line args
fill_matrix(matrix, n, argv);
// Assign total to the return of our sum_diag_matrix function
int total = sum_diag_matrix(matrix, n);
// Output our total
printf("%i\n", total);
// Return 0 to signal script running correctly
return 0;
}
// Fill matrix function fills the matrix of passed size n from passed array
void fill_matrix(int **matrix, int n, char **arr) {
// Initialize element integer to keep track of what element we're on
int element = 0;
// Nested loop iterates over matrix, filling out the values from the given array
for ( int i = 0; i < n; ++i) {
for ( int j = 0; j < n; ++j) {
*(*(matrix + i) + j) = atoi(arr[element + 2]);
printf("%i\n", *(*(matrix + i) + j));
element++;
}
}
// Return nothing for void
return;
}
// Sum diag matrix function sums the main diagonal of the matrix passed of passed size n
int sum_diag_matrix(int **matrix, int n) {
// Initialize total to keep track of sum
int total = 0;
// Iterate over diagonal elements of matrix
for ( int i = 0; i < n; ++i) {
total += *(*(matrix + i) + i);
}
// Return total sum
return total;
}
I'm new to pointers and such, so I'm trying to apply them everywhere, so potentially it could be that? Regardless I'm not too sure and I'm slightly stumped.
Any help would be appreciated!
-fsanitize=address is usually a great tool in debugging these kinds of problems. Even with the input you claim works, it spots the problem:
==1==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000018 at pc 0x000000401284 bp 0x7fff8ff3b540 sp 0x7fff8ff3b538
WRITE of size 8 at 0x602000000018 thread T0
#0 0x401283 in main /app/example.c:28
#1 0x7fd9788e9082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
#2 0x40111d in _start (/app/output.s+0x40111d)
0x60200000001c is located 0 bytes to the right of 12-byte region [0x602000000010,0x60200000001c)
allocated by thread T0 here:
#0 0x7fd978b72bbf in malloc (/opt/compiler-explorer/gcc-12.2.0/lib64/libasan.so.8+0xbbbbf)
#1 0x40122c in main /app/example.c:25
#2 0x7fd9788e9082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
SUMMARY: AddressSanitizer: heap-buffer-overflow /app/example.c:28 in main
Shadow bytes around the buggy address:
It says that at line 28, we're exceeding the memory allocated at line 25.
int **matrix = (int **) malloc(n * sizeof(int)); // Line 25
// Assign pointers inside double pointer of matrix enough memory for vector of size n
for ( int i = 0; i < n; ++i ) {
*(matrix + i) = (int *) malloc(n * sizeof(int)); // Line 28
}
Immediately, we see you use sizeof(int) and assign to int **, which is wrong. Fixed:
int **matrix = (int **) malloc(n * sizeof(int *));
(Also, you leak the memory on exit, which isn't a problem in systems with virtual memory like your desktop PC.)
Using the following macro would would also have caught the problem.
#define MALLOC(t, n) ( (t*)malloc(sizeof(t) * n) )
#define REALLOC(p, t, n) ( (t*)realloc(p, sizeof(t) * n) )
int **matrix = MALLOC(int*, n); // Warns if `int` is used instead of `int*`.
for ( int i = 0; i < n; ++i ) {
matrix[i] = MALLOC(int, n);
}
(edit)
can someone help me to understand why the allocation of a dynamic array is based on two pointers ( this code works without any problem)
int main(int argc, char** argv) {
int i;
int n=3;
int* *t1;
*t1 = (int*) malloc(n*sizeof(int));
for (i = 0 ; i <n ; i++)
{
scanf("%d",(*t1+i));
}
for ( i=0; i<n; i++)
{
printf("%d",*(*t1+i));
}
while the only writing that i know is
int* t;
t = (int*) malloc(n*sizeof(int));
so what is the interest of using *t instead of t.
Thank you.
Your question is unclear because you haven't specified what it is you are attempting to achieve. Later in a comment, you indicate you need a simple 1D array, but that isn't included in your question. Let's cover both case plus the case of using a pointer-to-array and make sure you understand the basics.
To understand dynamic allocation, you must understand there are no arrays involved (the exception being allocating for a pointer-to-array of fixed size).
Otherwise, dynamic allocation encompasses allocation of a block of memory of a given size and assignment of the starting address for that new block of memory to a pointer. In C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc? (in C++ it is required)
Allocating Memory For Integers
When you want to allocate a block of memory for the storage of integers, you simply allocate a block big enough to hold the number of integers you want to store, and assign the starting address for the new block of memory to a pointer. Let's take it step-by-step:
int *t;
declares a pointer-to int to which the beginning address for an allocated block of memory can be assigned.
int n = 100;
t = malloc (n * sizeof *t);
malloc allocates a new block of memory of n * sizeof *t bytes which is sufficient in size to hold n integer values and the beginning address for that block is assigned to the pointer t. Using the dereferenced sizeof *t to set the type-size ensures your type-size is correct. (t being a pointer-to int, when you dereference t (e.g. *t), your type is plain-old int, so sizeof *t is equivalent to sizeof (int))
It may not seem like it matters now (and for trivial types it doesn't make a lot of difference), but as the type of objects you deal with grow in complexity and levels of pointer indirection, mistakenly setting an incorrect type-size becomes a common problem with dealing with allocated nested structures, etc.. That is why simply using the dereferenced pointer to set type-size is recommended.
Let's take a simple example that users a pointer int *t_1D; to emphasize it is single linear allocation that can be indexed as a simple 1D array:
#define NUMINT 50 /* number of integers for t_1D */
...
int main (void) {
int *t_1D = NULL; /* pointer to int */
t_1D = malloc (NUMINT * sizeof *t_1D); /* allocate storage for NUMINT int */
if (t_1D == NULL) { /* validate EVERY allocation, handle error */
perror ("malloc-t_1D");
return 1;
}
for (int i = 0; i < NUMINT; i++)
t_1D[i] = i + 1; /* assign a value to each integer */
puts ("\nvalues in t_1D (with \\n every 5th integer)\n");
for (int i = 0; i < NUMINT; i++) { /* loop over each value */
if (i && i % ARRSZ == 0) /* simple mod test to output newline */
putchar ('\n');
printf (" %3d", t_1D[i]); /* output value at address */
}
puts ("\n");
free (t_1D); /* don't forget to free what you allocate */
Above when you are done with that block of memory, you must free() the block to prevent a memory leak. Understand for trivial examples where you allocate in main() the memory is freed on program exit. However, it is important to develop good habits early as you will commonly be allocating in a function all and if the memory is not freed before your function returns (or later freed in the caller before it returns) you lose the pointer to the block and it cannot be free -- resulting in a memory leak.
Simulating a 2D Array with a Pointer-To-Pointer
If you use a pointer-to-pointer (e.g. int **t;) as your pointer, your allocation is a two-step process. First you allocate a block of memory to hold some number of pointers (which you generally think of as the number of rows for the object you are allocating).
Then in a second set of allocations, you will allocate a block of memory to hold the number of integers-per-row you wish to store per-row (generally thought of as the col (column) number of integers) and assign the starting address for each allocated block to one of your allocated pointers -- in sequence.
The result is a data structure where you allocate 1-block of memory to hold row number pointers and and row blocks of memory to hold col number of integers. Then you can access each of the memory locations just as you would access values in a 2D array.
However, note since there are multiple allocations required to create an object from a pointer-to-pointer, there will be multiple calls to free required to free the memory allocated to the object.
Now let's look at how that can be used. Below, we will use int **t_2D; as the variable name to indicate we are storing an object that we can index as a 2D array:
#define ARRSZ 5 /* number of integers per-row for t_2D and t_PTA */
...
int **t_2D = NULL; /* pointer to pointer to int */
...
/* a pointer to pointer (allocate pointers, then ints for each pointer) */
t_2D = malloc (NUMINT/ARRSZ * sizeof *t_2D); /* allocate 10 pointers */
if (!t_2D) { /* validate EVERY allocation */
perror ("malloc-t_2D");
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++)
/* allocate/validate storage for 5 int assign start address to each ptr */
if (!(t_2D[i] = malloc (ARRSZ * sizeof *t_2D[i]))) { /* on failure */
while (i--) /* free previously allocated block for int */
free (t_2D[i]);
free (t_2D); /* free pointers */
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
for (int j = 0; j < ARRSZ; j++) /* loop over integer storage */
t_2D[i][j] = (i * ARRSZ) + j + 1; /* assign value for each int */
puts ("values in t_2D output by row x col:\n");
for (int i = 0; i < NUMINT/ARRSZ; i++) {
for (int j = 0; j < ARRSZ; j++)
printf (" %3d", t_2D[i][j]); /* output each integer */
putchar ('\n');
}
putchar ('\n');
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
free (t_2D[i]); /* free integers */
free (t_2D); /* free pointers */
Note the loop at the end that loops over each pointer freeing the storage for integers before calling free to free the block of memory holding the pointers themselves.
A Pointer-To-Array -- Single Allocation, Single-Free, 2D Indexing
There is one other common allocation that you will run into that warrants explanation. You can use a pointer-to-array of fixed length (e.g. int (*t_PTA)[CONST];) and then allocate storage for some number of the fixed arrays in a single call and be able to address the object as a 2D array just as was done above with t_2D. Since there is only a single-allocation required, there is only a single-free needed to free the memory associated with the object.
(note: do not confuse a poitner-to-array (e.g. int (*p)[CONST]) with an array-of-pointers (e.g. int *p[CONST]), they are two distinct types)
To allocate, use and free an object create from a pointer-to-array, you can do the following:
/* a pointer to array -- single allocation, single-free, 2D indexing */
int (*t_PTA)[ARRSZ] = NULL; /* pointer to array of int[ARRSZ] */
t_PTA = malloc (NUMINT/ARRSZ * sizeof *t_PTA); /* storage for 50 integers */
if (!t_PTA) { /* validate EVERY allocation */
perror ("malloc-t_2D");
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
for (int j = 0; j < ARRSZ; j++) /* loop over integer storage */
t_PTA[i][j] = (i * ARRSZ) + j + 1; /* assign value for each int */
puts ("values in t_PTA output by row x col:\n");
for (int i = 0; i < NUMINT/ARRSZ; i++) {
for (int j = 0; j < ARRSZ; j++)
printf (" %3d", t_PTA[i][j]); /* output each integer */
putchar ('\n');
}
putchar ('\n');
free (t_PTA);
(note: the convenience of the single free (t_PTA); used to free all memory associated with the object.)
Now let's put it altogether in a workable example:
#include <stdio.h>
#include <stdlib.h>
#define ARRSZ 5 /* number of integers per-row for t_2D and t_PTA */
#define NUMINT 50 /* number of integers for t_1D */
int main (void) {
int *t_1D = NULL, /* pointer to int */
**t_2D = NULL, /* pointer to pointer to int */
(*t_PTA)[ARRSZ] = NULL; /* pointer to array of int[ARRSZ] */
/* handling simple storage for integers */
t_1D = malloc (NUMINT * sizeof *t_1D); /* allocate storage for NUMINT int */
if (t_1D == NULL) { /* validate EVERY allocation, handle error */
perror ("malloc-t_1D");
return 1;
}
for (int i = 0; i < NUMINT; i++)
t_1D[i] = i + 1; /* assign a value to each integer */
puts ("\nvalues in t_1D (with \\n every 5th integer)\n");
for (int i = 0; i < NUMINT; i++) { /* loop over each value */
if (i && i % ARRSZ == 0) /* simple mod test to output newline */
putchar ('\n');
printf (" %3d", t_1D[i]); /* output value at address */
}
puts ("\n");
free (t_1D); /* don't forget to free what you allocate */
/* a pointer to pointer (allocate pointers, then ints for each pointer) */
t_2D = malloc (NUMINT/ARRSZ * sizeof *t_2D); /* allocate 10 pointers */
if (!t_2D) { /* validate EVERY allocation */
perror ("malloc-t_2D");
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++)
/* allocate/validate storage for 5 int assign start address to each ptr */
if (!(t_2D[i] = malloc (ARRSZ * sizeof *t_2D[i]))) { /* on failure */
while (i--) /* free previously allocated block for int */
free (t_2D[i]);
free (t_2D); /* free pointers */
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
for (int j = 0; j < ARRSZ; j++) /* loop over integer storage */
t_2D[i][j] = (i * ARRSZ) + j + 1; /* assign value for each int */
puts ("values in t_2D output by row x col:\n");
for (int i = 0; i < NUMINT/ARRSZ; i++) {
for (int j = 0; j < ARRSZ; j++)
printf (" %3d", t_2D[i][j]); /* output each integer */
putchar ('\n');
}
putchar ('\n');
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
free (t_2D[i]); /* free integers */
free (t_2D); /* free pointers */
/* a pointer to array -- single allocation, single-free, 2D indexing */
t_PTA = malloc (NUMINT/ARRSZ * sizeof *t_PTA); /* storage for 50 integers */
if (!t_PTA) { /* validate EVERY allocation */
perror ("malloc-t_2D");
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
for (int j = 0; j < ARRSZ; j++) /* loop over integer storage */
t_PTA[i][j] = (i * ARRSZ) + j + 1; /* assign value for each int */
puts ("values in t_PTA output by row x col:\n");
for (int i = 0; i < NUMINT/ARRSZ; i++) {
for (int j = 0; j < ARRSZ; j++)
printf (" %3d", t_PTA[i][j]); /* output each integer */
putchar ('\n');
}
putchar ('\n');
free (t_PTA);
}
Where you compile and run to receive the following:
Example Use/Output
$ ./bin/dynalloc_1_2_pta
values in t_1D (with \n every 5th integer)
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
values in t_2D output by row x col:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
values in t_PTA output by row x col:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
Memory Use/Error Check
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/dynalloc_1_2_pta
==10642== Memcheck, a memory error detector
==10642== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10642== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10642== Command: ./bin/dynalloc_1_2_pta
==10642==
values in t_1D (with \n every 5th integer)
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
values in t_2D output by row x col:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
values in t_PTA output by row x col:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
==10642==
==10642== HEAP SUMMARY:
==10642== in use at exit: 0 bytes in 0 blocks
==10642== total heap usage: 14 allocs, 14 frees, 1,704 bytes allocated
==10642==
==10642== All heap blocks were freed -- no leaks are possible
==10642==
==10642== For counts of detected and suppressed errors, rerun with: -v
==10642== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
It is a lot to digest at one sitting, but take it piece-by-piece and dynamic allocation will start to make sense. Let me know if you have furher questions.
In the first case t is a pointer to int*. And the right way would be for allocation:
int **t;
t = (int**) malloc(n*sizeof(int*));
So in other word: it is an array of int*, which is the dynamically allocated version of int* t[n].
And this is different, than the second case, where t is a pointer to int type, basically t is an array of int in this case, which is like the dynamically allocated version of int t[n].
Please clarify. However, the first version is incorrect. If you want to allocate a array of pointers to arrays, you should be doing:
int **t;
t=(int**) malloc(n*sizeof(int*));
To allocate the array of pointers to each individual row, and then allocating the rows:
for (int i=0; i<n; ++i){
t[i] = (int*) malloc(n*sizeof(int));
}
*t won't be valid in your first snippet, since it can be accessed. You would have to allocate **t first.
An int** would be is used when you want to allocate a block of int* objects. In your example, that is not what you have done or indeed want.
In fact you have not allocated or assigned anything to t1, making the allocation to *t1 (i.e. t1[0]) invalid because t1 is itself unknown.
If for example you wanted an allocated array of pointers to multiple allocated int arrays, then int** would be the appropriate data type for the array of pointers to arrays of int:
// Allocate n arrays of m ints
int** t = malloc( sizeof(int*) * n ) ;
for( int i = 0; i < n; i++ )
{
t[i] = malloc( sizeof(int) * m ) ;
}
Then for example t[2][3] refers to the fourth element in the third block of of int.
It is not an issue of syntax; they are not different forms of the same thing; they are semantically different, and in the context of your example int** is inappropriate and semantically incorrect.
It might be a stupid question, but I wonder if there is a efficient way to do this.
The situation:
int* array = malloc(n * m * sizeof(int));
//want to convert array into M[n][m]
what I am doing now:
int** M = malloc(n * sizeof(int*));
for(int i = 0; i < n; i++, array += m)
M[i] = array;
I don't think the conversion should be this complex. Is there any simple syntax C provided? Can I declare an extern M[n][m] then set its address to the array?
(error handling and memory management in the sample is omitted for simplicity. Just think it as a part of some function.)
After:
int* array = malloc(n * m * sizeof(int));
you can do:
int (*M)[m] = (int(*)[m])array;
and then use M[1][2] for example.
You could have done that in the first place too :
int (*M)[m] = malloc( n * sizeof *M );
The tricky part is declaring the variable to hold the pointer to the allocated array; the rest is straight-forward — assuming you have a C99 or later compiler.
#include <stdio.h>
#include <stdlib.h>
static void print_2dvla(int rows, int cols, int data[rows][cols])
{
for (int i = 0; i < rows; i++)
{
printf("%2d: ", i);
for (int j = 0; j < cols; j++)
printf(" %4d", data[i][j]);
putchar('\n');
}
}
int main(void)
{
int m = 10;
int n = 12;
int (*M)[m] = malloc(n * m * sizeof(M[0][0]));
if (M == NULL)
{
fprintf(stderr, "Failed to allocate %zu bytes memory\n", n * m * sizeof(M[0][0]));
exit(EXIT_FAILURE);
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
M[i][j] = (i + 1) * 100 + (j + 1);
}
print_2dvla(n, m, M);
free(M);
return 0;
}
Example output:
0: 101 102 103 104 105 106 107 108 109 110
1: 201 202 203 204 205 206 207 208 209 210
2: 301 302 303 304 305 306 307 308 309 310
3: 401 402 403 404 405 406 407 408 409 410
4: 501 502 503 504 505 506 507 508 509 510
5: 601 602 603 604 605 606 607 608 609 610
6: 701 702 703 704 705 706 707 708 709 710
7: 801 802 803 804 805 806 807 808 809 810
8: 901 902 903 904 905 906 907 908 909 910
9: 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
10: 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
11: 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
The key line is:
int (*M)[m] = malloc(n * m * sizeof(M[0][0]));
This says that M is a pointer to an array of int arrays each of which has the dimension m. The rest of the code simply uses that array with the usual 2-subscript notation — M[i][j] etc. It can be passed to functions. I've not shown it here, but it is trivial to put the initialization code into a function too, and then have several different sizes of matrix in a single function.
You can't declare global arrays in C without giving them a specific numerical size. This is because global variables are static and the compiler can't allocate a variable amount of memory for a global array.
In C you've got to remember that an array is actually just a pointer. When you're asking for int *array = malloc(n * sizeof(int)) what you're telling the compiler is that you need n lots of 4 byte blocks of int type reserved side by side in memory, where the value of array is actually a pointer to the first 4 byte block.
When you are accessing elements of an array you are actually doing pointer arithmetic and dereferencing the pointer, but this is hidden in the array[i] syntax. So, when array has int type, array[2] translates as go to the location given by the array pointer (i.e. the head) now move 2 * 4 bytes along in memory and dereference the pointer to access the integer stored there.
So when you're creating a 2-d array as you've discussed, there really isn't a better way of doing it. Make sure you have a firm grip on what it actually is you're getting from the compiler. Pointers are (on 64-bit machines anyway) 8 bytes and ints are 4 bytes. So when you call int **M = malloc(sizeof(int*) * m the compiler allocates you m blocks of width 8 bytes each, all of which have type int*.
From other programming languages it seems very over the top having to declare a pointer reference to a block of pointers, but getting passed the higher level idea of an array and considering them as a collection of pointers will really help you in the long run. When you need to pass these data types between functions you need to be able to have a firm idea of what you are actually manipulating; a pointer, a value, a pointer to a pointer? It will help you a lot in debugging code these ideas, as it is very easy to try and perform computations on pointers rather than values.
3 Useful Tips:
calloc(n, sizeof(int)) might be a better fit than calling malloc because calloc automatically initialises your entries to zero whereas malloc doesn't.
when calling calloc/malloc, you want to check that your dynamic memory allocation has been successful; if it isn't successful, then malloc will return NULL.
A good rule of thumb is that every time you call malloc you want to call free once you're done with the memory. This can help to prevent memory leaks.
Use an array of pointers.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n = 3, m = 4, i, j, count=0;
int *array[n];
for(i=0; i<n; i++)
array[i] = (int *)malloc(m * sizeof(int));
if( array[i] == NULL)
{
perror("Unable to allocate array");
exit(1);
}
// going to add number to your 2d array.
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
array[i][j] = ++count;
for (i=0; i < n; i++)
for (j=0; j < m; j++)
printf("%d ", array[i][j]);
// free memory
for(i=0; i<n; i++)
free(array[i]);
}
I'm trying to allocate a dynamic two dimensional array in C using the following code:
int **allocateMatrix(int rows, int columns) {
int i = 0;
int **p = NULL;
p = (int**) calloc(rows, sizeof(int*));
for(; i < rows; i++) {
p[i] = (int*) calloc(columns, sizeof(int));
}
return p;
}
The code works but actually it's allocating double the memory it needs.
For example, if i pass the arguments rows = 2 and columns = 3 i get an array that's 2 rows by 8 columns.
Am i doing something wrong?
Thank you.
Edit:
The content of the matrix (which is loaded from a file) is:
-1 5 0
4 0 2
And this is what the memory looks like after the allocation and the assignment of the values:
It is allocating the correct amount of memory, but it allocating more memory than a simple 2D array would use because what you've created is not a simple 2D array.
Assuming a 32-bit system (so sizeof(int) == sizeof(int *), and sizeof(int) == 4), then:
a simple 2D array needs 2 x 3 integers = 6 x 4 = 24 bytes
a dynamic 2D array needs 2 pointers plus 2 x 3 integers = 8 x 4 = 32 bytes
That's before there's any accounting for overhead in the memory allocations. So not twice, but more.
The advantages of what you're doing is you can write p[i][j] and get the right result. If you simulated a simple 2D array, you'd have to do the subscript calculation yourself: p[i*3+j] or use (*p)[i][j], depending on exactly how you defined the pointer p.
AFAICT, your screenshot of the array having 20 elements is because.. you told Netbeans (with that #20) to display 20 elements starting at a memory location (**(matrix)). What happens when you change it to be '#3'?
However, based on this comment:
Actually it's more than the double. I know because when i try to assign values they're not contiguous in memory but they are shifted (i can see it from the watches in the debug window in netbeans).
When you allocate memory, you're calling a library that figures out how to request from the operating system what space it may use and then of what space it's been given by the operating system what it hasn't used yet.
You're making assumptions about how the allocator works that may or may not be correct. It's possible for it to allocate space efficiently in a way you don't expect, especially due to virtual paging mechanisms. In short, contiguous calls to the allocator are not guarenteed to allocate contiguous memory, and rarely will.
If you want to use an array-of-pointers for a double array style structure and absolutely must have contiguous addresses in a more "expected" way, you can try this:
int **allocateMatrix(int rows, int columns) {
int i = 0;
int **p = NULL;
int *d = NULL;
p = (int**) calloc(rows, sizeof(int*));
d = (int*) calloc(rows * columns, sizeof(int));
for(; i < rows; i++) {
p[i] = d + i * columns;
}
return p;
}
(code not tested)
that's not because it haves a bidimensional array size (rows*columns*sizeof(int*)) to store the pointers and a bidimensional array space to store the real values (rows*columns*sizeof(int))?
You can use the following approach (no extra memory needed for storing data, actually 1D continuous array in memory):
#include <stdlib.h>
#include <stdio.h>
int (*allocateMatrix(int rows, int columns))[]{
int (*p)[columns] = calloc(rows, columns * sizeof(int)),
i, j;
for (i = 0; i < rows; i++) {
for (j = 0; j < columns; j++) {
p[i][j] = rows*i + j;
}
}
return p;
}
int main(int argc, char *argv[]) {
int rows = 4, cols = 5,
(*array)[cols] = allocateMatrix(rows,cols);
int i, j;
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
printf("array[%d][%d] = %2d\n", i, j, array[i][j]);
}
}
free(array);
return 0;
}
Output:
array[0][0] = 0
array[0][1] = 1
array[0][2] = 2
array[0][3] = 3
array[0][4] = 4
array[1][0] = 4
array[1][1] = 5
array[1][2] = 6
array[1][3] = 7
array[1][4] = 8
array[2][0] = 8
array[2][1] = 9
array[2][2] = 10
array[2][3] = 11
array[2][4] = 12
array[3][0] = 12
array[3][1] = 13
array[3][2] = 14
array[3][3] = 15
array[3][4] = 16
I have created a 2 d array which reads as follows
int i,j,lx,ly;// lx,ly are the row and column respectively
double** a;
a=(double**) malloc((lx+2)*sizeof(double));
a[0]= (double*) malloc((lx+2)*(ly+2)* sizeof(double));
assert(a[0]);
for(i=1;i<lx+2;i++)
{
a[i]=a[i-1]+i*(ly+2);
}
// I allocate a value of 0 to all the elements in this array as below
for(i=0;i<(lx+2)*(ly+2);i++)
{
a[i]=0;
}
// I print out all my elements below
for(i=0;i<(lx+2)*(ly+2);i++)
{
printf("position %d values %d\n",i,a[i]);
}
// When I see the output , it shows me a junk value at one particular position 13. I am unable to figure that out .. ALso kindly tell me how to access rows and columns like Eg to acces 7 th column row 0 and 5th row 6 th column in terms of lx, ly as shown in my code
Your approach is definitely heading in the right general direction.
I think this:
a=(double**) malloc((lx+2)*sizeof(double));
would normally be:
a = malloc(lx * sizeof(double *));
And then without the contiguity requirement, this:
a[0]= (double*) malloc((lx+2)*(ly+2)* sizeof(double));
in most programs would look like:
a[0] = malloc(ly * sizeof(double));
And finally, that last line needs to be in a loop that assigns each a[i] with it's own malloc'ed space.
However, that won't create contiguous memory. To do that you will need to do that big allocation and then divide it up for the row vector. So, instead of the second malloc in a loop, perhaps something like:
double *t = malloc(lx * ly * sizeof(double));
for (i = 0; i < lx; ++i)
a[i] = t + i * ly;
Putting it all together:
#include <stdio.h>
#include <stdlib.h>
void arrayDemo(int lx, int ly)
{
double **a;
int i, j;
a = malloc(lx * sizeof(double *));
double *t = malloc(lx * ly * sizeof(double));
for(i = 0; i < lx; ++i)
a[i] = t + i * ly;
for(i = 0; i < lx; ++i)
for(j = 0; j < ly; ++j)
a[i][j] = i*100 + j;
for(i = 0; i < lx; ++i) {
for(j = 0; j < ly; ++j)
printf(" %4.0f", a[i][j]);
printf("\n");
}
}
int main(int ac, char **av)
{
arrayDemo(atoi(av[1]), atoi(av[2]));
return 0;
}
$ cc -Wall all.c
$ ./a.out 4 7
0 1 2 3 4 5 6
100 101 102 103 104 105 106
200 201 202 203 204 205 206
300 301 302 303 304 305 306
This code allocates a 10 by 5 contiguous block of memory, initializes it with incrementing doubles, and then prints the values indexed by x and y:
#include "2d.h"
int main(void){
unsigned int x,y;
const unsigned int width = 10;
const unsigned int height = 5;
//we need an index into the x of the array
double * index[width];
//need the memory to store the doubles
unsigned int memorySizeInDoubles = width * height;
double * memory = malloc(memorySizeInDoubles * sizeof(double));
//initialize the memory with incrementing values
for(x = 0; x < memorySizeInDoubles; ++x){
memory[x] = (double) x;
}
//initialize the index into the memory
for(x = 0; x < width; ++x){
index[x] = memory + height * x;
}
//print out how we did
for(x = 0; x < width; ++x){
for(y = 0; y < height; ++y){
printf("[%u, %u]: Value = %f\n", x, y, index[x][y]);
}
}
free(memory);
return 0;
}
The 2d.h file should contain these lines:
#include <stdio.h>
#include <stdlib.h>
int main(void);
Note: The memory created is only contiguous for some definitions. The memory is logically contiguous, but not necessarily physically contiguous. If this memory is for a device driver for instance, malloc won't work.
Either you create a single dimension array
double my_array = malloc(sizeof(double) * size_x * sizeof(double) * size_y);
which you will access by
(get position x=28, y=12)
my_array[12 * size_x + 28];
or you create a 2d array like you do, but you access it with
double **my_array = (double**) malloc(15 * sizeof(double));
for(int i = 0 ; i < 25; i++)
{
my_array[i] = (double*) malloc(30 * sizeof(double));
for (int j = 0 ; j < 12; j++)
{
my_array[i][j] = 1.2;
}
}
double my_double = my_array[12][28];
In C, to have one chunk of contiguous memory, you need one malloc(), or have a statically allocated array. Since you want dynamic memory, you will need malloc(). Since you need everything to be contiguous, you will need only one call to it.
Now, what should the call look like? If I understood you correctly, you need lx times ly values, each with size sizeof(double), so you need lx*ly*sizeof(double) bytes to be allocated.
Digression: I prefer writing my malloc() calls as follows:
#include <stdlib.h> /* for malloc's prototype */
T *pt; /* for any type T */
size_t n; /* need n objects of type T */
pt = malloc(n * sizeof *pt);
Using sizeof with sizeof *pt instead of sizeof(T) offers an advantage that if the type of pt changes, you don't need to change the malloc() call. Not casting the result of malloc() is nice because then the whole malloc() call is type-agnostic, and is easier to type and read. Be sure to #include <stdlib.h> though.
So, to allocate space for n doubles, you can do:
double *pd = malloc(n * sizeof *pd);
if (pd != NULL) {
/* malloc succeeded */
} else {
/* malloc failed */
}
Now, after allocating memory, you need to be able to index it. Let's say you have lx == 2 and ly == 3. Your memory looks like:
+---+---+---+---+---+---+
pd: | 0 | 1 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+---+
pd[0], pd[1] and pd[2] are the double values corresponding to the first row, pd[3] to pd[6] are the double values corresponding to the second row. You should be able to generalize this observation to translate a given x,y index pair to one number that indexes into your pd array properly.