I compile the code below with gcc using -Wall -Werror and it compiles cleanly, runs as expected; however, I'm just curious if it is OK, in ANSI and/or ISO C context, to pass a (double ***) pointer via (void **).
The ISO/IEC 9899:2017, section 6.6 - 9 says:
"The array-subscript [] and member-access . and -> operators,
the address & and indirection * unary operators, and pointer
casts may be used in the creation of an address constant, but the
value of an object shall not be accessed by use of these operators."
In connection to this recommendation, the function allocateMatrix is, in fact, supposed to just allocate memory and return the corresponding address; so, please disregard the inner loop that assign values, it's there for test purposes only.
void allocateMatrix(int n, void **a) {
int i = 0, j = 0;
double **pTmp = calloc(n, sizeof(double *));
for (i = 0; i < n; i++) {
pTmp[i] = malloc(n * sizeof(double));
// following loop is inserted to make sure code runs as expected
// this does not exists in real code
for (j = 0; j < n; j++) {
pTmp[i][j] = (double)(i + 1) + (double)(j + 1) / 10.0f;
}
}
*a = pTmp;
return;
}
int main(int argc, char const *argv[]) {
int i = 0, j = 0;
int n = 5;
double **a = NULL;
// "a" is a (double **) pointer; so, "&a" is now a (double ***) pointer
allocateMatrix(n, (void **)&a);
// testing...
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
printf("%6.2lf", a[i][j]);
}
printf("\n");
}
return 0;
}
The C standard allows for conversion to and from void *, however that lattitute does not exist for void **.
Change the function argument to void * and cast it appropriately and it will work.
void allocateMatrix(int n, void *a) {
...
*(double ***)a = pTmp;
}
And change remove the cast from the function call:
allocateMatrix(n, &a);
Related
I'm trying to multiply a large and random matrix (NxN) and a random vector (N), using pointers.
Why am i getting an error type "invalid operands to binary * (have 'double *' and 'double *')" ?
The error seems to be in ptr3[i][j] = ptr3[i] + ptr1[i] * ptr2[k];
but I can't figure out why this doesn't work.
I'm new to C, so I still don't get pointers very well.
int main ()
{
time_t t;
double **ptr1, **ptr2, **ptr3;
int i, j, k;
int N = 500;
ptr1 = (double **) malloc (sizeof (double *) * N);
ptr2 = (double **) malloc (sizeof (double *) * N);
ptr3 = (double **) malloc (sizeof (double *) * N);
for (i = 0; i < N; i++)
ptr1[i] = (double *) malloc (sizeof (double) * N);
for (i = 0; i < N; i++)
ptr2[i] = (double *) malloc (sizeof (double) * N);
for (i = 0; i < N; i++)
ptr3[i] = (double *) malloc (sizeof (double) * N);
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
ptr1[i][j] = rand ();
}
}
for (i = 0; i < N; i++) {
*ptr2[i] = rand ();
}
t = clock();
for (i = 0; i < N; i++) {
ptr3[i] = 0;
for (k = 0; k < N; k++)
ptr3[i] = ptr3[i] + ptr1[i][k] * ptr2[k];
}
t = clock() - t;
double time_taken = ((double)t)/CLOCKS_PER_SEC;
printf("Tempo: %f segundos \n", time_taken);
printf ("\n");
return (0);
} ```
What the compiler is saying is that in the statement ptr3[i] = ptr3[i] + ptr1[i] * ptr2[k];, the bit which says ptr1[i] * ptr2[k] is attempting to * between two expressions which have the type double*. In other words, you are not allowed to multiply two pointers together. To do this properly, you need to dereference again (the [i] and [k] are dereferencing the double** to a double* already). To get this to compile, that statement should be (I added parenthesis for clarity -- they aren't actually needed):
*ptr3[i] = (*ptr3[i]) + (*ptr1[i]) * (*ptr2[k]);
That should get you to compiling, but the next problem you'll run into is a segmentation fault. Two lines above the place where you do the multiplication, you have this:
ptr3[i] = 0;
This is assigning ptr3[i] to be the null pointer, which is the same as 0 in C (other languages have a different name of this value: null, None, etc). What I think you meant to do here is:
*ptr3[i] = 0;
As an aside, since N is a known, fixed value, you can choose to not deal with all the malloc stuff by simply saying:
const int N = 500;
double ptr1[N][N];
double ptr2[N][N];
// ... and so on ...
This is declaring ptr1 as an array instead of a pointer, which is identical to a pointer in terms of memory access patterns, but different in a number of ways. Depending on what you are trying to learn, not dealing with dynamic memory (using malloc and free) might save you a little bit of headache for now.
how can i copy a double type array into an another double type array in c
here is a part of code:
int main(int argc, chae *argv[]){
double *a, *b;
int n = 20;
a = (double *)calloc(n, sizeof(double));
a = (double *)calloc(n, sizeof(double));
for (int i=0; i<n; i++ ){
a[i] =drand48();
}
}
but without using a loop like the following
for (int i=0; i<n; i++ ){
b[i] = a[i];
}
is there any function to do this automatically
There is no built-in way to copy arrays in C directly.
You have two options:
The loop you mentioned:
for(i = 0; i < n; i++) {
b[i] = a[i];
}
The memcpy function:
memcpy(b, a, n * sizeof(double));
The solution you are looking for is memcpy(void*,void*,size_t)
memcpy(&Array1[0], &Array2[0], sizeof(Array1));
In C language , typecast from standard pointer types to void * is done implicitly by the compiler. So no need to worry about passing double pointer as argument.
Sorry if this question already have a solution over there somewhere, but all answers of similar questions I found wasn't helping me.
void imprimePilhaDouble (void *vetor, int tam)
{
int i;
double *vetorDouble;
vetorDouble = (double*) vetor;
for (i = 0; i < tam; ++i)
{
printf("%e\t", *((double*) vetorDouble[i]));
}
printf("\n");
}
void imprimePilhaFloat (void *vetor, int tam)
{
int i;
float *vetorFloat;
vetorFloat = (float*) vetor;
for (i = 0; i < tam; ++i)
{
printf("%f\t", *((float*) vetorFloat[i]));
}
printf("\n");
}
The code above is returning these errors when compiled:
In function 'imprimePilhaDouble'
erro: cannot convert to a pointer type
In function 'imprimePilhaFloat'
erro: cannot convert to a pointer type
For the lines printf("%e\t", *((double*) vetorDouble[i])); and printf("%f\t", *((float*) vetorFloat[i])); respectively.
Is there any way to stop those errors? I made another similar function that seems to work right:
void imprimePilhaInteiro (void *vetor, int tam)
{
int i, *vetorInt;
vetorInt = (int*) vetor;
for (i = 0; i < tam; ++i)
{
printf("%d\t", *((int*) vetorInt[i]));
}
printf("\n");
}
The problem is that this line:
printf("%e\t", *((double*) vetorDouble[i]));
tries to cast a double to a double *. You can't cast a floating point value to a pointer, thus you get the error you report. The same thing happens with your float function.
When you cast an int to an int *, that doesn't cause an error, but is pretty much nonsense.
What are you trying to do?
vetor is a (void *).
vetorDouble is casted to (double *)
vectorDouble[i] is in fact *(vetorDouble + i), i.e. what is pointed to by the base address vetorDouble with an offset of (i) * size of (double), because vetorDouble is of type (* double).
So, vetorDouble[i] is *(vectorSouble+i).
It is already a double. You don't need to cast it to a (double*) again, and the compiler is right when it tells you you can't convert a double to a (double*): it has no meaning.
So, you must write:
void imprimePilhaDouble (void *vetor, int tam)
{
double *vetorDouble = (double*) vetor;
for (i = 0; i < tam; ++i)
{
printf("%e\t", vetorDouble[i]);
}
printf("\n");
}
You can even write (because, readingthe name of your function, it await a double):
void imprimePilhaDouble (double *vetorDouble, int tam)
{
for (i = 0; i < tam; ++i)
printf("%e\t", vetorDouble[i]);
printf("\n");
}
I couldn't understand the first and second value of the output, why are they different ? What is the second output meaning here ?
The Code is:
int **p = (int **)malloc(sizeof(int *) * 2);
int i, j, c = 1;
for (i = 0; i < 2; i++) {
p[i] = (int *)malloc(sizeof(int) * 2);
}
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
p[i][j] = c++;
}
}
printf("%d %d %d %d\n", (int)&p[0][0], (int)p, (int)*p, **p);
Output: 34439216 34439184 34439216 1
Alright. Let's talk about some basic issues first:
On many systems, int will take up less room than void *. So you're possibly truncating your pointers when you print them. It's quite easy to fix that, so let's do it.
Additionally, it's unnecessary to cast the value of malloc(), so let's get rid of that as well to clean up the code a bit.
Finally, as chris notes, to use the %p format specifier, we need to cast the int ** and int * variables to void *.
Fixed foo.c
#include <stdio.h>
#include <stdlib.h>
int main() {
int **p = malloc(sizeof(int *) * 2);
int i, j, c = 1;
for (i = 0; i < 2; i++)
p[i] = malloc(sizeof(int) * 2);
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
p[i][j] = c++;
printf("%p %p %p %d\n", (void *) &p[0][0], (void *) p, (void *) *p, **p);
}
Which now outputs:
0x7fd193c03930 0x7fd193c03920 0x7fd193c03930 1
So now, your actual question:
First, let's talk about what address &p[0][0] points to. That's a fairly complicated expression, but we can reduce it using a fairly simple process such that we end up with *p or p[0].
&p[0][0] == &*(p[0] + 0) == p[0] + 0 == p[0] == *(p + 0) == *p
Looking at that, it should be pretty clear why &p[0][0] (the first argument) and *p (the third argument) print the same value.
Now, I don't see any good reason why p[0] should point to the same address as p. p and p[0] have been assigned values from separate calls to malloc().
#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...
}