I apologize if this is a repeated question, but I can't seem to find the keywords to search for the question that I'm about to ask.
Basically, I have defined myself a struct.
#define max_terms 101
typedef struct{
int row, col, value;
} term;
Now I have three different terms namely, a[max_terms], b[max_terms] and c[max_terms]
I would like to input into the following function's parameter, so that I can choose to work on which of the three defined arrays
void input(/*parameter here*/){
a[0].row = 0; // want to be able to choose the array to work on instead of just a
}
Thank you for reading!
The easiest approach would be to pass a pointer to the first element of the array to the function.
void input(term *a)
{
a[0].row = 0;
}
/* ... */
term b[max_terms];
input(b);
As giorashc notes in the comments, if the arrays don't all use the same size you'll want to pass the actual size as an additional parameter.
You have two common options:
void input(term *t, size_t size)
and:
void input(term t[], size_t size)
Both mean the same. Passing an argument works the same for both. When you have:
term t[SIZE];
Then either of those will work:
input(&t[0], SIZE);
or:
input(t, SIZE);
Obviously, the second is more convenient. It means the same as the first one; it's just a shorter way to write it. C allows that because passing the address of the first element of an array is a very common operation.
Related
I am not very good at C and I am really confused about double array. Below is an outline of a code I have a question about. Main function calls CreateRandConn function and passes it a 2D array filled with 0 as an argument. CreateRandConn function takes a 2D array as a parameter, changes some of the value in 2DArray from 0 to 1 and returns the changed 2DArray back to main. I want to indicate in the function prototype the return type of CreateRandConn function is a 2D array. How do I indicate that? I don't really understand the syntax. Is what I wrote wrong? Is the way I am passing the 2DArray as a parameter in the function header incorrect? If so, how I do write it? I still get confused about the relationship between pointers and double arrays. Can someone explain it with the below code outline? Hopefully someone knows what my question is...
//Function prototype
int ** CreateRandConn(char * RandRoom[7], int my2DArray[7][7], char * room_dir);
//Function
int ** CreateRandConn(char * RandRoom[7], int my2DArray[7][7], char * room_dir)
{
...
return my2DArray;
}
int main()
{
int 2DArray[7][7] = {0};
2DArray = CreateRandConn(RandRoomArray, my2DArray[7][7], room_dir);
return 0;
}
I don't really understand the syntax.
Ok, so let's recap the basics:
One cannot assign to an array variable.
If an array gets passed to a function it "decays" to a pointer to its 1st element.
A multidimensional array is just an array of arrays. So a 2D-array is a 1D-array of 1D-arrays, a 3D-array is a 1D-array of 2D-arrays, a 4D-array is a 1D-array of 3D-arrays, and so on ...
A pointer p to an array of N elements of type T is to be defined as: T (*p)[N]
Now for you example:
You have
int 2DArray[7][7] = ...;
for the sake of clarity of the following explanations I change this to be
int a[5][7] = ...;
So this then is passed to a function. Where the following happens/applies:
Following 1. above, it is not possible to pass an array, as if it were possible one would assign it to the variable inside the function, as arrays cannot be assigned, one cannot pass an array.
Following 2. above, the function would need to define the related variable as "a pointer to the arrays 1st element".
Following 3. above, the a's 1st element is an int [7]
Following 4. above, a pointer to an int[7] will be defined as: int(*)[7].
So the function's relevant variable would look like:
... func(int (*pa)[7])
pa points to the 1st element of a. As a side note: From this pointer a the function cannot derive how many elements a actually "provides", will say: how many valid element after the one a points to will follow, so this needs to be passed to the function as well:
... func(int (*pa)[7], size_t rows)
From the steps so far we learned, that an array is not passed, but just a pointer to it's 1st element *1 is passed, is copied into the function's local variable (pa here).
From this directly follows that an array cannot be passed back as the function's return value, but just a pointer to an array's element (typically the 1st)
Looking at how a pointer to an array is defined: T (*p)[N] we know need to derive how a function returning a pointer to an array would look. The function's defalcation somewhat needs to become the p above. So taking T as int and N as 7 we then get:
int (*func(int (*pa)[7], size_t rows))[7];
The trivial implementation and usage then would be:
#include <stdlib.h> /* for size_t */
#define ROWS (5)
#define COLS (7)
int (*func(int (*pa)[COLS], size_t rows))[COLS];
int (*func(int (*pa)[COLS], size_t rows))[COLS]
{
for (size_t i = 0; i < rows; ++i)
{
for (size_t j = 0; j < COLS; ++j)
{
pa[i][j] = 0;
}
}
return pa;
}
int main(void)
{
int a[ROWS][COLS];
int (*pa)[COLS] = func(a, ROWS);
return EXIT_SUCCESS;
}
*1
(which sloppy, but wrongly spoken often is referred to as "a pointer to an array is passed", which in general it is not, but just here, as it's a 2D-array, will say the array's elements are arrays themselves).
If you understood the above, then just for completeness following a less strange looking (but also probably less educational ;-)) version of the above function declaration. It may be declared by using a typedef construct hiding away the somehow complicated declaration of the array-pointers as parameter and return type.
This
typedef int (*PA)[COLS];
defines a type pointing a an array of COLS of ints.
So using PA we can instead of
int (*func(int (*pa)[COLS], size_t rows))[COLS];
write
PA func(PA pa, size_t rows))[COLS];
This version is identical to the above.
And yes it looks simpler, but brings along the fact, that pointers pa and the function's return value) are not identifiable as being pointers by just looking at their definition. Such constructs are considered "bad practice" by many fellow programmers.
I am trying to understand function pointers and am stuggling. I have seen the sorting example in K&R and a few other similar examples. My main problem is with what the computer is actually doing. I created a very simple program to try to see the basics. Please see the following:
#include <stdio.h>
int func0(int*,int*);
int func1(int*,int*);
int main(){
int i = 1;
myfunc(34,23,(int(*)(void*,void*))(i==1?func0:func1));//34 and 23 are arbitrary inputs
}
void myfunc(int x, int y, int(*somefunc)(void *, void *)){
int *xx =&x;
int *yy=&y;
printf("%i",somefunc(xx,yy));
}
int func0(int *x, int *y){
return (*x)*(*y);
}
int func1(int *x, int *y){
return *x+*y;
}
The program either multiplies or adds two numbers depending on some variable (i in the main function - should probably be an argument in the main). fun0 multiplies two ints and func1 adds them.
I know that this example is simple but how is passing a function pointer preferrable to putting a conditional inside the function myfunc?
i.e. in myfunc have the following:
if(i == 1)printf("%i",func0(xx,yy));
else printf("%i",func1(xx,yy));
If I did this the result would be the same but without the use of function pointers.
Your understanding of how function pointers work is just fine. What you're not seeing is how a software system will benefit from using function pointers. They become important when working with components that are not aware of the others.
qsort() is a good example. qsort will let you sort any array and is not actually aware of what makes up the array. So if you have an array of structs, or more likely pointers to structs, you would have to provide a function that could compare the structs.
struct foo {
char * name;
int magnitude;
int something;
};
int cmp_foo(const void *_p1, const void *_p2)
{
p1 = (struct foo*)_p1;
p2 = (struct foo*)_p2;
return p1->magnitude - p2->magnitude;
}
struct foo ** foos;
// init 10 foo structures...
qsort(foos, 10, sizeof(foo *), cmp_foo);
Then the foos array will be sorted based on the magnitude field.
As you can see, this allows you to use qsort for any type -- you only have to provide the comparison function.
Another common usage of function pointers are callbacks, for example in GUI programming. If you want a function to be called when a button is clicked, you would provide a function pointer to the GUI library when setting up the button.
how is passing a function pointer preferrable to putting a conditional inside the function myfunc
Sometimes it is impossible to put a condition there: for example, if you are writing a sorting algorithm, and you do not know what you are sorting ahead of time, you simply cannot put a conditional; function pointer lets you "plug in" a piece of computation into the main algorithm without jumping through hoops.
As far as how the mechanism works, the idea is simple: all your compiled code is located in the program memory, and the CPU executes it starting at a certain address. There are instructions to make CPU jump between addresses, remember the current address and jump, recall the address of a prior jump and go back to it, and so on. When you call a function, one of the things the CPU needs to know is its address in the program memory. The name of the function represents that address. You can supply that address directly, or you can assign it to a pointer for indirect access. This is similar to accessing values through a pointer, except in this case you access the code indirectly, instead of accessing the data.
First of all, you can never typecast a function pointer into a function pointer of a different type. That is undefined behavior in C (C11 6.5.2.2).
A very important advise when dealing with function pointers is to always use typedefs.
So, your code could/should be rewritten as:
typedef int (*func_t)(int*, int*);
int func0(int*,int*);
int func1(int*,int*);
int main(){
int i = 1;
myfunc(34,23, (i==1?func0:func1)); //34 and 23 are arbitrary inputs
}
void myfunc(int x, int y, func_t func){
To answer the question, you want to use function pointers as parameters when you don't know the nature of the function. This is common when writing generic algorithms.
Take the standard C function bsearch() as an example:
void *bsearch (const void *key,
const void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *));
);
This is a generic binary search algorithm, searching through any form of one-dimensional arrray, containing unknown types of data, such as user-defined types. Here, the "compar" function is comparing two objects of unknown nature for equality, returning a number to indicate this.
"The function shall return an integer less than, equal to, or greater than zero if the key object is considered, respectively, to be less than, to match, or to be greater than the array element."
The function is written by the caller, who knows the nature of the data. In computer science, this is called a "function object" or sometimes "functor". It is commonly encountered in object-oriented design.
An example (pseudo code):
typedef struct // some user-defined type
{
int* ptr;
int x;
int y;
} Something_t;
int compare_Something_t (const void* p1, const void* p2)
{
const Something_t* s1 = (const Something_t*)p1;
const Something_t* s2 = (const Something_t*)p2;
return s1->y - s2->y; // some user-defined comparison relevant to the object
}
...
Something_t search_key = { ... };
Something_t array[] = { ... };
Something_t* result;
result = bsearch(&search_key,
array,
sizeof(array) / sizeof(Something_t), // number of objects
sizeof(Something_t), // size of one object
compare_Something_t // function object
);
I have an array/pointer related problem.
I created an int array myArray of size 3. Using a function I want to fill this array.
So I'm calling this function giving her the adress &myArray of the array.
Is the syntax correct for the function declaration`? I'm handing over the pointer to the array, so the function can fill the array elements one by one.
But somehow my array is not filled with the correct values.
In Java I could just give an array to a method and have an array returned.
Any help is appreciated! Thanks!
#include <stdio.h>
int myArray[3];
void getSmth(int *anArray[]);
int main(void)
{
getSmth(&myArray);
}
void getSmth(int *anArray[])
{
for(i=0...)
{
*anArray[i] = tmpVal[i];
}
}
Remove one level of indirection:
#include <stdio.h>
int myArray[3];
void getSmth(int anArray[]);
int main(void)
{
getSmth(myArray);
}
void getSmth(int anArray[])
{
for(i=0...)
{
anArray[i] = tmpVal[i];
}
}
Also, as others have suggested, it would be a good idea to pass the size of the array into getSmth().
No, the syntax is not correct. You have an extra *, making the argument into an array of pointers.
In general, it's better to use:
void getSmth(int *array, size_t length);
since then the function can work on data from more sources, and the length becomes available which is very handy for iterating over the data as you seem to want to be doing.
You'd then call it like so:
int main(void)
{
int a[12], b[53];
getSmth(a, sizeof a / sizeof a[0]);
getSmth(b, sizeof b / sizeof b[0]);
}
Note the use of sizeof to compute (at compile-time) the number of elements. This is better than repeating the numbers from the definitions of the variables.
Right now, your function accepts an int *anArray[] parameter, which is an array of pointers to int. Remove the unneccessary * and your function signature should look simply like this:
void getSmth(int anArray[]); // array of int
or
void getSmth(int *anArray); // pointer to first array element of type int
You should use either int anArray[] or int *anArray (which is effectively the same, because array decays to pointer). You should also make sure that the function knows how big your array is either by agreement or passing it as a parameter for it can not use sizeof for the purpose.
For my program I need to pass a 2D array of pointers to a function in a separate file. I've written a similarly-syntaxed file below:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int state;
int design;
} card_t;
card_t *cardSet[5][5];
void setFirst(card_t *cards[][]) { // <- Error: Array has incomplete element type
cards[0][0]->state = 1;
}
int main() {
setFirst(cardSet); // <- Error: Type of formal parameter 1 is incomplete
return 0;
}
When I change the code to all 1D arrays it compiles fine, but for a 2D array I get the errors shown above. What is the difference between the two cases?
Thanks!
Cameron
if you pass an array to a function, you have to specify the size of the inner array, in your case, instead of void setFirst(card_t *cards[][]), you should specify void setFirst(card_t *cards[][5]).
Why do you need to specify it and not the size of the first dimension?
Since cards is an array of array of card_t pointers, if you want to get to cards[1][0], the compiler will need to know how much to add to the pointer cards - cards is declared: card_t *cards[5][4] it will need to add 4 * sizeof(*card_t) to get to cards[1][0], but if cards is declared: card_t *cards[5][5] it will need to add 5 * sizeof(*card_t) to get to cards[1][0].
As has been mentioned, to pass a 2d array to a function, you need to have every dimension but the first declared.
However, you can also just pass the pointer, as follows. Note that you should always (unless the array dimension is completely fixed and the function that operates on the array only operates within the array's dimension) pass the length of each array, too.
void setFirst(card_t ***cards, size_t n, size_t m) {
if (n > 0 && m > 0) {
cards[0][0]->state = 1;
}
}
Because referencing an array via code[0][0] is the same as *(*(code+0)+0*m), you can pass two pointers instead of array dimensions.
Only the first index is optional. You should definitely mention the second index, because a two dimensional array decays to a pointer to 1d array.
void setFirst(card_t *cards[][5]) {
// ^ Newly added
// ..
}
Also make sure that the pointers are pointing to valid memory locations. Else dereferencing leads to segmentation faults. BTW, is there any reason to have a two dimensional array with pointers. I think you are just complicating the program.
To achieve something similar to what you are trying C99 has variable length arrays. These come particularly handy in function definitions:
void setFirst(size_t n, size_t m, card_t *cards[n][m]) {
...
}
Observe that you have to have the size parameters known at the moment of the array declaration, so you'd have to put them in front.
Lets take qsort()'s comparison callback function as an example
int (*compar)(const void *, const void *)
What happens when the result of the comparison function depends on the current value of a variable? It appears my only two options are to use a global var (yuck) or to wrap each element of the unsorted array in a struct that contains the additional information (double yuck).
With qsort() being a standard function, I'm quite surprised that it does not allow for additional information to be passed in; something along the lines of execv()'s NULL-terminated char *const argv[] argument.
The same thing can be applied to other functions which define a callback that leave no headroom for additional parameters, ftw() & nftw() being two others I've had this problem with.
Am I just "doing it wrong" or is this a common problem and chalked up to an oversight with these types of callback function definitions?
EDIT
I've seen a few answers which say to create multiple callback functions and determine which one is appropriate to pass to qsort(). I understand this method in theory, but how would you apply it in practice if say I wanted the comparison callback function to sort an array of ints depending on how close the element is to a variable 'x'?. It would appear that I would need one callback function for each possible value of 'x' which is a non-starter.
Here is a working example using the global variable 'x'. How would you suggest I do this via multiple callback functions?
#include <stdint.h>
#include <stdio.h>
#include <math.h>
int bin_cmp(const void*, const void*);
int x;
int main(void)
{
int i;
int bins[6] = { 140, 100, 180, 80, 240, 120 };
x = 150;
qsort(bins, 6, sizeof(int), bin_cmp);
for(i=0; i < 6; i++)
printf("%d ", bins[i]);
return 0;
}
int bin_cmp(const void* a, const void* b)
{
int a_delta = abs(*(int*)a - x);
int b_delta = abs(*(int*)b - x);
if ( a_delta == b_delta )
return 0;
return a_delta < b_delta ? -1 : 1;
}
Output
140 180 120 100 80 240
Change the value of the function pointer. The whole point (no pun intended) of function pointers is that the user can pass in different functions under different circumstances. Rather that passing in a single function which acts differently based on external circumstances, pass in different functions based on the external circumstances.
This way, you only need to know about the values of variables in the context of the call to qsort() (or whatever function you're using), and write a couple different simpler comparison functions instead of one big one.
In response to your edit
To deal with the issue described in your update, just use to the global variable by name in your comparison function. This will certainly work if you are storing the variable at the global scope, and I believe qsort() will be able to find it at most other (public) scopes visible to the comparison function definition, as long as the scope is fully qualified.
However, this approach won't work if you want to pass a value straight into the sorting process without putting it in a variable.
It sounds like you need the bsearch_s() and qsort_s() functions defined by TR 24731-1:
§6.6.3.1 The bsearch_s function
Synopsis
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdlib.h>
void *bsearch_s(const void *key, const void *base,
rsize_t nmemb, rsize_t size,
int (*compar)(const void *k, const void *y, void *context),
void *context);
§6.6.3.2 The qsort_s function
Synopsis
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdlib.h>
errno_t qsort_s(void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context);
Note that the interface has the context that you need.
Something rather close to this should be available in the MS Visual Studio system.
With qsort's signature being what it is, I think your options are pretty limited. You can use a global variable or wrap your elements in structs as you suggested, but I'm not aware of any good "clean" way of doing this in C. I imagine there are other solutions out there, but they won't be any cleaner than using global variables. If your application is single-threaded, I would say this is your best bet as long as you're careful with the globals.
I'd listen to tlayton, and wrap that logic in a function that returns a pointer to the appropriate comparison function.
You can write your own specialized qsort implementation and customize it to your need.
To give you an idea about how short it is, this is a qsort implementation with your delta.
void swap(int *a, int *b)
{
int t=*a; *a=*b; *b=t;
}
void yourQsort(int arr[], int beg, int end, int delta)
{
if (end > beg + 1)
{
int piv = arr[beg], l = beg + 1, r = end;
while (l < r)
{
//Here use your var something like this
int a_delta = abs(arr[l] - delta);
int b_delta = abs(piv - delta);
if (a_delta <= delta)
l++;
else
swap(&arr[l], &arr[--r]);
}
swap(&arr[--l], &arr[beg]);
yourQsort(arr, beg, l, delta);
yourQsort(arr, r, end, delta);
}
}
More C-optimized implementations are said to be here.
You will have to prepare several function callbacks and check the value before running qsort, then send the correct one.
IMO, go with the global. The problem is that you're really asking qsort to do two things, both sort and map, where it's only designed to do the first.
The other thing you could do is break it down into a couple steps. First compute an array of these (one for each element of the source array):
struct sort_element {
int delta; // This is the delta value
int index; // This is the index of the value in the source array
}
Call qsort on that array, using a sort function that compares delta values. Then you use the index'es on the sorted array to order your original array. This consumes some memory, but it may not matter that much. (Memory is cheap, and the only thing you have to store in the temporary array is the key, not the entire value.)