Plain C - Array pointers - c

I have structure to hold pointer to array of input numbers. When I create matrix I also create default data array. As I suppose the m.data = data; means that m.data pointer points at first element of the array. When I print data right after alocation everything seems ok. But when I print them after in the main function the result is different.
Why does output differs(commented sections)?
#include <stdio.h>
#include <stdlib.h>
typedef struct matrix {
int *data;
int rows;
} Matrix;
//Create Matrix
extern Matrix create_matrix(int size)
{
int data[size * size];
int i = 0;
for(i = 0; i < size * size; i++)
{
data[i] = 0;
}
Matrix m;
m.data = data;
for(i = 0; i < size * size; i++)
{
printf("%d\n",*(m.data + i)); //<--- m.data {0,0 ..... ,0,0,0}
}
m.rows = size;
return m;
};
extern void supply_row_data(Matrix m, int row, int* data)
{
int i = 0;
for(i = 0; i < m.rows; i++)
{
m.data[i] = data[i];
}
};
int main(){
int size = 4;
Matrix m = create_matrix(size);
int i = 0;
int *j = m.data;
for(i = 0; i < size * size; i++)
{
//*(j + i) = i;
printf("%d\n", *(j + i));
}
getch();
}

int data[size * size];
This is a local variable (array) to the function create_matrix It goes out of scope when the function terminates.
m.data = data;
This does not copy the data in the variable data to the data in the variable m.data but rather sets the pointer m.data to the beginning of the array data. When the function returns, the Matrix returned contains what is called a dangling pointer: a pointer to data that no longer exists.
Use the advice from #RSahu to fix this.

That's not how you can copy the data from an array in C.
You need to:
Allocate memory for the data.
m.data = malloc(sizeof(int)*size*size);
Copy the data one element at a time or using memcpy.
memcpy(m.data, data, sizeof(int)*size*size);
Make sure you deallocate the memory allocated to hold the matrix data.
free(m.data);

You should avoid using pointer to local data once function return address of array is no loger valid try to allocate array in following way
int* allocate_vector(size_t elem, int value){
int* vec = (int *) calloc(elem, sizeof(int));
int i = 0;
for( ; i < elem; i++){
*(vec + i) = value;
}
return vec;
}

Related

Returning from a function with incompatible return type int **

I have an exam and the teacher want to do a problem. It sound like this.
a)Reading information about an array (the function returns a structure associated with an array)
b)Reading the elements of an array (the function receives as parameters two integers and a pointer to FILE and returns a pointer to pointer to integer)
the point a) is Matrix* infoM.
the point b) is int** readM
And I get an error with the returning type
enter code here
#include <stdio.h>
#include <stdlib.h>
typedef struct Matrix{
int rows;
int cols;
int** data;
}Matrix;
Matrix* infoM( int n_rows, int n_cols)
{Matrix Matrix;
int i;
Matrix.rows = n_rows;
Matrix.cols = n_cols;
Matrix.data = (int**)malloc(sizeof(int*) * n_rows);
if(Matrix.data == 0)
{
fprintf(stderr, "err");
exit(EXIT_FAILURE);
}
for(i=0;i<n_rows;i++)
{
*(Matrix.data+i) = (int*)malloc(sizeof(int)*n_cols);
if(*(Matrix.data+i) == 0)
{
fprintf(stderr,"err");
exit(EXIT_FAILURE);
}
}
struct Matrix *m;
m = &Matrix;
return m;
}
int** readM(int n_rows, int n_cols, FILE *in)
{
Matrix* matrix = infoM(n_rows,n_cols);
int i,j;
for(i=0; i<n_rows; i++)
{
for(j=0; j<n_cols; j++)
{
fscanf(in, "%d",*(matrix->data+i)+j);
}
}
return matrix;
}
I would use a flexible array member to remove double-pointer - and additional overhead (it removes one level of indirection). Additionally, it simplifies malloc/free (only one needed).
To access data use an array pointer.
typedef struct Matrix{
size_t rows;
size_t cols;
int data[];
}Matrix;
Matrix *createM(size_t rows, size_t cols)
{
Matrix *m = malloc(sizeof(*m) + cols * rows * sizeof(m -> data[0]));
return m;
}
Matrix *initM(Matrix *m)
{
int (*data)[m -> cols] = (int (*)[m -> cols])m -> data;
for(size_t row = 0; row < m -> rows; row++)
{
for(size_t col = 0; col < m -> cols; col++)
{
data[row][col] = rand();
}
}
return m;
}
Use correct types for sizes.
C has a notion of lifetime for variables. Automatic variables (declared in a block of function) reach their end of life at the end of the block (or function...) where they are declared in. And using an object passed its end of life explicetely invokes Undefined Behaviour (close to hell for C programmers).
For that reason you cannot return the address of a local variable. It is called a dangling pointer (Google that word for additional details...).
But C allows to return a whole structure. So a minimal modification of your code could be:
...
Matrix infoM( int n_rows, int n_cols)
{Matrix Matrix;
int i;
Matrix.rows = n_rows;
...
return Matrix;
}
Matrix readM(int n_rows, int n_cols, FILE* in)
{
Matrix matrix = infoM(n_rows, n_cols);
int i, j;
for (i = 0; i < n_rows; i++)
{
for (j = 0; j < n_cols; j++)
{
fscanf(in, "%d", matrix.data[i] + j); // more C idiomatic...
}
}
return matrix;
}
For the same reason, readM is not allowed to return a pointer inside a local object, because it would be a dangling pointer, but you can again return the struct itself.

