#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
}
Related
#include <stdio.h>
#include <stdlib.h>
int find_lenght(int *arrr){
int i = 0;
while(arrr[i] != '\0'){
i++;
}
return i;
}
void init_array(int *arrr){
arrr=(int*)malloc(1*sizeof(int));
printf("New element:");
int lenght = find_lenght(arrr);
scanf("%d", &arrr[lenght]);
printf("Lenght = %d\n",lenght);
printf("Array elements are:\n");
for(int i = 0; i <= lenght; i++) {
printf("%d,", arrr[i]);
}
}
void print_array(int *arrr){
printf("Array elements are:\n");
int lenght = find_lenght(arrr);
for(int i = 0; i == lenght; i++) {
printf("%d,", arrr[i]);
}
}
int main() {
int *arr = NULL;
init_array(arr);
print_array(arr);
}
I don't know what am i missing here.
My point is to fill in and then print dynamic array
Also my taught is it's not filling the way it should, so it hasn't anything to print.
Your arr pointer in main is never assigned because your init_array assign the address of the allocated memory (the return value of malloc) to the input parameter arrr, which is, a local variable.
You have mainly two solutions to properly achieve what you want to do. The first one (the better one in my point of view), by making your init_array returning the allocated memory address to be assigned:
int* init_array()
{
int* retval = (int*)malloc(1*sizeof(int));
// ...
return retval;
}
int main()
{
int *arr = init_array(); //< assign arr with returned value
}
Another way is to make your init_array function taking a pointer to a pointer, so the function can assign this pointer:
void init_array(int** arrr)
{
(*arrr) = (int*)malloc(1*sizeof(int));
// ...
}
int main()
{
int* arr = NULL;
init_array(&arr); //< pass reference to arr
}
You need to pass the pointer to pointer to int to change passed pointer. Your for loop is invalid in print function. You need also to set the sentinel value yourself.
size_t find_length(const int *arrr)
{
size_t i = 0;
if(arrr)
while(arrr[i]) i++;
return i;
}
void add_element(int **arrr, int element)
{
size_t length = find_length(*arrr);
int *tmp = realloc(*arrr, (length + 2) * sizeof(**arrr));
if(tmp)
{
*arrr = tmp;
(*arrr)[length] = element;
(*arrr)[length + 1] = 0;
}
}
void print_array(const int *arrr)
{
printf("Array elements are:\n");
size_t lenght = find_length(arrr);
for(size_t i = 0; i < lenght; i++)
{
printf("arrr[%zu] = %d\n", i, arrr[i]);
}
}
int main(void) {
int *arr = NULL;
add_element(&arr, 5);
add_element(&arr, 15);
add_element(&arr, 25);
add_element(&arr, 35);
print_array(arr);
}
https://godbolt.org/z/drKej3KT5
the array on your main function is still NULL. the better way to do is just call the print_array() function after you initialize it. you just simply put print_array(arrr) inside init_array() and after the for loop statement.
The line
int lenght = find_lenght(arrr);
may invoke undefined behavior, because find_length requires its argument to be a pointer to the first element of a null-terminated int array. However, the content of the memory pointed to by arrr is indeterminate, because it has not been initialized. Therefore, it is not guaranteed to be null-terminated.
i'm trying to make a qsort function from scratch that sorts an array of pointers to structs
this is the code i have right now
static void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void _qsort(void* list, int list_len, int left, int right,
int(*comp)(const struct shpg_item *a, const struct shpg_item *b)) {
void *vt, *v3;
int i, last, mid = (left + right) / 2;
if (left >= right)
return;
void* vl = (char*)(list + (left * list_len));
void* vr = (char*)(list + (mid * list_len));
swap(vl, vr);
last = left;
for (i = left + 1; i <= right; i++) {
// vl and vt will have the starting address
// of the elements which will be passed to
// comp function.
vt = (char*)(list + (i * list_len));
if ((*comp)(vl, vt) > 0) {
++last;
v3 = (char*)(list + (last * list_len));
swap(vt, v3);
}
}
v3 = (char*)(list + (last * list_len));
swap(vl, v3);
_qsort(list,list_len, left, last - 1, comp);
trace_int(1);
_qsort(list, list_len, last + 1, right, comp);
}
void list_sort(struct shpg_item **list, int list_len,
int(*comp)(const struct shpg_item *a, const struct shpg_item *b)) {
_qsort(*list,list_len,0,(list_len-1),comp);
}
but this gives a segmentation fault error , can any one tell me why and help me ?
void * pointer addition
void * pointer addition is undefined behavior. But since the usual UB is OK, this may or may not be OP's trouble.
void _qsort(void* list, int list_len, int left, ...
...
(list + (left * list_len)) // UB
Instead recommend casting before addition.
// void* vl = (char*)(list + (left * list_len));
void* vl = ((char*) list) + (left * list_len);
Other issues may exist
I haven't check the entire code but your swap function seems wrong. Depending on the comment lines in your code;
// vl and vt will have the starting address
// of the elements which will be passed to
// comp function.
if (list + (left * list_len)) and (list + (last * list_len)) are pointers to be swapped (pointers to a string or a struct, for example), your swap function decoration & your caller line should read as:
Swapping two integers, floats, doubles, etc (in general swapping values only):
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
...
int x = 5;
int y = 3;
swap(&x, &y);
If you need to swap two pointers (a char * string or another type of pointer pointing to a struct), you can just swap pointer values without swapping the content pointed in the actual memory:
void swap(void **a, void **b) {
void *t = *a;
*a = *b;
*b = t;
}
...
char *x = "some string";
char *y = "some other string";
swap(&x, &y);
I've included a working example in the middle part of this answer, and also added an example using qsort.
Taking a quick look at the code I see problem here:
void _qsort(void* list, ...
Since list is an array of pointers it should be:
void _qsort(void** list, ...
or
void _qsort(void* list[], ...
With this declaration, pointer arithmetic will not be an issue, for example, list+3 == &list[3] == pointer to the 3rd pointer in the array. There's no need to cast list, as void** list will work fine in the main part of the code. The only code that will do any casting is the caller's compare function.
You can choose to emulate qsort's compare function parameters using type void **: compare(list+i, list+j), but it would be simpler to use type void *: compare(list[i], list[j]).
Swap should use void** as parameters. The call would be
swap(list+i, list+j)
/* ... */
void swap(void **i, void **j){
void * t;
t = *i;
*i = *j;
*j = t;
}
There are some comments about a void pointer possibly having a different size than a struct pointer or any type of data pointer, and that this could cause an issue. If this was true, then the C library function qsort() would not work because the first parameter for qsort is a void pointer, which will result in the caller's pointer being cast to a void pointer. In the caller's compare function, both parameters are const void pointers which the caller's compare function has to cast to the actual pointer types. With qsort() and the caller's compare function, parameters are being cast both to and from void pointers without issue.
C guarantees that a void pointer can be used to hold any type of data pointer, so in essence a void pointer is a generic data pointer (in 16 bit segment or selector environments, a generic "near" data pointer).
This is a working example, using typical Lomuto partition scheme (pivot = a[hi]):
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int data;
char name[32];
}XMPL;
int cmpr(void * pi, void *pj)
{
if(((XMPL *)pi)->data < ((XMPL *)pj)->data)
return -1;
if(((XMPL *)pi)->data > ((XMPL *)pj)->data)
return 1;
return 0;
}
void swap(void **i, void **j){
void * t;
t = *i;
*i = *j;
*j = t;
}
void QuickSort(void **a, int lo, int hi, int(*cmpp)(void *, void *))
{
void *p;
int i, j;
while(lo < hi){
p = a[hi];
i = lo;
for(j = lo; j < hi; ++j){
if((cmpp(a[j], p) < 0)){
swap(a+i, a+j);
++i;
}
}
swap(a+i, a+hi);
if(i - lo <= hi - i){ /* avoid stack overflow */
QuickSort(a, lo, i-1, cmpp);
lo = i+1;
} else {
QuickSort(a, i+1, hi, cmpp);
hi = i-1;
}
}
}
#define COUNT (1024)
int main(int argc, char**argv)
{
XMPL *ax; /* array of structures */
XMPL **pax; /* array of pointers to structures */
int i;
ax = malloc(COUNT * sizeof(XMPL));
pax = malloc(COUNT * sizeof(void **));
for(i = 0; i < COUNT; i++){ /* init structs, array of ptrs */
ax[i].data = rand();
pax[i] = ax+i;
}
QuickSort(pax, 0, COUNT-1, cmpr);
for(i = 1; i < COUNT; i++){
if(pax[i-1]->data > pax[i]->data){
break;
}
}
if(i == COUNT)
printf("passed\n");
else
printf("failed\n");
free(pax);
free(ax);
return(0);
}
Hoare parition scheme will probably be a bit faster. However, in this case, merge sort should be faster than quick sort. Merge sort does more moves but fewer compares than quick sort, and in this case, only pointers are being moved, while the compare involves an indirection via a pointer and a call to a compare function via a pointer.
Same basic code, but using qsort. Note that the cmpr() function needed one more dereference for each parameter.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int data;
char name[32];
}XMPL;
int cmpr(const void * pi, const void *pj)
{
if((*(XMPL **)pi)->data < (*(XMPL **)pj)->data)
return -1;
if((*(XMPL **)pi)->data > (*(XMPL **)pj)->data)
return 1;
return 0;
}
#define COUNT (1024)
int main(int argc, char**argv)
{
XMPL *ax; /* array of structures */
XMPL **pax; /* array of pointers to structures */
int i;
ax = malloc(COUNT * sizeof(XMPL));
pax = malloc(COUNT * sizeof(void **));
for(i = 0; i < COUNT; i++){ /* init structs, array of ptrs */
ax[i].data = rand();
pax[i] = ax+i;
}
qsort(pax, COUNT, sizeof(XMPL *), cmpr);
for(i = 1; i < COUNT; i++){
if(pax[i-1]->data > pax[i]->data){
break;
}
}
if(i == COUNT)
printf("passed\n");
else
printf("failed\n");
free(pax);
free(ax);
return(0);
}
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;
}
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.
#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...
}