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

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.

Related

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)

C - Convert array of elements into 2-d matrix

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

Passing arrays to functions without using pointers

C allows passing arrays to functions using the array name directly. Since the array name is the starting address of the array (address of element [0]) - this is passing by reference - hence even local array can be passed this way - and the changes of either function will be visible to the other without any need of explicit return.
What I understand so far is -
The function call just needs to include the name of the array which provides the starting address - and the integer size of each dimension as separate int arguments - this way any function other than the function that contains array definition - has all the information of arrays location and size (array size as well as size of each dimension) and can operate on any element. Once again, since this is pass by reference, any such change will be visible to all such functions including and from the one containing array definition (it will need to pass the same information as arguments to each function - the array name for starting address and each dimension size) , without any return required specifically for these changes to be visible to all functions including the calling function.
The array argument in the function prototype and function definition specifies the array with a pair of square braces for each dimension + in the same argument - the largest ? value for each dimension except the most significant one (rows in a 2-D array) is also specified eg -
//Prototype
return_type function_name ( array_name[][MAX_COLS], int rows, int cols);
// Function call somewhere
function_name (array_name, num_rows, num_columns); /* array name refers
to starting address */
Also for the dimensions for which the largest ? value is specified in prototype and definition (MAX_COLS for our example), the actual value during call, specified as a separate argument (cols), may and will mostly be different.
I do not know why the size is required for other dimensions (MAX_COLS) and it will be very kind of someone to explain. Also please correct, confirm, improve everything as necessary.
Example Code with 1-D array of pointers to model a 2-D array -
#define MAX_ROWS 20
extern void modify( int rows, int cols, int *a[]);
extern void input_2d_array(int rows, int cols, int *a[]);
extern void output_2d_array(int rows, int cols, int *a[]);
int main()
{
int rows = 4, cols = 3;
int* a[MAX_ROWS], i;
for (i=0; i<rows; i++)
a[i] = (int*) malloc ( cols*sizeof(int) );
input_2d_array(rows, cols, a);
printf("Initially in main array = \n");
output_2d_array(rows, cols, a);
modify(rows, cols, a);
printf("Finally in main array = \n");
output_2d_array(rows, cols, a);
_getch();
return 0;
}
void input_2d_array(int rows, int cols, int *a[])
{
int i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
{
printf("Please enter the elements for row %d and column %d of a \n", i + 1, j + 1);
scanf_s(" %d", (a+(i*cols)+j) );
}
return;
}
void output_2d_array(int rows, int cols, int *a[])
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
printf(" %d", *(a + (i*cols) + j) );
}
printf("\n");
}
return;
}
void modify(int rows, int cols, int *a[])
{
int i, j;
printf("Initally in modify array = \n");
output_2d_array(rows, cols, a);
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
*(a + (i*cols) + j) = (*(a + (i*cols) + j)) + 2;
// *(*(a + i) + j) += 2; // Gives exception
// *(a[i]+j) += 10; // Gives exception
}
}
printf("Finally in modify array = \n");
output_2d_array(rows, cols, a);
return;
}
There are some misunderstandings. It is going to take time to explain them.
Fixed width arrays
Your example prototype is (more or less):
//Prototype
ReturnType function_name(ArrayType array_name[][MAX_COLS], int rows, int cols);
Somewhere, you have a constant definition for MAX_COLS; for sake of argument, it can be:
enum { MAX_COLS = 64 };
This function only accepts arrays that have MAX_COLS columns, though the arrays can have any number of rows. The int cols argument is immaterial to this array's definition. In the calling code, the array must be defined with MAX_COLS (or its equivalent) as the second dimension.
Inside the function, the compiler will interpret a reference array_name[i][j] (i and j being integer types) as:
*(array_name + (i * MAX_COLS + j))
It will never use cols in that calculation. An attempt to pass an array with a different row width to the function leads to — I'm going to call it 'undefined behaviour', though there might strictly be a different interpretation for which sort of undesirable and incompletely specified behaviour is applicable. The result is not going to be what you expect. If you pass a narrower array, you may well index out of bounds of the actual array; if you pass a wider array, you probably won't run out of bounds, but (as when accessing out of bounds), you won't be accessing the elements you expect to access because the computation will be based on MAX_COLS, not the function argument cols.
Variable length arrays
Using a variable length array (VLA), you could revise your function to:
ReturnType function_name(int rows, int cols, ArrayType array_name[rows][cols]);
Note that the size variables must be defined before they are used; the size parameters must precede their use in an array definition.
Now, inside the function, the compiler will interpret array_name[i][j] (as before) as:
*(array_name + (i * cols + j))
You can pass any shape of array as long as you get the rows and cols parameters correct.
There are a variety of other notations that could be used in the prototype for the function taking a VLA, including these:
ReturnType function_name(int rows, int cols, ArrayType array_name[*][*]);
ReturnType function_name(int rows, int cols, ArrayType array_name[][*]);
However, the function definition would need to have cols appear before the array definition:
ReturnType function_name(int rows, int cols, ArrayType array_name[rows][cols]) { … }
ReturnType function_name(int rows, int cols, ArrayType array_name[][cols]) { … }
And with the 'unsized' leading dimension, you could (if you were perverse enough) write:
ReturnType function_name(int cols, ArrayType array_name[][*], int rows);
ReturnType function_name(int cols, ArrayType array_name[][cols], int rows) { … }
My own view is that it is simpler to maintain the code if the function prototype declaration exactly matches the function definition line, so I'd not use the notations with * in the prototypes. I'd also use the explicit ArrayType array_name[rows][cols] notation, indicating which parameter specifies each size. This matters if you do a matrix multiplication function, for example:
void MatrixMultiply(int r1, int c1, int c2,
Data m1[r1][c1], Data m2[c1][c2], Data result[r1][c2]);
Whether the compiler will report problems with matrix size mismatches is open to debate, but the opportunity is there. If you prefer, you could have a redundant r2 parameter to specify the row size of the m2 matrix, but then you've got problems if r2 != c1, and it is harder for the compiler to help — you're reduced to assertions or other error reporting mechanisms to indicate that nothing useful was done to the result because the matrix sizes were not compatible for multiplication.
I'm not sure whether I've deconstructed all the misunderstandings in your question; I suspect not.
Arrays of pointers vs 2D arrays
From a comment:
If my function signature is void modify(int rows, int cols, int *a[]) then how do I access a[i][j] and &a[i][j] in the called function?
This requires an array of pointers to int, so you have to set up the array differently from before (in the calling code). However, inside the function,
you simply write:
int x = a[i][j];
int *y = &a[i][j];
int *z = a[i] + j;
The expressions for y and z are equivalent; I'd probably use the former.
Note that the 'behind the scenes' calculation for x is different here from the formula used for a[i][j] when passing an array:
int x = *(*(a + i) + j);
There are two memory references, the first to read the pointer a[i], and the second to read a[i][j] (with two explicit additions but no explicit multiplication, though the subscript additions have to be scaled by the size of int * and int), whereas with the array notation, there was only one memory reference (with two explicit additions and one explicit multiplication — and only one scaling operation by the size of int).
The same comment also says:
I tried a[i]+j and (a[i]+j) combination as well as *(a+(i*cols)+j) and (a+(i*cols)+j) and none is working.
There's a good chance I've not managed to add * symbols in the right places, especially in the 'as well as' portion of the sentence. Please provide the correct notation in a new extra (or replacement) comment, and I can dissect what you actually typed rather than what I'm guessing you typed.
The value of a[i] + j should give you a pointer to the jth integer in the ith row of the data. You'd have to wrap that as *(a[i] + j) to get the int value. The parenthesized version also gives you the pointer to element a[i][j]; you need a * in front to get the value.
The variations like *(a+(i*cols)+j) are wrong because in this context, you do not need to multiply by the number of columns. There's no requirement the consecutive rows pointed at by a[i] and a[i+1] are contiguous in memory; they could be located in multiple disjoint blocks of memory (and in fact there could be multiple pointers to a single block of memory, too). Within a row, the elements must be contiguous, of course.
It's roughly the difference between int a[][4]:
+---+---+---+---+
| 2 | 3 | 5 | 7 |
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
| 7 | 5 | 3 | 2 |
+---+---+---+---+
| 9 | 8 | 7 | 6 |
+---+---+---+---+
and int *a[]:
+------------+ +---+---+---+---+
| 0x010C0304 |------>| 2 | 3 | 5 | 7 |
+------------+ +---+---+---+---+
| 0x020D0408 |------>| 1 | 2 | 3 | 4 |
+------------+ +---+---+---+---+
| 0x030E050C |------>| 7 | 5 | 3 | 2 |
+------------+ +---+---+---+---+
| 0x040F0600 |------>| 9 | 8 | 7 | 6 |
+------------+ +---+---+---+---+
Note that more storage is required to hold the int *a[] data than int a[][4].
Also note that I've made the 4 arrays of numbers in the int *a[] non-contiguous. Also, the rows in the int *a[] example could be of different lengths, provided you know how to access the length (or the lengths are all at least 4 and you don't go beyond the fourth element).
Adapting the MCVE from the question
As I said in the previous section, when you are using an 'array of pointers' notation, using cols in the subscript calculation is wrong. Here's an adaptation of your code — I've had to remove the Windows-specific features such as _getch() and scanf_s() (using 'nothing' and scanf() instead). I've also shown some alternatives; the printing shows some of the alternatives.
#include <stdio.h>
#include <stdlib.h>
#define MAX_ROWS 20
extern void modify(int rows, int cols, int *a[]);
extern void input_2d_array(int rows, int cols, int *a[]);
extern void output_2d_array(int rows, int cols, int *a[]);
int main(void)
{
int rows = 4, cols = 3;
int *a[MAX_ROWS], i;
for (i = 0; i < rows; i++)
a[i] = (int *)malloc(cols * sizeof(int));
input_2d_array(rows, cols, a);
printf("Initially in main array =\n");
output_2d_array(rows, cols, a);
modify(rows, cols, a);
printf("Finally in main array =\n");
output_2d_array(rows, cols, a);
//_getch();
return 0;
}
void input_2d_array(int rows, int cols, int *a[])
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
printf("Please enter the elements for row %d and column %d of a\n", i + 1, j + 1);
//scanf_s(" %d", (a + (i * cols) + j));
//scanf(" %d", (a + (i * cols) + j));
scanf(" %d", &a[i][j]);
//scanf(" %d", a[i] + j);
//scanf(" %d", *(a + i) + j);
}
}
}
void output_2d_array(int rows, int cols, int *a[])
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
//printf(" %d", *(a + (i * cols) + j));
printf(" %d", a[i][j]);
printf(" (%d)", *(*(a + i) + j));
}
printf("\n");
}
}
void modify(int rows, int cols, int *a[])
{
int i, j;
printf("Initally in modify array =\n");
output_2d_array(rows, cols, a);
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
a[i][j] = a[i][j] + 2;
*(a[i] + j) = *(*(a + i) + j) + 2;
//*(a + (i * cols) + j) = (*(a + (i * cols) + j)) + 2;
// *(*(a + i) + j) += 2; // Gives exception
// *(a[i]+j) += 10; // Gives exception
}
}
printf("Finally in modify array =\n");
output_2d_array(rows, cols, a);
}
Example run (program mda17):
$ mda17
Please enter the elements for row 1 and column 1 of a
23
Please enter the elements for row 1 and column 2 of a
24
Please enter the elements for row 1 and column 3 of a
25
Please enter the elements for row 2 and column 1 of a
26
Please enter the elements for row 2 and column 2 of a
27
Please enter the elements for row 2 and column 3 of a
28
Please enter the elements for row 3 and column 1 of a
99
Please enter the elements for row 3 and column 2 of a
98
Please enter the elements for row 3 and column 3 of a
97
Please enter the elements for row 4 and column 1 of a
96
Please enter the elements for row 4 and column 2 of a
95
Please enter the elements for row 4 and column 3 of a
94
Initially in main array =
23 (23) 24 (24) 25 (25)
26 (26) 27 (27) 28 (28)
99 (99) 98 (98) 97 (97)
96 (96) 95 (95) 94 (94)
Initally in modify array =
23 (23) 24 (24) 25 (25)
26 (26) 27 (27) 28 (28)
99 (99) 98 (98) 97 (97)
96 (96) 95 (95) 94 (94)
Finally in modify array =
27 (27) 28 (28) 29 (29)
30 (30) 31 (31) 32 (32)
103 (103) 102 (102) 101 (101)
100 (100) 99 (99) 98 (98)
Finally in main array =
27 (27) 28 (28) 29 (29)
30 (30) 31 (31) 32 (32)
103 (103) 102 (102) 101 (101)
100 (100) 99 (99) 98 (98)
$
Check this and try to find if array is passed as an array or a pointer to some function:
char arr[]={'a','b','c'};
int sizeOfArr = sizeof(arr)/sizeof(arr[0]);
in both the function find size of array using above method where arr[] has been created and where it has been passed - the sizeOfArr will decipher things. This perhaps would clear why size/dimensions have been passed explicitly - this is all I can make out of your entire statement. Correct me if I am wrong.
To not use pointers - wrap the array into the struct. Then the entire struct (including the array) will be passed to the function.

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