Attempt to access elements of a 2d struct array failing

typedef struct{
unsigned long a;
unsigned long b;
unsigned long c;
} mini_struct;
struct ministruct** build_2Dstruct(unsigned long x, unsigned long y){
double x_squared = pow(2, x);
struct ministruct** temp = (mini_struct**)malloc(x*sizeof(mini_struct*));
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct*)malloc(y*sizeof(mini_struct));
for(int j = 0; j < y; j++){
temp[i][j].a = 0;
etc....
}
}
return temp;
}
In the code above I am trying to create a 2D array of ministructs**, with the whole struct being made out of 2^x ministructs*, and each ministruct* has y amount of ministructs.
aka:
x = 2,
y = 2,
[[struct, struct], [struct, struct], [struct, struct], [struct, struct]]
However, for some reason when I try to access the second element or index 1 of the struct inside each struct*, it says there is an error: "expression must be pointer to complete object".
I just do not understand why the code is not allowing me to access each individual element of the elements of the array?
Thanks
You are trying to make an x by y array of structs. So:
// create array of x pointers
mini_struct **temp = malloc(x*sizeof(mini_struct*));
for (int i=0; i<x; i++) {
// to array of y structs
temp[i] = malloc(y*sizeof(mini_struct));
for (int j=0; j < y; j++) {
temp[i][j].a = 0;
... etc.
Question is incomplete so I will be making asumptions.
You seem to be wanting to allocate a 2D array of structs and initialize all members to 0. Here is a possible solution:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
typedef struct mini_struct{
unsigned long a;
unsigned long b;
unsigned long c;
} mini_struct;
struct mini_struct** build_2Dstruct(unsigned long x, unsigned long y){
double x_squared = pow(x, 2);
mini_struct **temp = (mini_struct **) malloc(x_squared * sizeof(mini_struct*));
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct *) calloc(y, sizeof(mini_struct));
}
return temp;
}
int main () {
int x = 3;
int y = 4;
mini_struct **struct2D = build_2Dstruct(x, y);
int x_squared = pow(x,2);
for (int i = 0; i < x_squared; ++i) {
for (int j = 0; j < y; ++j) {
printf("Value of data stored at struct[%d][%d] is: %d\n", i, j, struct2D[i][j]);
}
}
for (int i = 0; i < x_squared; ++i) {
free(struct2D[i]);
}
free(struct2D);
}
As you can see, this contains the whole program, not just the snippet you showed. In this case, a main function would have been useful so that we don't have to guess what you want to do. My solution creates the 2D array with all elements initialized to 0 (you can use calloc to do that, no need for a second for loop).
Another important point is that, because the function returns a newly heap allocated 2D array, you need to free it to avoid a memory leak (end of main function).
You allocate x pointers to mini_struct:
mini_struct **temp = (mini_struct **) malloc(x_squared * sizeof(mini_struct*));
But then when you initialize them:
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct *) calloc(y, sizeof(mini_struct));
}
You index temp based on upto x_squared.
Consider if x is 2. You would allocate temp to be an array of two pointers to mini_struct. But then your for loop would attempt to initialize four elements in temp.

