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

#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...
}

Related

In C - Can I initialize an array (and set the size) from within a function?

I am trying to pass a pointer to a funcion, and in that function create an array, and set the passed pointer to that array.
What I'm trying to do is create an array inside the function and then use that array outside the funcion.
void createArray(int *myPointer)
{
int intArray[20];
*myPointer = &intArray[0]; // This line gets error:
// assignment makes integer from pointer without a cast [-Wint-conversion]
for (int i = 0; i < 20; i++)
{
intArray[i] = i + 10;
}
}
int main(void)
{
int *intPointer;
createArray(&intPointer);
for (int i = 0; i < 20; i++)
{
printf("%d : %d \n", i, intPointer[i]);
}
return 0;
}
You meant to use
void createArray(int **myPointer)
That will resolve the two type errors.
But that will make main's pointer point to a variable that no longer exists after createArray returns. That's bad. And that's why you have to use malloc instead of automatic storage.
void createArray( int **myPointer ) {
int *intArray = malloc( 20 * sizeof(int) );
*myPointer = intArray; // Same as `&intArray[0]`
if ( !intArray )
return;
for ( int i = 0; i < 20; i++ )
intArray[i] = i + 10;
}
int main(void) {
int *intPointer;
createArray(&intPointer);
if ( intPointer ) {
perror( NULL );
exit( 1 );
}
for (int i = 0; i < 20; i++)
printf( "%d: %d\n", i, intPointer[i] );
return 0;
}
The reason for the compiler error is the *myPointer dereferencing, which gives you the content of type int that the pointer points at. The compiler is saying that you can't assign the pointer &intArray[0] to a plain int.
Besides being invalid C, it wouldn't change where the pointer points. To do that, you would have to do myPointer = &intArray[0];. However, in this case you can't do that either because the myPointer is just a local pointer variable inside the function - a local copy of the pointer you passed. You need a way to update the pointer in main().
Furthermore, we can never return a pointer to local data (data with "automatic storage duration") because that data ceases to be valid as soon as we leave the function.
The normal solution is to create dynamically allocated memory instead, since such memory persists throughout the execution of the program (or until you explicitly free it). There are two different ways to write a function for that:
#include <stdlib.h> // for malloc
int* createArray (void)
{
int* result = malloc(20 * sizeof(*result));
if(result == NULL)
return NULL; // some error handling will be required here
for (int i = 0; i < 20; i++)
{
result[i] = i + 10;
}
return result;
}
...
int *intPointer = createArray();
...
free(intPointer);
Alternatively you could pass the pointer itself by value, so that by doing the *myPointer = ...; assignment, you refer to where a int** points at:
#include <stdlib.h> // for malloc
void createArray (int** myPointer)
{
int* result;
result = malloc(20 * sizeof(*result));
if(result == NULL)
{
/* some error handling will be required here */
}
for (int i = 0; i < 20; i++)
{
result[i] = i + 10;
}
*myPointer = result;
}
...
int *intPointer;
createArray(&intPointer);
...
free(intPointer);
Either of these are ok and which one you use is mostly a matter of design. It's easier syntax to have the pointer returned, but then normally the return of functions is reserved for some error code.

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
}

C, Why does my custom free function give me the "pointer being freed was not allocated" error

