Accessing and setting array values within structs - c

I have a struct like this:
typedef struct {
int sizes[3];
float **vals[3]; // an array of size 3 of float ** pointers
} mystruct;
What I'm trying to do is set these array values in a function that takes a pointer to a mystruct.
void populateStruct(mystruct *s) {
int i, j, n;
for (n = 0; n < 3; n++) {
scanf("%d", &s->sizes[n]);
// Malloc the float pointers (**vals) based on the scanned sizes
s->vals[n] = (float **)malloc(s->sizes[n] * sizeof(float *));
for (i = 0; i < s->sizes[n]; i++)
s->vals[n][i] = (float *)malloc(s->sizes[n] * sizeof(float));
// Populate the float "arrays"
for (i = 0; i < s->sizes[n]; i++) {
for (j = 0; j < s->sizes[n]; j++) {
scanf("%f", &s->vals[n][i][j]);
}
}
}
}
Here is how I'm using the function in main:
int main() {
mystruct *s1;
populateStructure(s1);
return 0;
}
This code compiles fine, but I get a seg fault when I run it. C is not a strong point of mine, so I'm not too sure what I'm doing wrong.

How are you declaring your s structure and how are you passing it?
In your function where you call populateStruct you should probably declare s:
as mystruct s and call populateStruct(&s)
or
mystruct *s;
s = malloc(sizeof(mystruct));
populateStruct(s);

mystruct *s1;
s1 is only a pointer with unpredictable value. You didn't allocate memory for the struct you need.
Dereferencing a wild (uninitialized) pointer would cause segv.
You can modify your code to either:
mystruct s1;
populateStructure(&s1);
or
mystruct *s1 = (mystruct *)malloc(sizeof(mystruct));
populateStructure(s1);
( don't forget to free s1 in the second one)

Related

Accessing a 2D array which is returned as a pointer in C

I'm trying to return a 2D array from a function. I've tried some ways mentioned in some websites. But they are helpless. So finally I'd assigned a pointer to the 2D array and returned it from the function. And the sample function's code is given below
float *test(int *x, int *y)
{
static float res[2][3];
float[] temp = {1,2,3};
for(int i=0;i<3;i++) res[0][i] = temp[i];
for(int i=0;i<3;i++) res[1][i] = temp[i]*-1;
float *ptr = &res[0][0];
return ptr;
}
Now I have a problem that how to access this 2D array in main function to print all of it's elements.
Could anyone give a solution? Thanks in advance:)
You have to go through dynamic allocation malloc is used for this.
Consider this code:
float **result = NULL; // if you want to return 2D array you need double pointer
result = (float **)malloc(2 * sizeof(float *)); // allocating assuming that the allocating will not fail otherwise it return NULL
for(int i = 0; i < 2; i++)
result[i] = (float *)malloc(3 * sizeof(float));
for(int i = 0; i < 3; i++) result[0][i] = i;
for(int i = 0; i < 3; i++) result[1][i] = i * -1;
return result;
Important part is also in main function where you should deallocate the memory to prevent memory leak. Is's done through free function and you should do this revere to the allocation to free all the memory you allocated.
for(int i=0;i<3;i++) free(result[i]); //done in main
free(result);
Declare the return type of your function properly, then just return the static array:
float (*test(int *x, int *y))[3]
{
static float res[2][3];
float temp[] = {1,2,3};
for(int i=0;i<3;i++) res[0][i] = temp[i];
for(int i=0;i<3;i++) res[1][i] = temp[i]*-1;
return res;
}
Note that returning a static array has the problem that all calls to the function will (re)use that same array, so the second call will clobber the array returned by the first call. You could instead malloc the array:
float (*test(int *x, int *y))[3]
{
float (*res)[3] = malloc(2 * sizeof *res);
float temp[] = {1,2,3};
for(int i=0;i<3;i++) res[0][i] = temp[i];
for(int i=0;i<3;i++) res[1][i] = temp[i]*-1;
return res;
}
but then the caller will need to remember to call free on the returned pointer when it is no longer needed.
You could return a pointer to static variable:
char (*modify(char input))[3]
{
static char variable[3][3];
variable[0][0] = input;
variable[1][1] = input+1;
return variable;
}
int main() {
char (*result)[3] = modify(a);
}
However, this is not a reentrant function. Another option is using dynamic memory (i.e. malloc), but memory leaks are quite common when returning pointers to allocated memory.
Another approach it's to pass the array to the function, already allocated, so you don't have to be worried about releasing memory or using statics:
void modify(char variable[][3], char input) {
variable[0][0] = input;
variable[1][1] = input+1;
}
int main(void) {
char result[3][3];
modify(result,a);
}
A better approach it's to create a typedef to highlight the purpose, length and making easier working with it:
typedef struct { char x[3][3]; } my2D_t;
void modify(my2D_t *variable, char input) {
variable->x[0][0] = input;
variable->x[1][1] = input+1;
}
int main() {
my2D_t result;
char a = 1;
modify(&result,a);
}
Also returning by value as tstanisl noticed. It creates another my2D_t, but the compiler will probably end up with something similar to the previous idea for the sake of optimization known as the "as-if" rule:
typedef struct { char x[3][3]; } my2D_t;
my2D_t modify(char input) {
my2D_t variable;
variable.x[0][0] = input;
variable.x[1][1] = input+1;
return variable;
}
int main() {
char a = 1;
my2D_t result = modify(a);
}