Returning a pointer to an array of structs

Let's say I have to create an array of structs that is allocated on the heap and return a pointer that points to this array of structs.
typedef struct Pair {
int x;
int y;
} Pair;
Pair** foo(int n, int m, int length)
{
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return &arr;
}
When I compile a program containing this function, it warns me that I am returning the address of a local variable. I assume this is because the pointer is initialised within the function (i.e. on the stack), therefore it counts as a local variable.
When I compile it, ignoring this warning, and run it anyway, the program crashes when the returned pointer is accessed.
I have tried allocating the pointer dynamically:
Pair** ptr = malloc(sizeof(**ptr));
ptr = &arr;
...
return ptr;
but the program still crashes when this pointer is accessed. How can I create this array within a function and return a pointer to this array so that it can be safely accessed?
This array is initialized on the stack but the pointer (arr) is a local variable, so the caller, main, cannot access it. You do not need to use the address of the pointer. You can access the array with the pointer itself.
Pair* foo(int n, int m, int length)
{
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return arr;
}
If you want an array of structs, the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
int y;
} Pair;
static Pair* foo(int n, int m, int length) {
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return arr;
}
int main(void) {
Pair *z = foo(111, 222, 3);
for (int i = 0; i < 3; ++i)
printf("z[%d]= { %d, %d }\n", i, z[i].x, z[i].y);
free(z);
return 0;
}
gives the output:
z[0]= { 111, 222 }
z[1]= { 112, 223 }
z[2]= { 113, 224 }
If you want an pointer to an array of structs, you can change your function signature from Pair** to be Pair*.
If you still want an pointer to an array of pointers, then allocate memory for a Pair struct for each index of arr.
for(int i = 0; i < length; ++i){
arr[i] = malloc(sizeof(Pair));
...
}
Instead of returning &arr, you can declare arr as
Pair** arr = malloc(sizeof(Pair*) * length);
Because arr is a local variable, it will be free when foo end. So you don't have access for arr after. To solve this you should declare array pointer in heap:
Pair** foo(int n, int m, int length)
{
Pair ** arr = (Pair**)malloc(sizeof(Pair*));
*arr = malloc(sizeof(Pair) * length);
for (int i = 0; i < length; ++i) {
(*arr)[i].x = n++;
(*arr)[i].y = m++;
}
return arr;
}

Function to initialize two dimensional array

I have a c program in which I want to initialize a 2 dimensional array.
So I made this function :
void initLayer(int **layer, int *dimensions) {
printf("initLayer\n");
layer = malloc(sizeof(int*) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++) {
layer[i] = malloc(sizeof(int) * dimensions[1]);
}
}
When I use this function there is no problem, but when I try to read the 2D array later I always get a segmentation fault.
I think it may be because the initialization made in the function are not saved when its finished.
Do you know how I could correct my function ? Thank you in advance.
To passing pointer to function you need one more pointer.
int **matrix; is an array of arrays, so to fill it you need to pass it as a pointer, which is int ***layer. but it is weird.
also for changing data by pointer you need to add a star * before it. *layer = ...
#include <stdlib.h>
void initLayer(int ***layer, int *dimensions)
{
*layer = malloc(sizeof(int *) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++)
{
*(*layer + i) = malloc(sizeof(int) * dimensions[1]);
}
}
int main()
{
int **matrix;
int dimensions[2] = { 4, 6 };
initLayer(&matrix, dimensions);
// then do whatever you want
for (int i = 0; i < dimensions[0]; i++)
{
for (int j = 0; j < dimensions[1]; j++)
{
matrix[i][j] = i * j;
}
}
}
as for me, better to use typedef to make code more readable:
#include <stdlib.h>
typedef int * Array;
typedef int ** Matrix;
void initLayer(Matrix *layer, Array dimensions)
{
*layer = malloc(sizeof(Array) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++)
{
(*layer)[i] = malloc(sizeof(int) * dimensions[1]);
}
}
int main()
{
Matrix matrix;
int dimensions[2] = { 4, 6 };
initLayer(&matrix, dimensions);
// then do whatever you want
for (int i = 0; i < dimensions[0]; i++)
{
for (int j = 0; j < dimensions[1]; j++)
{
matrix[i][j] = i * j;
}
}
}
When you call the function, the int **layer pointer is copied. So, when you do layer = malloc(...) what actually happens is the function sets its local copy to the malloc result. What you want is to mutate the variable which you called the function with. You can do this by taking a int ***layer and passing in &layer when calling initLayer. Note that you must then use *layer instead of layer in your code.
You have two approaches here:
to pass a reference to the double pointer (***int in this case)
or to return the allocated pointer as the result of your function:
in the first case:
void initLayer(int ***layer, int *dimensions) {
printf("initLayer\n");
*layer = malloc(sizeof(int*) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++) {
layer[i] = malloc(sizeof(int) * dimensions[1]);
}
}
you pass a reference to a pointer, instead of passing the (uninitialized) pointer. Remember, in C, all parameters are passed by value. In this case, you can call your function as:
...
int**vector;
...
initLayer(&vector, dims); /* you pass the address of your double pointer */
In the second case:
int** initLayer(int *dimensions) {
printf("initLayer\n");
int **layer = malloc(sizeof(int*) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++) {
layer[i] = malloc(sizeof(int) * dimensions[1]);
}
return layer;
}
in this case, you call it as:
...
int**vector;
...
vector = initLayer(dims); /* you receive your double pointer as a return value */

