I am trying to create a variable matrix using a function that inputs an empty array pointer m and outputs the int array pointer m with values 1,2,3,4,...n elements in the matrix. I use the variable k and increment the value upwards to accomplish this (not sure if this is the best way).
I am getting a subscripted value is not an array, pointer, or vector in my for loop here matrix[i][j] = k++; and I am not really sure why it is only appearing inside the for loop and nowhere else.
If I am inputting an int array pointer called matrix, I shouldn't be getting this error right?
int *create_matrix(int* matrix) {
int i,j;
int k = 0;
// 'total' will be 70 = 10 * 7
int total = sizeof(matrix);
// 'column' will be 7 = size of first row
int column = sizeof(matrix[0]);
// 'row' will be 10 = 70 / 7
int row = total / column;
for (i=0; i < row; i++) {
for (j=0; j < column; j++) {
matrix[i][j] = k++;
}
}
return matrix;
}
int main(void) {
// Creating a custom matrix.
int m[3][4] = {0};
create_matrix(*m);
return 0;
}
You need to learn the difference between arrays and pointers. You can point a pointer to a matrix, but the information about size and number of dimensions are lost as long as you're only accessing the array via the pointer.
You would need to do something like this:
int *create_matrix(int* matrix, size_t size_x, size_t size_y) {
...
}
int main()
{
int m[3][6];
size_t size_y=sizeof m[0]/sizeof m[0][0];
size_t size_x=sizeof m / sizeof m[0];
create_matrix(m);
}
To do
int m[3][4] = {0};
create_matrix(*m);
is equivalent of
int m[3][4] = {0};
create_matrix(m[0]);
so is equivalent of having
int m[4] = {0};
create_matrix(m);
// 'total' will be 70 = 10 * 7
int total = sizeof(matrix);
matrix is a int *, sizeof(matrix) values 4 if an address uses 32b and 8 if an address uses 64b
The effective size of matrix in main is not relevant
// 'column' will be 7 = size of first row
int column = sizeof(matrix[0]);
matrix[0] is an int, so you get the size of an int (4 or 8 probably)
matrix[i][j] = k++;
because matrix is an int * the form matrix[i][j] is invalid.
To name it matrix is not helpful.
Your program can be :
#include <stdio.h>
void fill_matrix(int matrix[][4], size_t row) {
size_t i, j;
int k = 0;
for (i=0; i < row; i++) {
for (j=0; j < sizeof(matrix[0])/sizeof(int); j++) {
matrix[i][j] = k++;
}
}
}
int main(void) {
// Creating a custom matrix.
int m[3][4] = {0};
fill_matrix(m, sizeof(m)/sizeof(m[0]));
size_t i, j;
for (i=0; i < sizeof(m)/sizeof(m[0]); i++) {
for (j=0; j < sizeof(m[0])/sizeof(int); j++) {
printf("matrix[%d][%d] = %d\n", i, j, m[i][j]);
}
}
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wextra m.c
pi#raspberrypi:/tmp $ ./a.out
matrix[0][0] = 0
matrix[0][1] = 1
matrix[0][2] = 2
matrix[0][3] = 3
matrix[1][0] = 4
matrix[1][1] = 5
matrix[1][2] = 6
matrix[1][3] = 7
matrix[2][0] = 8
matrix[2][1] = 9
matrix[2][2] = 10
matrix[2][3] = 11
Probably it is more visible if you initialize each cell of the matrix with i*10+j rather than with k++, in that case that prints :
matrix[0][0] = 0
matrix[0][1] = 1
matrix[0][2] = 2
matrix[0][3] = 3
matrix[1][0] = 10
matrix[1][1] = 11
matrix[1][2] = 12
matrix[1][3] = 13
matrix[2][0] = 20
matrix[2][1] = 21
matrix[2][2] = 22
matrix[2][3] = 23
Your attempt is a reasonable attempt but it reveals some misconceptions about how objects in C work. That's all right. Yours is a good teaching example and I believe that you will be glad that you have made it. Now try this:
static const int NO_ROWS = 3;
static const int NO_COLUMNS = 4;
int *create_matrix(
int *const matrix, const int no_rows, const int no_columns
) {
int k = 0;
for (int i = 0; i < no_rows; i++) {
for (int j = 0; j < no_columns; j++) {
matrix[no_columns*i+j] = k++;
}
}
return matrix;
}
int main(void) {
// Creating a custom matrix.
int m[NO_ROWS][NO_COLUMNS];
create_matrix(m[0], NO_ROWS, NO_COLUMNS);
return 0;
}
Your matrix is constructed as an array of arrays. However, in C, an array is just a region of storage in which a sequence of objects of the same type (in your case, int) can be kept. The symbol m is interpreted by the C compiler as
meaning the address of the matrix's initial element—or, more precisely, because your matrix is an array of arrays, the address of the matrix's initial row; and
referring to the type of the matrix's initial row, which is itself an array type, int[NO_COLUMNS].
The problem is that there exists no really neat, direct way to specify to a precompiled function the type int[NO_COLUMNS] unless you are willing to hard-code the type. Therefore, one relatively straightforward way to treat the matrix within create_matrix() would be as a single, linear array, as shown.
One point to grasp here is that C does not understand the shape of your matrix. Rather than rows and columns, C sees a linear region of storage.
Another point to grasp is that function to which an array is passed receives only the array's initial address. If it needs the size, that must be separately passed.
Related
Given array A[3][2] ={(1,2),(3,4),(5,6)}
I want to traverse through the first column elements i.e 1,3,5 and next column elements, 2,4,6. All this must be done using a single pointer. How to do this?
If you have 2 array indices, use two for loops.
uint32_t m, n, sum = 0U;
for(n = 0U; n < 2; ++n){ // For each column [n]
for(m = 0U; m < 3; ++m){ // For each row [m] in column [n]
sum += A[m][n];
}
}
Edit: There's not really a difference when using pointers (especially once passed into a function, when it decays). But you have to deal with dereferencing the pointer. This code is more type obfuscating, and could lead one to improperly type/reference, if you don't compile with sufficient warning flags.
uint32_t A[3][2] = {{1,2},{3,4},{5,6}};
uint32_t m, sum = 0U;
uint32_t (*pa2_n)[2];
uint32_t * p_m;
for(pa2_n = &A[0]; pa2_n < &A[3]; ++pa2_n){ // For each column [n]
for(m = 0U; m < 2U; ++m){ // For each row [m] in column [n]
sum += (*pa2_n)[m];
}
// Or
for(p_m = &(*pa2_n)[0]; p_m < &(*pa2_n)[2]; ++p_m){ // For each row [m] in column [n]
sum += *p_m;
}
}
printf("Hello World %u\n", sum);
//
// a method using only 1 pointer could rely on pointer math
//
#include <stdio.h>
#define ROWS 3
#define COLS 2
int
main(void)
{
int matrix[ROWS][COLS] = {
{ 1, 2 },
{ 3, 4 },
{ 5, 6 },
};
int *ptr = &matrix[0][0];
while (1) {
printf("%d,", *ptr);
// point into the next row, same col
ptr += COLS;
// now pointing at least 1 row too many?
if (ptr >= &matrix[ROWS][0]) {
printf("\n");
// at least 1 row too many, last col?
if (ptr >= &matrix[ROWS][COLS - 1])
break;
// backup by total element count - 1 (first row, next col)
ptr -= (ROWS * COLS) - 1;
}
}
return (0);
}
If you want to traverse in the given array int A[3][2] using single pointer you should look at this code:
#include <stdio.h>
int main(void)
{
int arr[3][2] = { 1, 2, 3, 4, 5, 6 };
int *ptr = arr[0], i, j;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
{
printf("%4d", *(ptr+j*2+i));
}
putchar('\n');
}
return 0;
}
I assume you know about the memory representation of a 2D array. If you don't then I'll tell you in short.
A 2D array is stored in the computer's memory on consecutive locations, i.e. one row after another.
That is elements of arr in the above code, will be stored as first 1, second 2, and so on. Using this *(ptr+j*2+i) statement we are traversing through the array. In 1st iteration we are printing ptr+0 then ptr+2 and so on.
Or you can make it simple by declaring a pointer to an array
int (*ptr)[2]; ptr = arr;
and now you can access elements of arr using ptr just like a 2D array.
printf("%4d", ptr[j][i]); or printf("%4d", *(*(ptr+j)+i));
I hope you'll understand the answer.
I am new to C programming and especially to pointers. In the program I wrote, I tried to write a function that returns a pointer to specified column of array. See the code below for better understanding (or confusion :) ):
#include <stdio.h>
#include <stdlib.h>
// function for getting pointer to specidifed column index
// 'ind' is index of requested column, 'ncol' is number of items in column
int* get_col(const int* arr, unsigned int ind, unsigned int ncol);
int main() {
unsigned int n;
printf("Input matrix size : ");
scanf("%i", &n);
int arr[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
arr[i][j] = i * n + j;
}
for (int i = 0; i < n; i++) {
printf("values in column %d: \n", i);
int *col = get_col((int*)arr, i, n);
for (int j = 0; j < n; j++) {
printf("%d ", *col);
col = col + 1;
}
printf("\n");
}
return 0;
}
int* get_col(const int* arr, unsigned int ind, unsigned int ncol) {
int *result = malloc(sizeof(int) * ncol);
for (int i = 0; i < ncol; i++)
*result = *(arr + i*ncol + ind);
return result;
}
As you see get_col function accepts pointer to array, column index and column size (n of elements in column, i.e number of rows) as arguments and trying to return a pointer to 1D array that contains values of column at requested index. The problem is that result is not correct. In case n=3 results are like below:
Input matrix size : 3
values in column 0:
6 0 0 // supposed to be 0 3 6
values in column 1:
7 0 0 // supposed to be 1 4 7
values in column 2:
8 0 0 // supposed to be 2 5 8
I think that the problem lies in my understanding of pointers not the algorithm implemented. Actually, at first I didn't use pointer in my get_col function like below:
int result[ncol];
// ... do my work here to populate array
return &result;
Then as compiler complains warning: function returns address of local variable [-Wreturn-local-addr], I converted result from array to pointer in get_col function like above. What is the problem in this code? Did I use pointers in get_col function as it should be?
In the following line:
*result = *(arr + i*ncol + ind);
You're always writing to the same memory address.
Change it to one of the two following options:
*(result + i) = *(arr + i*ncol + ind);
result[i] = *(arr + i*ncol + ind);
Regarding your second problem when you used:
int result[ncol];
// ... do my work here to populate array
return &result;
You should understand that result variable in this case (static-memory allocation) is stored in the stack. So, after your function returns, the variable values doesn't exist anymore in the memory. That's why you need dynamic-memory allocation. In dynamic-memory allocation, that values stay in the memory until you call free by yourself.
I am working on code which will keep track of each time a specific element in an array is accessed. The array itself will be allocated dynamically based off of the inputs by the user, and so no functions that I have seen are what I'm looking for. To be more specific, how do I dynamically allocate the rows and columns of an array, and then initialize every element to 0?
Ex.
./SIM A B
int* array_columns = malloc(atoi(argv[1]) * sizeof(int));
int* array_rows = malloc(atoi(argv[2]) * sizeof(int));
int array[*array_rows][*array_columns];
everything that I have seen requires knowing beforehand the number of elements in each row/column. Can anyone give any pointers on how to initialize this array to 0? edit: I have added the line where I attempt to establish the array
This program allocates memory using command line parameters and creates a variable that can be accessed using array syntax. It uses calloc to initialize values to zero:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int **array;
int length = atoi(argv[1]);
int width = atoi(argv[2]);
array = calloc(length, sizeof(int *));
for (int i = 0; i < length; i++) {
array[i] = calloc(width, sizeof(int));
}
for (int i = 0; i < length; i++) {
for (int j = 0; j < width; j++) {
printf("array[%d][%d] = %d\n", i, j, array[i][j]);
}
}
for (int i = 0; i < length; i++) {
free(array[i]);
}
free(array);
return 0;
}
Compiled With
gcc -Wall -Werror -o scratch scratch.c
Output
[user#machine]: ./scratch 3 5
array[0][0] = 0
array[0][1] = 0
array[0][2] = 0
array[0][3] = 0
array[0][4] = 0
array[1][0] = 0
array[1][1] = 0
array[1][2] = 0
array[1][3] = 0
array[1][4] = 0
array[2][0] = 0
array[2][1] = 0
array[2][2] = 0
array[2][3] = 0
array[2][4] = 0
Note
I left out input validation and error checking to keep the example small.
Compiler Options
I use -Wall -Werror to turn on all warnings and treat them as errors. This means the compiler won't produce an executable unless all the causes of warnings are fixed. The -o scratch tells the compiler what to name the output file.
It doesn't matter 1D, 2D or ND. You can use two strategies:
The first is to create a simple 1D array as
int *a = (int *)malloc(atoi(argv[1]) * atoi(argv[2]) * sizeof(int));
The second is to create an array of arrays as below:
int len = atoi(argv[1]);
int len2 = atoi(argv[2]);
int **a = (int **)malloc(len * sizeof(int *));
for (int i = 0; i < len; ++i) {
a[i] = (int *)malloc(len2 * sizeof(int));
}
The first variant gives you a simple way to initialize and delete array, the second variant can allow to create bigger array because in this case memory chunks for child arrays can be reserved in different places of the memory.
To initialize it by some value use memset.
For 1D array:
memset(a, 0, sizeof(int) * len * len2);
For array of arrays:
for (int i = 0; i < len; ++i) {
memset(a[i], 0, sizeof(int) * len2);
}
P.S. Some modern compilers allow you to initialize dynamic array as static but that code can have troubles when you will try to compile it in another environment.
P.P.S. Sorry for my English, I hope someone will fix it to human-readable English.
I was writing a code the other day and I found it rather strange, that int** and int[][] does not behave the same way. Can anyone point out the differences between them? Below is my sample code, which fails with a segmentation fault, if I pass constant size 2d array, while it does work fine when I pass a dinamically allocated 2d array.
I am confused mainly because ant int[] array works the same as int*.
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int **t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[0][j] < t[0][j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k][j];
t[k][j] = t[k][j+1];
t[k][j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
So based on the below answers I realize, that a multidimensional array is stored continuously in a row major order. After some modification, the below code works:
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int *t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[j] < t[j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k*m + j];
t[k*m + j] = t[k*m + j+1];
t[k*m + j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
My new question is this: How to modify the code, so that the procedure works with int[][] and int** also?
Realize that int **t makes t a pointer to a pointer, while int t[3][6] makes t an array of an array. In most cases, when an array is used in an expression, it will become the value of the address of its first member. So, for int t[3][6], when t is passed to a function, the function will actually be getting the value of &t[0], which has type pointer to an array (in this case, int (*)[6]).
The type of what is being pointed at is important for how the pointer behaves when indexed. When a pointer to an object is incremented by 5, it points to the 5th object following the current object. Thus, for int **t, t + 5 will point to the 5th pointer, while for int (*t)[M], t + 5 will point to the 5th array. That is, the result of t + 5 is the same as the result of &t[5].
In your case, you have implemented void sort_by_first_row(int **t, int n, int m), but you are passing it an incompatible pointer. That is, the type of &t[0] (which is what t will become in main) is not the same as what the function wants, a int **t. Thus, when the sorting function starts to use that address, it will think its indexing into pointers, when the underlying structure is an array of arrays.
int** is quite different from int[][]. int** is simply a pointer to a pointer and would appear like the following:
in reality, you can access the entire multidimensional array with simply int* pointing to the first element, and doing simple math from that.
Here is the result of the separate allocations (in your commented code):
However when you allocate a multidimensional array, all of the memory is contiguous, and therefore easy to do simple math to reach the desired element.
int t[3][6];
int *t = (int*) malloc((3 * 6) * sizeof(int)); // <-- similarly
This will result in a contiguous chunk of memory for all elements.
You certainly can use the separate allocations, however you will need to walk the memory differently.
Hope this helps.
int t[3][6] is very nearly the same thing as int t[18]. A single contiguous block of 18 integers is allocated in both cases. The variable t provides the address of the start of this block of integers, just like the one-dimensional case.
Contrast this with the case you have marked as "working", where t gives you the address of a block of 3 pointers, each of which points to a block of memory with 6 integers. It's a totally different animal.
The difference between t[3][6] and t[18] is that the compiler remembers the size of each dimension of the array, and automatically converts 2D indices into 1D offsets. For example, the compiler automatically converts t[1][2] into *(t + 1*6 + 2) (equivalent to t[8] if it were declared as a one-dimensional array).
When you pass a multi-dimensional array to a function, there are two ways to handle it. The first is to declare the function argument as an array with known dimension sizes. The second is to treat your array like a 1D array.
If you are going to declare the size of your array, you would declare your function like this:
void sort_by_first_row(int t[][6], int n)
or this
void sort_by_first_row(int t[3][6])
You either have to declare all array dimension sizes, or you can leave out the first size. In both cases, you access elements of t using t[i][j]; you've given the compiler enough information to do the offset math that converts from 2D notation to a 1D index offset.
If you treat it as a 1D array, you have to pass the array dimensions and then do the offset math yourself.
Here's a full working example, where f and f2 both generate the same output:
void f(int* t, int m, int n)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
std::cout << t[i * n + j] << " ";
std::cout << std::endl;
}
void f2(int t[][6], int m)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < 6; j++)
std::cout << t[i][j] << " ";
std::cout << std::endl;
}
int main()
{
int t[3][6];
int val = 1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 6; j++)
{
t[i][j] = val;
val++;
}
}
f(&(t[0][0]), 3, 6);
f2(t, 3);
return 0;
}
One thing to note is the hack-ish way I had to pass t to f. It's been a while since I wrote in C/C++, but I remember being able to pass t directly. Maybe somebody can fill me in on why my current compiler won't let me.
A int ** is a pointer to a pointer to an int, and can be a pointer to an array of pointers to arrays of ints. A int [][] is a 2-dimensional array of ints. A two-dimensional array is exactly the same as a one-dimensional array in C in one respect: It is fundamentally a pointer to the first object. The only difference is the accessing, a two-dimensional array is accessed with two different strides simultaneously.
Long story short, a int[][] is closer to an int* than an int**.
I am having trouble creating a 2D Array of a size defined by the user, with numbers 1, 2, 3.etc.
If the user chooses for example: a = 2 and b = 2, the program produces:
3 4
3 4
instead of:
1 2
3 4
My program looks like:
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
int Array[a][b];
int row, column;
int count = 1;
/*User Input */
printf("enter a and b \n");
scanf("%d %d", &a, &b);
/* Create Array */
for(row = 0; row < a; row++)
{
for(column = 0; column <b; column++)
{
Array[row][column] = count;
count++;
}
}
/* Print Array*/
for(row = 0; row<a; row++)
{
for(column = 0; column<b; column++)
{
printf("%d ", Array[row][column]);
}
printf("\n");
}
return 0;
}
int a, b;
variables a and b are uninitialized and their value is undetermined by C language
int Array[a][b];
You declare an array which has [a,b] size. The problem is that a and b are undetermined and using them at this point is undefined behavior.
scanf("%d %d", &a, &b);
you get a and b values -- but the Array remains the same!
Simplest solution: try to put Array declaration after scanf. Your compiler may allow it (I think C99 is required to do so).
Variable length array is not supported in c89 standard.
int Array[a][b]; is meaningless. Because values of a and b is unknown at that time. so change it to Array[2][2].
Since your array size is not known at compile-time, you'll need to dynamically allocate the array after a and b are known.
like code as follows:
int **allocate_2D_array(int rows, int columns)
{
int k = 0;
int **array = malloc(rows * sizeof (int *) );
array[0] = malloc(columns * rows * sizeof (int) );
for (k=1; k < rows; k++)
{
array[k] = array[0] + columns*k;
bzero(array[k], columns * sizeof (int) );
}
bzero(array[0], columns * sizeof (int) );
return array;
}
Since your array size is not known at compile-time, you'll need to dynamically allocate the array after a and b are known.
Here's a link that describes how you can allocate the multi-dimensional array (really an array of arrays): http://www.eskimo.com/~scs/cclass/int/sx9b.html
Applying the example code from that link, you might do this:
int **Array; /* Instead of int Array[a][b] */
...
/* Create Array */
Array = malloc(a * sizeof(int *));
for(row = 0; row < a; row++)
{
Array[row] = malloc(b * sizeof(int));
for(column = 0; column <b; column++)
{
Array[row][column] = count;
count++;
}
}