I'd like to store the pointers of two arrays (*a and *b) created by malloc in a function.
For example, if &a[0]=0x0061FEC8 and &b[0]=0x007700FE, then the array to store these two pointers should be c[0]=0x0061FEC8 and c[1]=0x007700FE
void storePointers(int **ptrArray){
// create two arrays a and b by malloc
int *a = (int *)malloc(5*sizeof(int)); // a stores 5 integers
int *b = (int *)malloc(10*sizeof(int)); // b stores 10 integers
// create an array to store the pointers of a and b
*ptrArray = (int **)malloc(2*sizeof(int*));
(*ptrArray)[0] = a;
(*ptrArray)[1] = b;
}
int main(){
int *mArray = NULL;
storePointers(&mArray);
// these two lines should print 0x0061FEC8 and 0x007700FE
printf("mArray[0]: %p\n", mArray[0]);
printf("mArray[1]: %p\n", mArray[1]);
return 0;
}
This program actually worked. But the compiler displayed a warning message:
warning: assignment to 'int' from 'int *' makes integer from pointer without a cast [-Wint-conversion]
(*ptrArray)[0] = a;
warning: assignment to 'int' from 'int *' makes integer from pointer without a cast [-Wint-conversion]
(*ptrArray)[1] = b;
I assume int is common so the compiler fixed the problem by itself so that my program ran properly? I have another similar program, but it uses struct. So instead of a warning, I get an error of
Error: incompatible types when assigning to type 'myStruct' from type 'myStruct *'
I would like to know the root cause and solution to get rid of the warning and ultimately the error in my struct program.
If an array is int * then an array of arrays is int ** and if you want to return an array of arrays as an out parameter, then you need a pointer to that -- int ***. So you need to change the type of mArray as well as the ptrArray parameter:
void storePointers(int ***ptrArray){
// create two arrays a and b by malloc
int *a = (int *)malloc(5*sizeof(int)); // a stores 5 integers
int *b = (int *)malloc(10*sizeof(int)); // b stores 10 integers
// create an array to store the pointers of a and b
*ptrArray = (int **)malloc(2*sizeof(int*));
(*ptrArray)[0] = a;
(*ptrArray)[1] = b;
}
int main(){
int **mArray = NULL;
storePointers(&mArray);
// these two lines should print 0x0061FEC8 and 0x007700FE
printf("mArray[0]: %p\n", mArray[0]);
printf("mArray[1]: %p\n", mArray[1]);
return 0;
}
That should then work if you change the type from int to something else.
Related
I have this code:
#include <stdio.h>
int main(void) {
int b[] = {1,2,3};
int *a = b; //works
int c = 1;
int *d = c; //doesn't work
}
Why is it that it works to initialize the pointer with an array but not an int?
int *d = c; it does work. It is simply converting the integer number held in c into a pointer. The compiler will issue the warning (unless you cast explicitly).
You can use it, for example, to read from a particular address of memory.
unsigned read_from_memory_address(unsigned address)
{
unsigned *x = (unsigned *)address;
return *x;
}
Of course, how this function will behave (or what type address should have) is implementation defined.
Pointers keep references to objects. If you want pointer to reference an integer variable you need to supply the reference (address) of this variable.
int *x = &c;
Arrays in expressions decay to pointer to first element of the array. That is why you do not need to use & in front of the array (you can, but the pointer will have a different type - in this case pointer to array).
int array[3];
int *x = array; //decays to pointer to first element
int (*y)[3] = &array; //pointer to array of 3 `int` elements
This is part of an assignment.
I currently at the part where I have to read in a .csv file into following struct:
typedef struct {
int n;
double **data;
} Matrix;
The .csv file has for example 3 rows and 3 columns:
1 2 3
4 5 6
7 8 9
and would look like this as a 2d array:
double array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
and now I would want to assign my array to the Matrix like this:
function someFunction(Matrix *m) {
//...
double array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
A->data = array;
A->n = 3;
//...
}
But assigning array to data is not working as I get following error using gcc -Wall -pedantic-errors:
error: assignment to ‘double **’ from incompatible pointer type ‘double *’ [-Wincompatible-pointer-types]
79 | A->data = array;
How can I resolve this problem? Part of the assignment is that gcc is not allowed to show any warnings when using -Wall and -pedantic-erros, so hacks aren't allowed.
double** is a pointer to pointer. Of course the (outer) pointer could point to some array, too:
double* array[7];
double** pointer = array;
Now each of the pointers in array could point to other arrays as well:
double valueArray[12]
double* pointerArray[10];
double** pointer = array;
pointer[0] = valueArray; // equivalent to pointerArray[0] = ...
Two-dimenstional arrays are not arrays of pointers, though, they are arrays of arrays, and pointer to first element is of different type:
double array[10][12];
double(*pointer)[12] = array;
Trying to cover arbitrary size matrices produces some trouble, though:
struct Matrix
{
size_t n;
double(*data)[n]; // you cannot exchange arbitrary pointers,
// you need a compile time constant!
};
Be aware that this is different from VLA in function parameters, where you could have
void f(size_t n, int(*data)[n]);
Then it looks as if you get pretty much into trouble already with the bit of code you presented:
void someFunction(Matrix* m)
{
double array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
m->data = array; // assuming you meant m instead of A
// and you did adjust the pointer type already appropriately
}
array has local storage duration and will be destroyed as soon as you return from the function, resulting in a dangling pointer in m and in undefined behaviour, if you dereference that pointer after returning from function.
So you would need to malloc an array of sufficient size instead. But don't forget to free it again then, too!
So if you don't want to go the pointer to pointer way:
double** array = malloc(sizeof(*array) * n);
array[0] = malloc(sizeof(**array) * n);
// ...
which would allow for the m->data[x][y] syntax, then you should stick to the one-dimensional array approach:
struct Matrix
{
size_t n;
double* data;
};
and maybe some accessor function:
double get(struct Matrix* m, size_t row, size_t column)
{
return m->data[row * m->n + column];
}
which would get around the double pointer indirection and thus be faster (actually, that's exactly the same calculation that occurs under the hoods with a true two-dimensional array, i. e. not the pointer to pointer variant).
I want to use the C function called is_subsetOf() in two different ways:
Way 1: int* a and int* b are arrays with sizes >=2.
Way 2: int* a has size >=2, but int* b is only size 1, which means b is an int.
How can I force C to be okay with int* b being of size 1? Or is this not possible in C? An int IS an array of size 1??
int* is_in(int *left_hand, int n_l, int *right_hand, int n_r) {
int *get_bool;
get_bool = malloc(sizeof(int)*n_l);
for (int i=0; i<n_l; i++) {
if (is_subsetOf(right_hand, n_r, *(left_hand+i), 1)) {
*(get_bool+i) = 1;
}
}
return (get_bool);
}
int desc(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
int is_subsetOf(int *a, int n_a, int *b, int n_b) {
qsort(a, n_a, sizeof(int), desc);
qsort(b, n_b, sizeof(int), desc);
int v = includes(a, n_a, b, n_b);
return(v);
}
Here are the messages I get from the compiler. It's just a warning, I know, but I'd like everything to be clean.
tmp.c: In function ‘is_in’:
tmp.c:73:47: warning: passing argument 3 of ‘is_subsetOf’ makes pointer
from integer without a cast [-Wint-conversion]
if (is_subsetOf(right_hand, n_r, *(left_hand+i), 1)) {
~~~~~~~~~^~~
tmp.c:37:39: note: expected ‘int *’ but argument is of type ‘int’
int is_subsetOf(int *a, int n_a, int *b, int n_b) {
int* a and int* b are arrays with sizes >=2.
No, they are pointers and they don't have any size. You probably meant that you pass arrays through them, but they are not arrays. Know that there is a difference.
An int IS an array of size 1
No, int a[1]; is an array of size 1; int a; is just int. But arrays can decay into pointers to their first element and variables have addresses, so this is correct:
int a[1];
int b;
int* ptr1 = a;//Points to the a[0]
int* ptr2 = &b;
Both are now same type and can be used in the same way. Of course you don't know if the int is followed by any more ints in memory, that kind of checking is up to the programmer (usually by passing the length param as you do). The following is the code you are actually looking for:
is_subsetOf(right_hand, n_r, left_hand+i, 1)
Pointers can be incremented, left_hand+i will point to the i-th int after the int to which left_hand currently points to. Again, validity of such pointer is up to programmer.
The compiler warning is quite important here, because *(left_hand+i) is of type int and the compiler warns that it will treat is as int*. Essentially looking that the value of int as an address to memory. That's not at all what you want and it is an error.
How to cast back from void* ?
int *a[13][12];
void *b
int *c[13][12];
b = (void*) a;
c = (?????) b;
This
c = (int *[13][12])b;
says cast specifies array type
This
c = (int *[][])b;
says array type has incomplete element type.
Compiler is gcc (Ubuntu/Linaro 4.6.1)
In C, you cannot assign to an array, so since c is declared as an array of arrays of pointers to ints, you can't assign it directly.
You could however overwrite all of its items by assigning c[i][j] in turn inside a for loop, for example.
c and a are arrays not pointers, see above, you can use a pointer to a (2 dim) array like
int a[13][12] ={ 1,2,3 };
void *b = &a;
int (*c)[13][12] = b;
and all that without casts
You cannot assign directly to an array, or cast to an array type in C. However, since arrays decay to pointers, you can copy the data from a void * pointer (i.e.: memcpy) to an array and use it as an array, e.g.:
#include <stdio.h>
#include <string.h>
int main() {
int a1=1, a2=2, a3=3, a4=4;
int *a[2][2] = { { &a1, &a2 }, { &a3, &a4 } };
printf("%d %d %d %d\n", *a[0][0], *a[0][1], *a[1][0], *a[1][1]);
void *b;
b = (void*) a;
int *c[2][2];
memcpy(c, b, sizeof(c));
printf("%d %d %d %d\n", *c[0][0], *c[0][1], *c[1][0], *c[1][1]);
return 0;
}
Compiling and running the following program will give you:
1 2 3 4
1 2 3 4
However, c and a are two different arrays now.
void main()
{
int (*d)[10];
d[0] = 7;
d[1]=10;
printf("%d\n",*d);
}
It should print 10 but compiler is showing error such as follows:
test.c:4:7: error: incompatible types when assigning to type ‘int[10]’ from type ‘int’
Note that I have included some errors , not all.
As noted by chris, d is a pointer to an array. This means you use the variable improperly when you access it, but also that you will access random memory unless you assign d to point to a valid array.
Change your program as follows:
int main(void)
{
int (*d)[10]; /* A pointer to an array */
int a[10]; /* The actual array */
d = &a; /* Make `d` point to `a` */
/* Use the pointer dereference operator (unary prefix `*`)
to access the actual array `d` points to */
(*d)[0] = 7;
(*d)[1] = 10;
/* Double dereference is okay to access the first element of the
arrat `d` points to */
printf("%d\n", **d);
return 0;
}
In C, [] is the same as *, the pointer syntax. Thus the following lines are the same:
int** array2d1;
int* array2d2[];
int array2d3[][];
To relate to a closer example, the main function has the following popular forms:
int main(int argc, char** argv){ ... }
or
int main(int argc, char* argv[]){ ... }
Thus
int (*d)[10]
is the same as
int* d[10]
which is the same as
int** d;
int firstArray[10];
d = &firstArray;
Effectively, you are creating a pointer to a pointer (which is a pointer to an array) and allocating the first pointer to an array that 10 elements. Therefore, when you run the following lines:
d[0] = 7;
d[1] = 10;
You are assigning the 1st array's address to 7 and the second array's address to 10. So as Joachim has mentioned, to assign values, you need to deference twice:
(*d)[0] = 7
(*d)[1] = 10
Which says "Assign 7 to the 0th index at the value pointed by d". I hope that makes sense?
d is a pointer to an array of 10 ints.
int (*d)[10] is the declaration for a point to an array of 10 ints.
vs.
int *d[10], which is an array of 10 int pointers.
For more complex syntax like this (usually involving pointers), I use cdecl to help me decode it.
It's used in this form
int d[10]
I guess you are mistaken that d must be a "kind of pointer" and therfor you put an * before the d.
But that's not what you want. You wan to name an array of integer and the notation for that is seen above.
Concept of pointer can get confusing sometimes in C.
Consider an array int d[6] = {0,1,2,3,4,5}
Then, *d is equivalent to d[0]. d is itself an pointer to an array and *d dereferences that pointer and gives us the value.
Hence, following code would print the same values:
int main()
{
int (d)[10];
*d = 7;
*(d + 1)=10;
printf("%d\n",*d);
printf("%d\n",d[0]);
return 0;
}
result:
7
7
Please see http://codepad.org/LYY9ig1i.
If you change your code as follows:
#include<malloc.h>
int main()
{
int *d[10]; //not (*d)[10]
d[0] = (int *)malloc(sizeof(int *) * 10);
d[0][0] = 7;
printf("%d\n",d[0][0]);
return 0;
}
Hope this helps you!