I am trying to dynamically allocate an array, put some data in it, and then free it and set the array pointer to null so that it can not be accessed in the future. Also, unrelated, but I am storing the size of the array in the first element and then passing it back indexed one up, it is part of the assignment, so hopefully that doesn't confuse anyone.
If I am understanding the error correctly, I am trying to call free() on the array that my malloc'ed array was copied in to. This is not allowed because free() is not being called on the actual malloc'ed array but rather the one that's holding its values.
If this is the case, how would I fix my call of free() to only receive an array address and dereference it like free(*array);. Right now I have some mess of asteriscs and a cast and I have no idea why it works. If you know how to fix the free call into the above or just explain why what I have now works, I would greatly appreciate it. My goal is to be able to set the parameter for the custom free function to a void pointer instead of a specific data type pointer. Thanks!!
#include <stdlib.h>
int getSizeArray(void *array);
void * createArray(int n, int sizeOfDatatype);
void freeArray(double ** array);
int main(void){
double * arr = createArray(10, sizeof(double));
int size = getSizeArray(arr);
/* using output for error checking
for(int i = 0; i < 10; i++){
arr[i] = i;
}
for(int j = 0; j < 10; j++){
printf("%f\n", arr[j]);
}
*/
void* p = &arr;
freeArray(p);
}
int getSizeArray(void *array){
int s = ((int *) array)[-1];
return s;
}
void * createArray(int n, int sizeOfDatatype){
int * array = malloc((n * sizeOfDatatype) + sizeof(int));
array[0] = n;
return (void*) (array + 1);
}
void freeArray(double ** array){
free(*array);
*array = NULL;
}
EDIT: Look to #JonathanLeffler comment. The issue is with alignment. I switched around some of my code but I had to index back one and not cast in my functions but instead in main
#include <stdlib.h>
int getSizeArray(void *array);
void * createArray(int n, int sizeOfDatatype);
void freeArray(double ** array);
int main(void){
double * arr = createArray(10, sizeof(double));
arr = (void*) (arr + 1);
int size = getSizeArray(arr);
/* using output for error checking*/
for(int i = 0; i < 10; i++){
arr[i] = i;
}
for(int j = 0; j < 10; j++){
printf("%f\n", arr[j]);
}
arr = (double*) (arr - 1);
freeArray(&arr);
for(int j = 0; j < 10; j++){
printf("%f\n", arr[j]);
}
}
int getSizeArray(void *array){
int s = ((int *) array)[-1];
return s;
}
void * createArray(int n, int sizeOfDatatype){
int * array = malloc((n * sizeOfDatatype) + sizeof(int));
array[0] = n;
return array;
}
void freeArray(double ** array){
free(*array);
*array = NULL;
}
I provided a complete solution to this problem for another user. Must be a class assignment. My version is very similar to yours except I used macros instead of functions. Anyway, #Serge answer was so close. It -1 not +1.
Here what I plug into my code and it worked fine:
void freeArray(void** array)
{
free( ((int*)(*array)) - 1 );
*array = NULL;
}
Let me explain what going on. The C allocation routines are basically doing what you are doing. They save the array size one word above the actual array. Follow link for more information on how free() works. In our version, we are saving the array size one int (2 words/4 bytes) above the actual array. Your code was wrong because the address you reference is the 3rd element and not the first. You need to pass in the address where the array allocation originated which is ((int*)(*array)) - 1.
If you free(*array), you don't need to *array = NULL after that.
Also, you can't cast a (void *) onto an (int *) and assign it to a (double *).
Lastly, you can't freeArray(p); if p is a single pointer since freeArray(double ** array) has a parameter of double double-pointer.
Hopefully, this helps.
You can compare my modified code.
#include <stdlib.h>
#include <stdio.h>
int getSizeArray(void *array);
void * createArray(int n, int sizeOfDatatype);
void freeArray(void ** array);
int main(void){
double * arr = (double *)createArray(10, sizeof(double));
int size = getSizeArray(arr);
printf("size of arr %d\n", size);
// using output for error checking
for(int i = 0; i < 10; i++){
arr[i] = i;
}
for(int j = 0; j < 10; j++){
printf("%f\n", arr[j]);
}
void ** p = (void **)&arr;
freeArray(p);
printf("del arr, then arr = %u\n",(unsigned)arr);
}
int getSizeArray(void *array){
int s = ((int *) array)[-1];
return s;
}
void * createArray(int n, int sizeOfDatatype){
int * array = (int*)malloc((n * sizeOfDatatype) + sizeof(int));
array[0] = n;
return (void*) (array + 1);
}
void freeArray(void ** array){
free(((int*)*array)-1);
*array = NULL;
}
output:
size of arr 10
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
del arr, then arr = 0

Why does a pointer to a multidimensional array return segmentation fault when accessed after passing the pointer to a function?

So I don't really know what this problem is really called so searching and googling leads to different answers which does not answer my question.
This is the code:
#include <stdio.h>
#include <stdlib.h>
void gen_matrix(int **array, int rm, int cm) {
// int ** array;
int r, c;
array = (int **) malloc(sizeof(int *) * rm);
for (int r = 0; r < rm; ++r) {
array[r] = (int *) malloc(sizeof(int) * cm);
for (int c = 0; c < cm; ++c) {
array[r][c] = 1;
} // c
} // r
}// gen_matrix
int main() {
int **a;
gen_matrix(a, 2, 2);
printf("%d", a[0][0]);
return 0;
}
The problem is that printf() in main() returns Segmentation Fault. What I found out is that the address that the pointer a in main() points to does not change when malloc() is used inside gen_matrix().
In gen_matrix(), I can access the array just fine, but after I return to main(), the pointer a does not point to the array malloc() created.
Thank you.
You are losing the update to array when gen_matrix() returns, because you are not passing it the address of a. You could add an extra indirection level by passing in the address of a to gen_matrix(), but it would be cleaner to just have gen_matrix() return the malloced address and assign it to a in main():
int **gen_matrix(int rm, int cm) {
int ** array;
array = malloc(sizeof(*array) * rm);
for (int r = 0; r < rm; ++r) {
array[r] = malloc(sizeof(*(array[r])) * cm);
for (int c = 0; c < cm; ++c) {
array[r][c] = 1;
} // c
} // r
return array;
}// gen_matrix
int main() {
int **a;
a = gen_matrix(2, 2);
printf("%d", a[0][0]);
return 0;
}
Also, it's not a good idea to cast the return from malloc() and it is preferable to dereference the pointer the memory is being assigned to to get the proper size for sizeof().
And you should of course free() the memory before exiting.
When you call your function the parameter int ** array is the "array itself". What you need is a reference to it, either with one more level of pointer indirection or a C++-style reference. So, what you do is you modify the function to accept a triple-pointer:
void gen_matrix(int ** * array, int rm, int cm) {
and when you call it you also get the address of the "pointer to the matrix":
gen_matrix(&a, 2, 2);
of course you have to modify the code in the function to take care of that extra indirection:
*array = (int **) malloc(sizeof(int *) * rm);
and in the other two places as well.

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.

Resources