Passing array of structs with reference - segmentation fault

#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X** a, int size){
for (int i = 0;i < size; i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container = (struct X*)malloc(sizeof(struct X) * n);
read_record(&container, n);
}
I created a 1D array of size n, then I passed it by reference to the function read_record. However, when I execute the program, there is a segmentation fault. What is the problem?
EDIT:
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. That's why I want to send the array as a reference. If I did it in main then I would write:
container = realloc(container, (n + 10) * sizeof(Struct X));
How can I do this in the function?
container is already a pointer, you don't need to pass the address-of the pointer, instead:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X *a, size_t size)
{
for (size_t i = 0; i < size; i++) {
a[i].deg = 0;
}
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
read_record(container, n);
}
also, prefer size_t to store the number of allocated objects.
Nitpick: read_record doesn't seem a good name for a function that modifies the contents of the records.
EDIT: As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
Same approach but returning a reallocated container:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
struct X *read_record(struct X *a, size_t size)
{
struct X *new = realloc(a, sizeof(struct X) * size);
if (new != NULL)
{
for (size_t i = 0; i < size; i++) {
new[i].deg = 0;
}
}
return new;
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
container = read_record(container, n * 2);
if (container == NULL)
{
fprintf(stderr, "Can't read record\n");
exit(EXIT_FAILURE);
}
}
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
The pointer is passed by value, so to save the changes and have them usable outside the function scope, after the function ends, i.e. in main, a pointer to pointer must be the argument, and the address of the pointer must be passed, your overall assessment is correct.
Your implementation, however, is not correct, here's how you shoud do it:
Live demo
void read_record(struct X **a, int size) //double pointer
{
*a = realloc(*a, sizeof **a * (size + 10)); //reallocate memory for 20 ints
if (*a == NULL)
{
perror("malloc");
}
for (int i = 0; i < size + 10; i++) //assing new values
{
(*a)[i].deg = 1;
}
}
int main()
{
int n = 10;
struct X *container = malloc(sizeof *container * n); //original allocation
//the pointer now has space for 10 ints
if (container == NULL)
{ //check allocation errors
perror("malloc");
}
for (int i = 0; i < n; i++) //assign values
{
container[i].deg = 0;
}
read_record(&container, n); //pass by reference
//the pointer now has space for 20 ints
}
Alternatively you can return the pointer instead, refering to David Ranieri's answer.
The first function parameter has the pointer to pointer type struct X**. So dereferencing the parameter a you will get a pointer of the type struct X*. Now you may apply the subscript operator that yields lvalue of the type struct X..
That is the function definition will look like
void read_record(struct X** a,int size){
for (int i=0;i<size;i++){
( *a )[i].deg = 0;
}
}
Or this statement
( *a )[i].deg = 0;
may be substituted for this statement
a[0][i].deg = 0;
On the other hand, there is no great sense to declare the first parameter as having the type struct X**. The function can look simpler as for example
void read_record(struct X* a,int size){
for (int i=0;i<size;i++){
a[i].deg = 0;
}
}
and be called like
read_record( container, n );
When you call read_record you pass a pointer to a pointer to the first element of an array of X structures.
But inside the read_record you treat it as a pointer to the first element of an array of pointers to X structures (i.e. as an array of pointers to X). There's a subtle but very important difference here.
If you want to emulate pass-by-reference for the pointer variable, you need to dereference it inside the read_record to get the original pointer (and remember that then you have an array of objects, not pointers):
(*a)[i].deg = 0;
Double pointer is the problem. The code should be:
void read_record(struct X* a,int size){ // Check the change
for (int i=0;i<size;i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container=(struct X*)malloc(sizeof(struct X)*n);
read_record(container,n); // Check the change
}

Returning multidimensional arrays from a function in C

What is the best way to return a multidimensional array from a function in c ?
Say we need to generate a multidimensional array in a function and call it in main, is it best to wrap it in a struct or just return a pointer to memory on the heap ?
int *create_array(int rows, int columns){
int array[rows][columns] = {0};
return array;
}
int main(){
int row = 10;
int columns = 2;
create_array(row,columns);
}
The code above, is just to sketch out the basic program I have in mind.
This is wrong:
int *create_array(int rows, int columns){
int array[rows][columns] = {0};
return array;
}
and should produce a warning like this:
prog.c:2:6: note: (near initialization for 'array')
prog.c:3:13: warning: return from incompatible pointer type [-Wincompatible-pointer-types]
return array;
^~~~~
prog.c:3:13: warning: function returns address of local variable [-Wreturn-local-addr]
since you are returning the address of an automatic variable; its lifetime ends when its corresponding function terminates.
You should either declare a double pointer in main(), pass it through the function, dynamically allocate memory for it and return that pointer. Or you could create the array in main() and pass the double pointer to the function.
I want to know ways to allocate multidimensional arrays on the heap and pass them around
For allocating memory on the heap you could use one of these two methods, which involve pointers:
#include <stdio.h>
#include <stdlib.h>
// We return the pointer
int **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i, **array;
array = malloc(N*sizeof(int *));
for(i = 0 ; i < N ; i++)
array[i] = malloc( M*sizeof(int) );
return array;
}
// We don't return the pointer
void getNoReturn(int*** array, int N, int M) {
/* Check if allocation succeeded. (check for NULL pointer) */
int i;
*array = malloc(N*sizeof(int *));
for(i = 0 ; i < N ; i++)
(*array)[i] = malloc( M*sizeof(int) );
}
void fill(int** p, int N, int M) {
int i, j;
for(i = 0 ; i < N ; i++)
for(j = 0 ; j < M ; j++)
p[i][j] = j;
}
void print(int** p, int N, int M) {
int i, j;
for(i = 0 ; i < N ; i++)
for(j = 0 ; j < M ; j++)
printf("array[%d][%d] = %d\n", i, j, p[i][j]);
}
void freeArray(int** p, int N) {
int i;
for(i = 0 ; i < N ; i++)
free(p[i]);
free(p);
}
int main(void)
{
int **p;
//getNoReturn(&p, 2, 5);
p = get(2, 5);
fill(p ,2, 5);
print(p, 2, 5);
freeArray(p ,2);
return 0;
}
Pick whichever suits best your style.
What is the best way to return a multidimensional array from a function in c ?
My recommendation is to avoid doing that, and avoid multidimensional arrays in C (they are unreadable and troublesome).
I would recommend making your matrix type your proper abstract data type, represented by some struct ending with a flexible array member:
struct mymatrix_st {
unsigned nbrows, nbcolumns;
int values[];
};
Here is the creation function (returning a properly initialized pointer to dynamic memory):
struct mymatrix_st*
create_matrix(unsigned mnbrows, unsigned mnbcolumns) {
if (mnbrows > UINT_MAX/4 || mnbcolumns > UINT_MAX/4
||(unsigned long)mnbrows * (unsigned long)mnbcolums
> UINT_MAX) {
fprintf(stderr, "too big matrix\n");
exit(EXIT_FAILURE);
};
size_t sz = sizeof(struct mymatrix_st)+(mnbrows*mnbcolumns*sizeof(int));
struct mymatrix_st*m = malloc(sz);
if (!m) {
perror("malloc mymatrix"); exit(EXIT_FAILURE); };
m->nbrows = mnbrows;
m->nbcolumns = mnbcolumns;
for (unsigned long ix=(unsigned long)mnbrows * (unsigned long)mnbcolumns-1;
ix>=0; ix--)
m->values[ix] = 0;
return m;;
} /*end create_matrix*/
It is on purpose that struct mymatrix_st don't contain any interior pointer. You can and should use free to destroy it.
Here is the accessor function; make it a static inline function and define it in the same header declaring struct mymatrix_st and create_matrix, e.g.
static inline int getmatrix(struct mymatrix_st*m, unsigned row, unsigned col) {
if (!m) {
fprintf(stderr, "getmatrix with no matrix\n");
exit(EXIT_FAILURE);
};
if (row >= m->nbrows || col >= m->nbcolumns){
fprintf(stderr, "getmatrix out of bounds\n");
exit(EXIT_FAILURE);
};
return m->values[row*m->nbcolumns + col];
}
I leave up to you to define and implement the other operations on your abstract struct mymatrix_st type.
(you could adapt the code, perhaps removing the out of bound check, but I don't recommend unsafe code)
int** create_array(int rows, int columns){
int** array = malloc(rows * sizeof(int*));
int i;
for (i=0; i<rows; i++)
array[i] = malloc(columns * sizeof(int));
return array;
}
should do the trick. If you use int array[rows][columns]; then it's dead as soon as the functiom returns, and you get a UB. You should at least use dynamic memory allocation.
You can't return an array, but you can return a regular pointer and document that the callee may treat it as a pointer to a multidimensional array of the dimensions that it had passed to the caller.
(Note that the returned pointer must point to dynamic or static, but not automatic memory--don't return pointers to local variables!)
It takes some slightly wordy casts and possibly a macro but it's doable:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void*
multi(int R, int C)
{
return calloc ( 1, sizeof(int[R][C]) ); //or sizeof(int)*R*C
}
int main()
{
int (*r_)[3][4] = multi(3,4);
if(!r_) return EXIT_FAILURE;
#define r (*r_)
//emulate C++ a reference -- r now behaves as an `int r[3][4];`
//Test that addresses advance as they would in a multi-d array
int local[3][4];
assert(&local[1][0]-&local[0][0] == 4); //base example
assert(&r[1][0]-&r[0][0] == 4); //"returned" multi-d array
free(r); //or free(&r) or free(r_) -- here it shouldn't matter
#undef r
return 0;
}
Note that an array of pointers is not the same thing as a multi-d array.
A true multi-d array is one contiguous block, whereas an array of pointers (though usable with the same indexing syntax) has much worse locality of reference, so this might be preferable over returning pointers to pointers if you want better performance.

Seg fault when assigning a dynamically allocated 2D array to a double pointer within a struct

I am creating a game with a 2d array as the board. Originally, I tried to dynamically allocate the board to the struct in one function, but figured I would create the board, and then assign this newly created board to the double point within the struct.
This is my declaration of the struct. When I run my create board function, everything works out, but when I print to it there is a seg fault, so I am going to assume I haven't allocated enough space and there is an issue with my pointers.
typedef struct Game_State{
int num_rows;
int num_cols;
int num_mines;
char** board;
char MINE;
char hidden_tile;
char marked_tile;
char flagged_tile;
char revealed_tile;
}game;
This is the code I used to create a dynamically allocated board depending on the command line arguments of rows and columns, yet when I print the board, there is a segmentation fault!
void create_board(struct Game_State game){
//intitialization
int i;
int j;
int num_rows = game.num_rows;
int num_cols = game.num_cols;
char hidden_tile = game.hidden_tile;
char** board;
printf("Create Board Rows: %d\n", num_rows);
printf("Create Board Cols: %d\n", num_cols);
printf("Create Board Hidden Tile: %c\n", hidden_tile);
//dynamically allocates space for the board (2x2)
board =(char**) malloc(num_rows *sizeof(char*));
for(i = 0; i < num_rows; ++i){//for each row
board[i] = (char*) malloc(num_cols * sizeof(char));
for(j = 0; j < num_cols; ++j){
board[i][j] = hidden_tile;
}
}
game.board=board;
}
UPDATE
I believe our segmentation fault is coming from our printboard function, we try to print the board with headers. I used this exact code for another function with success, so I think maybe I'm accessing my board wrong?
void print_board(struct Game_State game){//defines print board function
//intitializations
int i = 0;
int j = 0;
int k = 0;
int num_row_val = game.num_rows;
int l = num_row_val;
int num_col_val = game.num_cols;
char** board =game.board
printf("%d\n", num_row_val);
printf("%d\n", num_col_val);
printf("%d\n", l);
while(l > 0){
for(i = 0; i < num_row_val; ++i){
printf("%d " , (l - 1));//prints row headers
for(j = 0; j < num_col_val; ++j){//prints board
printf("%c ",game.board[i][j]);
}
printf("\n");
--l;
}
}
for(k = 0; k < num_col_val; ++k){//prints column header
printf(" %d" , k);
}
printf("\n");
}
When you pass a struct Game_State to a function, you are passing a copy of the variable. More specifically, the .board member of the game variable inside create_board() is a copy of the .board member of the variable that was passed to the function.
So when you return from the create_board() function, the game variable ceases to exist and the only pointer you had to the allocated memory is irretrievably lost. The .board member of the variable that was passed to the function remains uninitialized and, unsurprisingly, your program crashes inside print_board().
Whenever you need to modify a Game_State structure inside a function, you will need to pass a pointer to struct Game_State:
void create_board (struct Game_State *game) { /* Pointer to Game_State */
...
}
int main (void) {
struct Game_State g;
create_board (&g); /* Address of g. */
...
}
You will also have to access the struct members inside create_board() differently. These lines:
int num_rows = game.num_rows;
int num_cols = game.num_cols;
char hidden_tile = game.hidden_tile;
...
game.board=board;
should be changed to:
int num_rows = game->num_rows;
int num_cols = game->num_cols;
char hidden_tile = game->hidden_tile;
...
game->board=board;
which is shorthand for:
int num_rows = (*game).num_rows;
int num_cols = (*game).num_cols;
char hidden_tile = (*game).hidden_tile;
...
(*game).board=board;

Passing a double array by reference in C : Bus error 10

#include <stdio.h>
#include <stdlib.h>
void setZero (double **, int);
int main (void) {
double *ptr = NULL;
int i, size = 3;
ptr = (double *)malloc(size * sizeof(double));
//*
setZero(&ptr, size);
/*/
// Sanity test
for ( i = 0 ; i < size ; ++i ) {
printf("index %d/%d\n", i, (size-1));
ptr[i] = 0; // NOT EXPLODING...
}
//*/
free(ptr);
return 0;
}
void setZero (double **_ref_array, int _size) {
int i;
for ( i = 0 ; i < _size; ++i ) {
printf("index %d/%d\n", i, (_size-1));
*_ref_array[i] = 0; // EXPLODING...
}
}
1) Why is this not working?
2) What is a "Bus error 10"
P.S. I know better than to initialize an array this way, but this just happens to be a simple and clean example of an underlying concept that I'm not understanding...
The dereference is happening after the index. I.e.
This says "Get the double pointer at index 'i', then set the value 0 to the memory at the address within that pointer."
*_ref_array[i] = 0;
This says "Get the address of the array of doubles from _ref_array, than index off that address by i-doubles.
(*_ref_array)[i] = 0;
On the face of the code given, you don't need to pass the address of the pointer to the function. You should be using:
void setZero(double *ptr, int size)
{
for (int i = 0; i < size; i++)
ptr[i] = 0.0;
}
and:
setZero(ptr, size);
The trouble you've got is as WhozCraig says:
*_array_ref[i]
is interpreted as:
*(_array_ref[i])
instead of:
(*_array_ref)[i]
as you need it to be. The former is trampling up the stack; the latter is initializing the allocated memory.
If you really must pass a pointer to a pointer to the function, then you can either wrap parentheses around the dereferences, or you can assign a local pointer and use that normally, right up to the point where you need to make use of the double pointer to change the value in the calling function.
void setZero(double **ptr, int size)
{
double *base = *ptr;
for (int i = 0; i < size; i++)
{
base[i] = 0.0;
// Or: (*ptr)[i] = 0.0;
}
...presumably some code here needs to assign to *ptr...
...if there is no such code, there is no need of the double pointer...
}

Resources