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.
Related
This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Closed last year.
I want to understand how to know the size of array without using sizeof and not in main function.
and i really want to understand why my code not working when i do it in other function.(in main it works same as sizeof). >>> The rasult i got are some trash numbers
*with char array is understood but i dont know how to do it with other data specifiers.
#include <stdio.h>
void arrSize(int a[],int b[]){
int size_a = *(&a+1) - a;
int size_b = *(&b+1) - b;
printf("%d,%d",size_a,size_b);
}
int main(){
int arr[] = {2,12,14,16};
int brr[] = {8,53,2,4,16};
arrSize(arr,brr);
return 0;
}
This function declaration
void arrSize(int a[],int b[]){
int size_a = *(&a+1) - a;
int size_b = *(&b+1) - b;
printf("%d,%d",size_a,size_b);
}
is adjusted by the compiler to the following declaration
void arrSize(int *a,int *b){
int size_a = *(&a+1) - a;
int size_b = *(&b+1) - b;
printf("%d,%d",size_a,size_b);
}
That is parameters having array types are adjusted by the compiler to pointers to array element types.
On the other hand, in this call
arrSize(arr,brr);
the arrays are implicitly converted to pointers to their first elements.
Having a pointer to the first element of an array you are unable to determine the array size pointed to by the pointer.
the initializers in these declarations
int size_a = *(&a+1) - a;
int size_b = *(&b+1) - b;
invoke undefined behavior because you are dereferencing pointers that do not point to valid object.
#include <stdio.h>
void print(int (*p)[3]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[3])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
I have written a C function. See above.
It can print all the elements in an array.
There is one thing which is not so perfect : The number of array elements seems to be known in advance.
So I made some modification in hopes of making the function universal :
#include <stdio.h>
void print(int (*p)[]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
In the function, p is pointer pointing to the entire array.
However, it fails to be compiled.
Why can't int (*p)[] be used as an argument for C function?
int (*p)[] can be used as an argument for the function. The part of your code that gives the error is sizeof *p which is obviously not possible, because the type of *p is int[] which is an incomplete type and hence has no known size.
For the function to know the length of the array, you must design a way for the function to receive this information. Options include:
what you did in the original code.
passing the length as another argument.
including the length as an array element.
having a sentinel value on the end of the array.
The most common idiom would be to pass int *p, size_t n, you do not really gain anything by using pointer-to-array without the dimension being given.
The problem is that int [] is an incomplete type as the array has no defined size and therefore its sizeof cannot be taken.
In "modern C" (i.e. for almost 2 decades) you could have used variable-length arrays for this - you can pass the size as an argument and then the array:
#include <stdio.h>
#include <stdlib.h>
void print(size_t n, int (*p)[*]);
int main(void) {
int a[3] = {1, 2, 3};
print(3, &a);
}
void print(size_t n, int (*p)[n]) {
for (size_t i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
Of course this gains you nothing, since sizeof *p / sizeof **pp will be ... n. Therefore we might as well have used
void print(size_t n, int p[n]) {
for (size_t i = 0; i < p; i++)
printf("%d\n", p[i]);
}
which is less typing.
Short answer: int (*p)[] can't be used as an argument and have the function magically know the array size, because the standard says so.
Longer answer:
int (*p)[] is a pointer to an array, but the array has no defined size. So by looking at the array, it is impossible to do pointer arithmetic, calculate size of the thing p is pointing at, etc..
You don't have array of arrays so you don't need int (*p)[]. You have an array of int, so int *p or int p[] should be enough. This does not solve the problem of knowing the size of your array in print. To do this you basically have 3 options
Hardcode the value in the function
Put a sentinel value in your array to mark the end
Pass the size as a separate parameter like this:
void print(int n, int p[n])
Just remember that whatever method you use, parameter passing of arrays will always use pointers behind the scenes, so you CAN NOT use sizeof(p) to calculate the size of the array. sizeof will always return the size of a pointer in those situations
Let's suppose that we have the following functions (in C):
int sum(int a, int b){
return a+b;
}
int diff(int a, int b){
return a-b;
}
So we know that we can declare an array of funtion pointers in the following way:
int (*test[2]) (int a, int b);
test[0] = sum;
test[1] = diff;
But the following is also valid (but we use heap allocation):
int (**test) (int a, int b) = malloc( 2*sizeof(*test));
test[0] = sum;
test[1] = diff;
So far so good. Now let remember that to declare a (dynamically allocated) array of two integers we can do:
int* test = malloc( 2*sizeof(int));
So why we cannot declare an array of function pointers as
int (*test) (int a, int b) = malloc( 2*sizeof(*test)); ?
Is the reason that as test is the same as *test and **test (and so on), malloc( 2*sizeof(*test)) is returning a pointer to a function pointer and therefore it cannot be assigned to (*test) ?
If this supposition is correct, can you explain in detail why we get the compilation error
error: lvalue required as left operand of assignment
when we try to do
int (*test) (int a, int b) = malloc( 2*sizeof(*test));
test=diff; //<--- This is ok.
test+1 = sum; //<--- This is what gives the error!
Disclaimer: I suppose that this is a basic question and the supposition is correct, but I would like a better explanation to have this kind of thing clear one and for all.
Edit:
Notice that this is equivalent to
int (*test) (int a, int b) = malloc( 2*sizeof(*test));
*test=*diff; //<--- This is ok.
*(test+1) = *sum; //<--- This is what gives the error!
as this is somewhat more similar to the case:
int *test = malloc(2*sizeof(*test));
*test = 0;
*(test+1) = 1;
So why we cannot declare an array of function pointers as
int (*test) (int a, int b) = malloc( 2*sizeof(*test));
Because test does not point to a function pointer; it is a function pointer. Thus it cannot point to the first element of an array of function pointers.
If you want an array of function pointers use the previous form:
int (**test) (int a, int b) = malloc( 2*sizeof(*test));
Here, *test has function pointer type and thus test can (and does) point to the first element of an array of function pointers. Further:
error: lvalue required as left operand of assignment
when we try to do
int (*test) (int a, int b) = malloc( 2*sizeof(*test));
test=diff; //<--- This is ok.
test+1 = sum; //<--- This is what gives the error!
No matter what type test has, test+1=anything is always invalid C. test+1 can never be an lvalue. I don't see why you would expect this to work.
GCC is also papering over another bug in your program, sizeof(*test). Since *test has function type, sizeof(*test) is invalid, but GCC silently assigns it the value 1. This results in allocating too little memory for a function pointer, but it doesn't matter anyway because in the following line you throw away the memory you got from malloc and assign something else to test.
I am trying to compute the power of the matrix A using multiplications.
I am having problems with the ArrayPower function. It does not function as i think it should.The MultiArray function however seems to work fine. Can anyone help me ?
#include <stdio.h>
int** MultiArray(int a[2][2],int b[2][2]);
int** ArrayPower(int a[2][2],int e);
int main(void)
{
int fa[2][2];
fa[0][0]=0;
fa[0][1]=1;
fa[1][0]=1;
fa[1][1]=1;
int **multifa=malloc(sizeof(int)*2);
for (int i=0;i<2;i++) {
multifa[i]=malloc(sizeof(int)*2);
}
multifa=ArrayPower(fa,2);
printf("%d %d\n",multifa[0][0],multifa[0][1]);
printf("%d %d\n",multifa[1][0],multifa[1][1]);
return 0;
}
int** MultiArray(int a[2][2], int b[2][2]) {
//multi a *b
//memory allocation
int i,rows=2,cols=2;
int **c=malloc(rows*sizeof(int));
for (i=0;i<rows;i++) {
c[i]=malloc(cols*sizeof(int));
}
c[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0];
c[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1];
c[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0];
c[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1];
return c;
}
int** ArrayPower(int a[2][2],int e) {
//memory allocation
int i,rows=2,cols=2;
int **c=malloc(rows*sizeof(int));
for (i=0;i<rows;i++) {
c[i]=malloc(cols*sizeof(int));
}
c[0][0]=a[0][0];
c[0][1]=a[0][1];
c[1][0]=a[1][0];
c[1][1]=a[1][1];
for (i=1;i<e;i++) {
c=MultiArray(a,c);
}
return c;
}
MultiArray is declared as taking a second parameter of type int [2][2], but it is called with an argument of c, which as type int **. These are not compatible types.
In a parameter, the type int [2][2] is automatically converted to a pointer to an array of two int, the type int (*)[2]. This is a pointer to a place where there are two int objects (and, because we know it is the first element of an array of two arrays of two int objects, we know there are two more int objects beyond the first two).
The definition of c with int **c means that c is a pointer to a pointer to an int. A pointer to a pointer and a pointer to an array are different and are not compatible.
One way to fix this is to define c with int (*c)[2] = malloc(2 * sizeof *c);. It is then unnecessary to have the loop after the definition that allocates more space; the single allocation allocates the entire array.
The return type of MultiArray should be changed similarly, as well as the code within it and elsewhere in the program. Alternatively, the second parameter of MultiArray can be changed from int b[2][2] to int **b. (This latter is an easier edit but produces an inferior program, since it uses more pointers and allocations than necessary.)
You should always compile your code with warnings enabled. That would have alerted you to the incorrect call.
Why aren't these function prototypes equivalent?
void print_matrix(char *name, int SX, int SY, int m[SX][SY])
void print_matrix(char *name, int SX, int SY, int **m)
Even though the two function arguments can be consumed in the same way, namely via m[i][j], they're quite different:
int m[M][N] is an array of M arrays of N ints.
int **m is a pointer to a pointer to an int.
You cannot pass arrays as function arguments, so an "array of K elements of type T" decays to a "pointer-to-T", pointing to the first element of the array. Thus it is permissible and equivalent to write the first form as int m[][N] in a function argument, since the value M is lost. However, the value N is not lost; it is part of the type!
So the following are admissible/erroneous for the first form:
void f(int arr[M][N]);
int a[M][N];
int b[2*M][N];
int c[M][N + 1];
f(a); // OK
f(b); // OK; slowest extent is forgotten in the decay
//f(c); // Error! 'c' is not an array of {array of N ints}.
For the second form, the meaning is rather different:
void g(int **p);
int a;
int * pa = &a;
g(&pa); // fine, pointer to 'pa'
int arr[M][N];
// g(arr); // Error, makes no sense
The expression arr designates the pointer to the first element of an array of arrays of N integers, i.e. its type is int (*)[N]. Dereferencing it gives an array of N integers, and not a pointer to an integer.
There is no way to convert the expression arr into a pointer to a pointer: If you said,
int ** fool = (int**)arr;
then *fool would point to the first element of the first array (arr[0]), and not to an int pointer. So you cannot dereference the value further, because the value is not a pointer.
The only correct way to pass a two-dimensional array as a double pointer is to construct an intermediate helper array:
int * helper[M]; // array of pointers
for (size_t i = 0; i != M; ++i)
{
helper[i] = arr[i]; // implicit decay
}
g(helper); // or "g(&helper[0])"