passing back values from array in struct by ref - c

struct myStruct
{
int* arr;
int size;
};
void get_back(struct myStruct* my ,int* arr, int* size)
{
arr = my->arr;
*size = my->size;
}
int main()
{
struct myStruct my;
my.arr = (int*) malloc(3 * sizeof(int));
my.arr[0] = 20;
my.arr[1] = 200;
my.arr[2] = 2000;
my.size = 3;
int* ret_arr = NULL;
int size;
get_back(&my, ret_arr, &size);
free(my.arr);
return 1;
}
The goal of my simple program is to get back the values from my.arr into ret_arr, since ret_arr=nullptr, do I need to allocate the memory and than copy it into the array inside get_back function?
or I can just point to the existing array inside "my" struct?
This is my current solution, I copy the values.
struct myStruct
{
int* arr;
int size;
};
int* get_back(struct myStruct* my , int* size)
{
int *arr = (int*)malloc(3 * sizeof(int));
for (int i = 0; i < my->size; i++)
{
arr[i] = my->arr[i];
}
*size = my->size;
return arr;
}
int main()
{
myStruct my;
my.arr = (int*) malloc(3 * sizeof(int));
my.arr[0] = 20;
my.arr[1] = 200;
my.arr[2] = 2000;
my.size = 3;
int* ret_arr = NULL;
int size;
ret_arr = get_back(&my, &size);
free(my.arr);
free(ret_arr);
return 1;
}

Seeing as you're freeing the array, you probably want to copy the contents over with memcpy (from string.h).
You will also need to include stdlib.h for malloc.
#include <string.h>
#include <stdlib.h>
// Struct definition goes here
void get_back(struct myStruct* my, int** arr, int* size)
{
*arr=malloc(my->size*sizeof(int)); //Allocate space for integers
memcpy(*arr, my->arr, my->size*sizeof(int)); //Copy integers to new array
*size=my->size;
}
The function needs to take a pointer to the pointer in order to be able to modify it.
Additionally, your main function will need to be modified too.
int main()
{
struct myStruct my; // Structs are not types.
my.arr = (int*) malloc(3 * sizeof(int));
my.arr[0] = 20;
my.arr[1] = 200;
my.arr[2] = 2000;
my.size = 3;
int* ret_arr = NULL;
int size;
get_back(&my, &ret_arr, &size); //Need to pass ret_arr by reference
free(my.arr);
return 1;
}

Use std::vector, it's very comfortable and has many useful algorithms, there is std::copy function to copy from one vector to another, take a look at your task with a help of vectors:
#include <vector>
#include <iostream>
struct myStruct
{
std::vector<int> arr;
};
int main()
{
myStruct my;
my.arr.push_back(20);
my.arr.push_back(200);
my.arr.push_back(2000);
std::vector<int> ret_arr;
std::copy(my.arr.begin(), my.arr.end(), std::back_inserter(ret_arr));
return 1;
}
And the result is on screen:
If you want to use C language then you should pass pointer on pointer(int** arr) to get right pointing after leaving scope. I will show two methods, first just to point on already allocated memory:
void get_back_pointers(myStruct* my ,int** arr, int* size)
{
*arr = my->arr;
*size = my->size;
}
Other is for deep copy, to allocate new array and copy data to it:
void get_back_copy(myStruct* my ,int** arr, int& size)
{
*arr = (int*) malloc(3 * sizeof(int));
memcpy( *arr, my->arr, my->size * sizeof(int) );
size = my->size;
}
After get_back_copy passed arr will be needed to free its memory. In debugger you can see results that my.arr and ret_arr have one address but ret_arr2 has another because it's allocated in new memory:

Related

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
}

Expand a C array inside a function

