C - Convert array of elements into 2-d matrix - c

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]);
}

Related

Dynamic memory allocation with / without function

I tried creating function that dynamically allocates memory for 2 dimensional array and put some integer values into the array. Overall, the function worked as expected but there were some error. So I did the same thing within main() and got the right result. My code is like below:
#include <stdlib.h>
#include <stdio.h>
void test(int d1, int d2, int ***p){
int value;
*p = (int **)(malloc(sizeof(int)*d1));
for (int i = 0; i < d1; i++){
(*p)[i] = (int *)(malloc(sizeof(int)*d2));
for (int j = 0; j < d2; j++){
(*p)[i][j] = i * 10 + j;
}
}
printf("\n");
}
int main(void){
int d1, d2;
int ** ptr;
printf("length of 1st dimension?\n");
scanf("%d", &d1);
printf("length of 2nd dimension?\n");
scanf("%d", &d2);
test(d1, d2, &ptr);
for (int i=0; i<d1; i++){
for (int j=0; j<d2; j++){
printf("%d ", ptr[i][j]);
}
printf("\n");
}
free(ptr);
ptr = (int **)(malloc(sizeof(int)*d1));
for (int i=0; i< d1; i++){
ptr[i] = (int *)(malloc(sizeof(int)*d2));
for (int j=0; j<d2; j++){
ptr[i][j] = i *10 +j;
}
}
printf("\n######################\n\n");
for (int i=0;i<d1;i++){
for (int j=0; j<d2;j++){
printf("%d ", ptr[i][j]);
}
printf("\n");
}
free(ptr);
return 0;
}`
When I passed 5 as a length of 1st and 2nd dimension, I got the result like below:
length of 1st dimension?
5
length of 2nd dimension?
5
532699424 32725 2 3 4
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
######################
0 1 2 3 4
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
I think, except that I passed pointer to pointer to pointer as an argument to the function, I did the same thing. However some values in the first row are different. And I got different value for the first row whenever I executed the function.
Could someone please let me know what I did wrong?
Thank you in advance.
The lines
*p = (int **)(malloc(sizeof(int)*d1));
ptr = (int **)(malloc(sizeof(int)*d1));
are wrong. The elements is int*, but only room for int is allocated per element.
This may cause trouble if int* is larger than int (for example, when int* is 8 bytes and int is 4 bytes).
The lines should be
*p = malloc(sizeof(int*)*d1);
ptr = malloc(sizeof(int*)*d1);
or (with risk of making mistake reduced by avoiding writing type manually)
*p = malloc(sizeof(*p)*d1);
ptr = malloc(sizeof(*ptr)*d1);
See also: c - Do I cast the result of malloc? - Stack Overflow

Sort working in main() but not in separate function

I'm working on a homework problem for C and unix programming, and the teacher told us to write a sort function for an array in C.
I've got sorting working from some for loops in main, but the separate sort function we need doesn't work.
#include <stdio.h>
#include <stdlib.h>
int Sort(int arr[], int size){
int i,j,a;
for(i = 0; i < size; i++){
for(j = i+1; j < size; j++){
if(arr[i] > arr[j]){
a = arr[i];
arr[i] = arr[j];
arr[j] = a;
}
}
return arr;
}
}
int main(){
int a;
int BAT[40];
for(int i=0; i < 40; i++){
BAT[i] = (float)(599)* ( (float)rand() / (float)RAND_MAX );
printf("%d \n", BAT[i]);
}
printf(" the array should now be sorted \n");
//Sort(BAT, 40); THIS IS THE FUNCTION CALL THAT DIDNT SEEM TO WORK SO I COPIED THE SORT OUT OF THE SORT FUNCTION TO TEST
//THIS IS THE SORT CODE AND WHILE IT IS IN THE MAIN IT WORKS
for(int i = 0; i < 40; i++){
for(int j = i+1; j < 40; j++){
if(BAT[i] > BAT[j]){
a = BAT[i];
BAT[i] = BAT[j];
BAT[j] = a;
}
}
}
//END OF SORTING TEST
for(int j=0; j < 40; j++){
printf("%d \n", BAT[j]);
}
I expect the Sort(BAT, 40) to sort the array which I then try to print but instead nothing seems to occur.
Your sort routine should have worked as written, but you are failing to enable warnings in your code and thus you are not allowing the compiler to help you fix the warnings and errors in your code -- that alone would have allowed your code to run just fine.
For instance, your compiler will tell you the exact line number, and many times the exact character in that line where the error or warning was detected, e.g.
bubblesortfn.c: In function ‘Sort’:
bubblesortfn.c:21:5: warning: return makes integer from pointer without a cast
[enabled by default]
return arr;
^
How can a return make an integer from a pointer?? Simple, you have your function attempting to return an integer array (int *), and you have your function declared int Sort. (you don't need to return anything, but you can simply fix it by changing your declaration to int *Sort (....)).
The remainder of the problems are simple syntax issues and unused variables (e.g. a in main()) that would be instantly flagged by your compiler -- listen to it. Let it help you write better code.
Always compile with warnings enabled, and do not accept code until it compiles cleanly without warning. To enable warnings add -Wall -Wextra -pedantic to your gcc/clang compile string. For clang, instead you can use -Weverything. For VS (cl.exe on windows), use /W3 (or use /Wall but you will get quite a few extraneous non-code related warnings). Read and understand each warning -- then go fix it.
As mentioned in my comment, don't use magic numbers in your code (except where absolutely required like with the fscanf field-width modifier). Instead, If you need a constant, #define one (or more), or use a global enum to do the same thing. That way you have one single place at the top of your code to change things if needed and you don't have to go picking through your declarations or loop limits to change things.
Literally, fixing the warnings identified and tidying things up a bit was all that was needed to get your code working and properly sorting the array in your Sort function (I also added a prnintarray() function to print your array to avoid the repeated loops in main(). Putting it altogether, and seeding the random number generator by calling srand() before you use rand(), you could do:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* if you need a constant, define one (or more) - avoid magic numbers */
#define ROWSZ 10 /* max integers to print per-row */
#define MAXB 40 /* max integers in BAT */
#define MULTP 599 /* multiplier constant */
int *Sort (int arr[], int size)
{
int i, j, a;
for (i = 0; i < size; i++) {
for (j = i + 1; j < size; j++) {
if (arr[i] > arr[j]){
a = arr[i];
arr[i] = arr[j];
arr[j] = a;
}
}
}
return arr;
}
/* simple print function to output arr of sz with rowsz int per-row */
void prnintarray (int *arr, size_t sz, size_t rowsz)
{
for (size_t i = 0; i < sz; i++) {
if (i && i % rowsz == 0)
putchar ('\n');
printf (" %4d", arr[i]);
}
putchar ('\n');
}
int main (void) {
int BAT[MAXB] = {0}; /* initialize all arrays - good practice */
srand (time(NULL)); /* seed the random number generator */
for (int i = 0; i < MAXB; i++) /* fill array */
BAT[i] = MULTP * ( (float)rand() / (float)RAND_MAX );
puts ("\nunsorted array:\n");
prnintarray (BAT, MAXB, ROWSZ);
Sort (BAT, MAXB);
puts ("\nsorted array:\n");
prnintarray (BAT, MAXB, ROWSZ);
}
Example Use/OUtput
$ ./bin/bubblesortfn
unsorted array:
461 519 346 508 265 93 358 407 278 151
465 531 430 148 181 227 452 206 401 202
103 518 259 267 342 495 570 431 477 455
164 339 375 511 248 42 6 8 450 284
sorted array:
6 8 42 93 103 148 151 164 181 202
206 227 248 259 265 267 278 284 339 342
346 358 375 401 407 430 431 450 452 455
461 465 477 495 508 511 518 519 531 570
Look things over and let me know if you have further questions.
Use qsort For Real-World Sorting
While there is nothing wrong with writing a bubblesort function for the learning aspect of it, the C-library provides qsort which can, and should, cover the majority of your sorting needs. Your only job in using qsort is to write a simple compare() function to tell qsort how to sort adjacent members of the array. The prototype for the compare() function usually sends new C programmers into a state of panic. The prototype is:
int compare (const void *a, const void *b)
Don't let it bother you. a and b are just pointers to the two members of your array currently being compared. Your job is to write the remainder of the function so that if the value pointed to by a:
sorts before the value pointed to by b, a negative number is returned;
is equal to the value pointed to by b, zero is returned and finally
sorts after b a positive values is returned. (all just like strcmp).
To handle the fact that a and b are void pointers, you simply cast them to int pointers before dereferencing to make use of their values, e.g.
int compare (const void *a, const void *b)
{
const int *pa = a, /* a and b are pointers to elements being compared*/
*pb = b; /* in array, cast as required to proper type */
Since your array is int, a and b will be pointers-to int, you simply cast them to int *. Now you can access the values through the pointers (e.g. dereference *pa to get the value at the address held by pa).
Now to satisfy the return requirements the trivial solution would be:
return *pa - *pb;
However, if the *pa is a large negative value and *pb is a large positive value, subtracting *pa - *pb can easily result in integer overflow and undefined behavior. Instead of a direct subtraction, by using two inequalities, chance of overflow can be eliminated while providing the needed return. Think through:
return (*pa > *pb) - (*pa < *pb);
So putting your qsort function together and replacing your call to Sort with a call to qsort, you would rewrite your code as:
int compare (const void *a, const void *b)
{
const int *pa = a, /* a and b are pointers to elements being compared */
*pb = b; /* in array, cast as required to proper type */
/* inequality avoids overflow from subtracting 2 large values
* (x > y) - (x < y) , returns -1, 0, 1 (like strcmp) for
* -1 -> x sorts before y, 0 -> x equals y, 1 -> x sorts after y
*/
return (*pa > *pb) - (*pa < *pb);
}
Then
qsort (BAT, MAXB, sizeof *BAT, compare);
Give it a try. As a bonus for large arrays, qsort will be Orders of Magnitude faster than a bubblesort (one of the slowest sorts for large arrays)

How to create variable length array on heap? [duplicate]

This question already has answers here:
Dynamically creating a contiguous 5D array? [closed]
(6 answers)
Closed 6 years ago.
I used C's variable length array to implement an algorithm:
int matrix[rows][cols];
I managed to test that this does fail for ridiculous dimensions. Is there a way to allocate this matrix on heap instead of stack? Otherwise I'll have to rewrite this to int**...
Something like calloc(sizeof(int[rows][cols]), 1)? Note that this question is specifically about variable length arrays.
It looks simple enough. The only remotely tricky bit is the type to hold the pointer to the dynamically allocated array:
#include <stdlib.h>
#include <stdio.h>
static void print_matrix(int r, int c, int matrix[r][c])
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
printf(" %d", matrix[i][j]);
putchar('\n');
}
}
static void set_matrix(int r, int c, int matrix[r][c])
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
matrix[i][j] = (i+1) * 100 + j + 1;
}
}
int main(void)
{
size_t rows = 9;
size_t cols = 7;
size_t size = sizeof(int[rows][cols]);
printf("rows = %zu, cols = %zu, size = %zu\n", rows, cols, size);
int (*matrix)[cols] = calloc(sizeof(int[rows][cols]), 1);
if (matrix != 0)
{
set_matrix(rows, cols, matrix);
print_matrix(rows, cols, matrix);
free(matrix);
}
return 0;
}
This code carefully uses calloc() to zero all the elements of the array, and then calls set_matrix() to set them to non-zero values. As written, malloc() would be better than calloc(), but the question used calloc() and it would not be hard to make it sensible for use with this code too (for example, a conditional assignment in set_matrix(), such as if (i && j && i != j)).
Example output:
rows = 9, cols = 7, size = 252
101 102 103 104 105 106 107
201 202 203 204 205 206 207
301 302 303 304 305 306 307
401 402 403 404 405 406 407
501 502 503 504 505 506 507
601 602 603 604 605 606 607
701 702 703 704 705 706 707
801 802 803 804 805 806 807
901 902 903 904 905 906 907
You can create a pointer to a VLA:
size_t rows, cols;
... // get values for rows and cols
T (*arr)[cols] = malloc( sizeof (T [cols]) * rows );
if ( arr )
{
...
arr[i][j] = some_value;
...
}
There is some debate over whether
T (*arr)[cols] = malloc( sizeof *arr * rows );
should work. The way the standard is worded, this form results in undefined behavior, since sizeof has to evaluate *arr at runtime (since the expression *arr refers to a VLA), and arr is an invalid pointer when sizeof *arr is evaluated.
However, it depends on what "evaluate" means in that particular context; there's no reason to have to dereference arr in order to determine the size of the array it points to, any more than you would for a fixed-length array:
T (*arr)[10] = malloc( sizeof *arr * rows );
I and a few others are of the opinion that the standard is poorly worded in this respect, and that sizeof *arr should be valid whether arr points to a fixed- or variable-length array. This is the idiom I use and it hasn't failed on me...yet.
But, I would be remiss if I didn't point out this issue, and provide you with something that I know won't result in UB.

Stepping through a multidimensional array using pointers in C

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.

rand() not produce random [c]

I was asked to write a program that produces a 2d array of random numbers. My code produces strange results. Regardless of the size of the matrix it produces a "reverse diagonal matrix" (not sure what else to call it). I was to understand that rand() produces a pseudorandom number between 0 and RAND_MAX but somehow the results are dependent on the size of my matrix, I am unsure how this behavior could happen.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAT_SIZE 5
void main (void)
{
srand(time(0));
unsigned char * ptr = malloc(MAT_SIZE*MAT_SIZE);
unsigned char i, j;
for(i = 0; i < MAT_SIZE; i++)
{
for(j = 0; j < MAT_SIZE ; j ++)
{
*(ptr + i + j ) = rand();
}
}
for(i = 0; i < MAT_SIZE ; i++)
{
for(j = 0; j < MAT_SIZE ; j ++)
{
printf("%5d", *(ptr + i + j));
}
printf("\n");
}
free(ptr);
}
Output for 3*3
142 141 11
141 11 230
11 230 28
Output for 5*5
232 157 62 131 245
157 62 131 245 54
62 131 245 54 138
131 245 54 138 246
245 54 138 246 108
Even a pseudorandom number shouldn't behave differently based on how it is used. Is there something I'm not understanding about the program that forces these results?
The problem is not with the random numbers that are generated but with how you are saving them in your matrix. To access element (j, i) you do not want
*(ptr + i + j )
but
*(ptr + MAT_SIZE * i + j )
You are only accessing the first i+j members of the array, and looping over the same indices repeatedly. Instead of:
*(ptr + i + j )
Try
*(ptr + i * MAT_SIZE + j )
Note that you can dynamically allocate a 2D array as follows:
unsigned char (*ptr)[MAT_SIZE] = malloc( MAT_SIZE * sizeof *ptr );
...
ptr[i][j] = rand();
...
free( ptr );
Makes life a little simpler. This way you can use normal 2D array indexing instead of having to map i and j to a single dimension.
Nits:
Unless your compiler documentation explicitly lists void main() as a valid signature for main, use int main( void ) instead. I know you've seen thousands of examples of void main() in books and on line, but just because the compiler doesn't complain about it doesn't mean it isn't wrong.
rand() returns int, which will not fit into an unsigned char. Overflow on unsigned types is well-defined, but even so, you may want to explicitly map your rand result onto the range [0..255].

Resources