Allocating contiguous memory for a 3D array in C

I need to allocate contiguous space for a 3D array. (EDIT:) I GUESS I SHOULD HAVE MADE THIS CLEAR IN THE FIRST PLACE but in the actual production code, I will not know the dimensions of the array until run time. I provided them as constants in my toy code below just to keep things simple. I know the potential problems of insisting on contiguous space, but I just have to have it. I have seen how to do this for a 2D array, but apparently I don't understand how to extend the pattern to 3D. When I call the function to free up the memory, free_3d_arr, I get an error:
lowest lvl
mid lvl
a.out(2248,0x7fff72d37000) malloc: *** error for object 0x7fab1a403310: pointer being freed was not allocated
Would appreciate it if anyone could tell me what the fix is. Code is here:
#include <stdio.h>
#include <stdlib.h>
int ***calloc_3d_arr(int sizes[3]){
int ***a;
int i,j;
a = calloc(sizes[0],sizeof(int**));
a[0] = calloc(sizes[0]*sizes[1],sizeof(int*));
a[0][0] = calloc(sizes[0]*sizes[1]*sizes[2],sizeof(int));
for (j=0; j<sizes[0]; j++) {
a[j] = (int**)(a[0][0]+sizes[1]*sizes[2]*j);
for (i=0; i<sizes[1]; i++) {
a[j][i] = (int*)(a[j]) + sizes[2]*i;
}
}
return a;
}
void free_3d_arr(int ***arr) {
printf("lowest lvl\n");
free(arr[0][0]);
printf("mid lvl\n");
free(arr[0]); // <--- This is a problem line, apparently.
printf("highest lvl\n");
free(arr);
}
int main() {
int ***a;
int sz[] = {5,4,3};
int i,j,k;
a = calloc_3d_arr(sz);
// do stuff with a
free_3d_arr(a);
}
Since you are using C, I would suggest that you use real multidimensional arrays:
int (*a)[sz[1]][sz[2]] = calloc(sz[0], sizeof(*a));
This allocates contiguous storage for your 3D array. Note that the sizes can be dynamic since C99. You access this array exactly as you would with your pointer arrays:
for(int i = 0; i < sz[0]; i++) {
for(int j = 0; j < sz[1]; j++) {
for(int k = 0; k < sz[2]; k++) {
a[i][j][k] = 42;
}
}
}
However, there are no pointer arrays under the hood, the indexing is done by the magic of pointer arithmetic and array-pointer-decay. And since a single calloc() was used to allocate the thing, a single free() suffices to get rid of it:
free(a); //that's it.
You can do something like this:
int ***allocateLinearMemory(int x, int y, int z)
{
int *p = (int*) malloc(x * y * z * sizeof(int));
int ***q = (int***) malloc(x * sizeof(int**));
for (int i = 0; i < x; i++)
{
q[i] = (int**) malloc(y * sizeof(int*));
for (int j = 0; j < y; j++)
{
int idx = x*j + x*y*i;
q[i][j] = &p[idx];
}
}
return q;
}
void deallocateLinearMemory(int x, int ***q)
{
free(q[0][0]);
for(int i = 0; i < x; i++)
{
free(q[i]);
}
free(q);
}
I use it and works fine.

Resources