This works in a main, but breaks when put into a function. I'm not sure how to reassign the pointer after passing into a function.
void expandArray(int** arr[], int* size) {
int *temp;
*temp = *arr;
*arr = (int*) malloc(*size * 2 * sizeof(int));
for (int i = 0; i < *size; i++) {
printf("assigning from temp: %d ", temp[i]);
arr[i] = temp[i];
printf("to arr: %d \n", arr[i]);
}
*size = *size * 2;
free(temp);
}
main(){
int *arr;
arr = (int*) malloc(maxSize * sizeof(int));
if ....
expandArray(arr, &arrSize);
// use bigger arr for other stuff
}
In main, arr is declared as int *arr. When main calls expandArray, it should pass a pointer to arr, which is written &arr and has type int **a.
However, you declared the parameter to expandArray as int **arr[], adding additional brackets. Those are unnecessary and change the type, and your compiler should have warned you about that. Pay attention to compiler warnings. Be sure you understand them, and resolve them before proceeding.
In expandArray, you use both arr[i] and temp[i] to access the array. However, arr[i] is not a correct way to access array elements. When the declaration of the arr parameter is corrected, it will be int **arr, and it will not be proper to refer to an element of the array as arr[i]. It will be (*arr)[i].
Commonly, to make this a little less confusion, authors will use a temporary variable to hold the pointer, so they do not need the extra asterisk:
int *NewArray = malloc(...); // Get new space.
*arr = NewArray; // Send new address to caller.
...
NewArray[i] = temp[i]; // Use temporary variable for access.
Some other points:
When calling malloc, use sizeof *p, where p is the pointer being assigned to, rather than sizeof(int). This is better because, if you later want to change the type for p, it only has to be changed in its declaration, not also in the sizeof. Then there is less likely to be a mistake where it is changed in one place and not another.
Do not cast the result of malloc. This is unnecessary in C, although it is required in C++.
main should be declared as int main(void) or int main(int argc, char *argv[]), not as main(). (C implementations may also provide for other forms.)
Use size_t for sizes of arrays, not int, and either size_t or ptrdiff_t for indices of arrays.
Overall, the code could be:
#include <stdio.h>
#include <stdlib.h>
void expandArray(int **arr, int *size)
{
// Record old pointer and size in temporary variables for convenience.
int *OldArray = arr;
size_t OldSize = *size;
// Prepare new size and pointer.
size_t NewSize = 2 * OldSize;
int *NewArray = malloc(NewSize * sizeof *NewArray);
// Handle allocation failure.
if (!NewArray)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
// Copy data from old array to new array.
for (size_t i = 0; i < OldSize; ++i)
NewArray[i] = OldArray[i];
// Send new size and pointer to caller.
*size = NewSize;
*arr = NewArray;
// Release old memory.
free(OldArray);
}
int main(void)
{
int *arr;
arr = malloc(InitialSize * sizeof *arr);
if (...)
expandArray(&arr, &arrSize);
// use bigger arr for other stuff
}
I think the arr sould be int ** type.
void expandArray(int** arr, int* size) {
int *temp;
temp = *arr;
*arr = (int*) malloc(*size * 2 * sizeof(int));
for (int i = 0; i < *size; i++) {
printf("assigning from temp: %d ", temp[i]);
(*arr)[i] = temp[i];
printf("to arr: %d \n", (*arr)[i]);
}
*size = *size * 2;
free(temp);
}
If you just want to expand the array size, you can use realloc.
And the extended area should be initialized using memset.
void expandArray(int** arr, int* size) {
*arr = (int*) realloc(*arr, *size * 2 * sizeof(int));
memset(*arr+*size, 0, *size * sizeof(int));
*size = *size * 2;
}

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

C: Having a pointer to pointer in main and create an array in other function

I have code like:
#include <stdio.h>
#include <stdlib.h>
void mad(int ***, int, in);
int main(void) {
int **x;
int n,m;
scanf("%d%d",&n,&m);
mad(x,n,m);
x[0][0] = 5;
printf("%d\n",x[0][0]);
return 0;
}
void mad(int ***x, int n, int m) {
int i;
**x = malloc(sizeof(int *));
for (i = 0; i < n; i++)
***(x + i) = malloc(m * sizeof(int));
}
This is wrong can someone explain why this is wrong and help me to get it right.
You need to have a variable which is a pointer to a pointer, so declare it as such:
int **x;
but if you want another function to assign it a value, you need to pass a pointer to that variable, so declare a function as
void mad(int ***x,int n, int m);
call it with passing a pointer to the variable:
mad(&x,m,n);
and assign a new value to the dereferenced pointer
void mad(int ***x,int n, int m)
{
*x = malloc(...);
}
BTW, the first malloc call seems incorrect – you allocate the block of memory big enough to keep a single pointer to int while it probably should be n pointers to int:
*x = malloc(n*sizeof(int *));
Then allocate your n array's rows, each m ints long:
for (i=0; i<n; i++)
*(*x + i) = malloc(m*sizeof(int));
*x ìs an pointer to a pointer to an array. malloc(n * sizeof(int*)); allocates an array of pointers. *(*x+i) or (*x)[i] is an array. malloc(m * sizeof(int)); allocates an array. Adapt your code like this:
void mad(int ***x, int n, int m){
int i;
*x = malloc(n * sizeof(int*)); // allocate memory where x refers to
for( i=0; i<n; i++ )
*(*x+i) = malloc(m * sizeof(int)); // similar to (*x)[i] = malloc(m * sizeof(int))
}
mad(&x,n,m);
// ^
You should avoid all of those inefficient pointer-to-pointer based lookup tables. They are not arrays since they are not allocated in adjacent memory cells.
Allocate a real 2D array instead:
void alloc2d ( size_t x, size_t y, int(**ptr)[x][y] )
{
*ptr = malloc ( sizeof(int[x][y]) );
}
int main (void)
{
const int x = 5;
const int y = 3;
int (*arr_ptr)[x][y];
alloc2d(x, y, &arr_ptr);
int (*array2d)[y] = *arr_ptr; // point at 1st element which is an array
array2d[i][j] = something;
...
free(arr_ptr);
}

write a code for the following function using struct pointers and array

I am new to C programming. Can any body tell me how can I do the coding for the term in bold?
create a structure called arrayData that contains an integer pointer called array and an integer variable called size.
create a function with the following header: arrayData* createArray(int size). Inside this function you will malloc space for a new arrayData structure. You will then need to create an array using the input variable as the number of elements. Finally you will need to set the variables in the malloc'ed arrayData pointer equal to the array and the array size. Finally return the pointer of malloc'ed arrayData structure.
I have tried something like:
#include<stdio.h>
struct arrayData
{
int *array;
int size;
}
struct arrayData* createArray(int size)
{
struct arrayData *str = (struct arrayData*)malloc(sizeof(struct arrayData));
int a = 10;
int arr[a];
for ( a = 0; a < 10; a++ )
{
str->arr[i] = a;
}
return str;
}
int arr[a]; is allocated locally inside the function and will be destroyed when the function returns. You should dynamically allocate str->array for proper allocation.
struct arrayData* createArray(int size)
{
struct arrayData *str = malloc(sizeof(struct arrayData));
int a = 10;
str->array = malloc(size * sizeof(int));
str->size = size;
for ( a = 0; a < 10; a++ )
{
str->array[i] = a;
}
return str;
}
Just a few changes for allocating size and array
struct arrayData* createArray(int size)
{
struct arrayData *str = (struct arrayData*)malloc(sizeof(struct arrayData));
int a = 10;
//int arr[size]; // array should be of size provided
int *arr = (int*)malloc(size * sizeof(int));
str->size = size; // you should assign size to structure variable
for ( a = 0; a < 10; a++ )
{
arr[i] = a;
}
str->array = arr; // you should point the array in structure to the
// integer arr which you created
return str;
}

Resources