H.ello just a hobbyist here. I started again C after a little JS detour that taught me closures, oop and other stuff. I usually make small code snippets that I can reference or reuse later. So in the code below is there a reason why the compiler says counter is undeclared, as it is referenced as an argument of the callback function argument?
To make this work,
1. I could make counter a global variable, this works but it is not best practice.
2. I could move caller function inside main, but I'd like to avoid this.
3. pass counter as a 4th seperate pointer argument, however in that case, I don't really know with what voodoo should I invoke the caller function popArr within main.
Generally I'm interested in the technique how to use callbacks with arguments without using global variables or putting everything inside main.
So here is the code:
#include <stdio.h>
// CALLBACKS
/* Caller */
void popArr(int *arr, size_t length, int (*callback)(int *counter)) {
for (size_t i=0; i<length; i++) {
arr[i] = callback(&counter);
printf("arr[%zu] is: %d\n", i, arr[i]);
}
}
/* A simple generator callback saving counter. */
int generator(int *counter) {
*counter = *counter+1;
return *counter*5;
}
/* Main function. */
int main(void) {
int counter = 1;
int arr[10];
popArr(arr, 10, &generator);
return 0;
}
So in the code below is there a reason why the compiler says counter
is undeclared, as it is referenced as an argument of the callback
function argument?
I presume you mean in function popArr(). Yes, of course there's a reason. In popArr(), the symbol counter appears only in the prototype for the callback function, and the scope of that appearance is limited to the prototype in which it appears. There is no symbol with that name in scope in the body of popArr().
The different appearances of the symbol counter in that prototype, in function generator(), and in main() all have different, non-overlapping scope. They are not related to each other, notwithstanding the reuse of the same name.
Generally I'm interested in the technique how to use callbacks with arguments without using global variables or putting everything inside main.
There are two main scenarios:
Callbacks with parameters that the caller (popArr() in your example) is expected to choose itself, and
Callbacks with parameters that the callback provider (main() in your example) is expected to specify.
Those are not mutually exclusive. Case (1) has no special requirements -- the caller just passes whatever argument is appropriate, at its own discretion. Case (2) isn't much harder, in principle: the code that provides the callback simply needs to provide the appropriate argument with it. For your very simple case, where the argument and callback do not need to be stored, that would look something like this:
void popArr(int *arr, size_t length, int (*callback)(int *), int *counter) {
// The name of the parameter to (*callback)() is omitted for clarity. It is
// optional in this context.
for (size_t i = 0; i < length; i++) {
arr[i] = callback(counter); // Note: passing counter, not *counter
printf("arr[%zu] is: %d\n", i, arr[i]);
}
}
/* A simple generator callback saving counter. */
int generator(int *counter) {
*counter += 1;
return *counter * 5;
}
/* Main function. */
int main(void) {
int counter = 1;
int arr[10];
// It is unnecessary, but not harmful, to use the & operator on the function
// name. I think it's better style to omit it.
// It is necessary to use the & operator on 'counter', but mainly because
// you want to pass a pointer to counter, as opposed to its value
popArr(arr, 10, generator, &counter);
return 0;
}
Related
I have an assignment that requires the use of a function
void stats(FILE *in, int *count, double *sum); , which is supposed to compute the sum, average, and integer count of each file. We are supposed to call the function by using stats(in, &count, &sum) . I'm confused as to how exactly I'm supposed to send the results back to main if the stats function has a void return type. Any help or explanation would be greatly appreciated! Thanks
Your function signature indicates that each parameter is a pointer argument (they begin with a *). Declare (and possibly initialize) those variables in your main function, then pass the addresses of those variables as indicated in the way you're told to call the function: stats(in, &count, &sum). The function will modify those variables in main scope using the pointers you passed to it, without returning any value. This is an example of pass (or call) by reference.
So overall, your main function will have something like:
int main(void)
{
/* some FILE opening here */
int count = 0;
double sum = 0;
stats(in, &count, &sum);
/* rest of your main function */
return 0;
}
If you want to understand more about what the * and & mean, you should go through how pointers work in C – here is a very basic resource to get you started.
I am taking a hybrid class of "Algorithms, architecture, and assembly language" at my local community college. Although it's an intro class and mainly focuses on how computers turn code into binary, we have some assignments for C code. Some of the stuff we've never even gone over in class, and I'm lost.
The instructions read:
Write a function named DoSomething, with no return value, it should do just one (1) thing: multiply the global variable my_result by 5 and store the result back into my_result
You do not have to call DoSomething, or initialize my_result, I will do that.
I have tried
int my_result;
dosomething (my_result) {
my_result = my_result * 5;
}
but this is incorrect. I have almost zero experience with C language and am stuck. I'm not asking anyone to do my homework, I just want to understand. This has not been covered in class.
You almost have it. Since my_result is global, you do not need to pass it into the function, it is accessible everywhere. Oh, and every function needs its return value specified. Use void to specify that there is no return value and no parameters.
int my_result;
void dosomething (void) {
my_result = my_result * 5;
}
A correct function declaration must have a type, the name of the function and its arguments.
type function_name(type1 arg1, type2 arg2, type3 arg3, ...);
If a function does not return anything, then type must be void
void function_name(type1 arg1, type2 arg2, type3 arg3, ...);
If a function does not take any parameter, then the you can use void instead
of the list of arguements:
type function_name(void);
Your dosomething function is missing the return type, which should be void
(assignment says Write a function named DoSomething, with no return value)
and it takes no arguments (at least the assignment does not specify any), so the
correct prototype of the function must be:
void DoSomething(void);
So the correct program
#include <stdio.h>
int my_result;
void DoSomething(void)
{
my_result = my_result * 5;
}
int main(void)
{
my_result = 6; // initializing global variable
DoSomething();
printf("my_result: %d\n", my_result);
return 0;
}
which will print my_result: 30.
There is nothing to get worried about. Relax, it's just part of the process in becoming a good developer.
To solve such problems, first note what the function expects and we want from the function to return.
Now, in your question, it is given that function would return nothing. So the return type of the function would be void.
Now, since we have to use a global variable, it means function expects no argument.
Hence, our code is :
#include <stdio.h>
int my_result; // Our Global Variable
void doSomething (void) // Our Function
{
my_result = my_result * 5;
}
int main()
{
/* Asking the value of my_result */
printf("Please enter a value : ");
scanf("%d", my_result);
doSomething();
printf("\nNew value of my_result is : %d\n", my_result);
return 0;
}
// End of main.
The instructions read:
Write a function named DoSomething, with no return value,…
So code for that is:
void DoSomething(void)
… it should do just one (1) thing: Multiply the global variable my_result by 5 and store the result back into my_result.
And code for that is:
{
my_result = my_result * 5;
}
You do not have to call DoSomething, or initialize my_result, I will do that.
Done. The total code requested is:
void DoSomething(void)
{
my_result = my_result * 5;
}
You have indicated in your comments that you are submitting this code into some sort of automatic grading/checking software. So that software is designed to accept code that matches the assignment, no more and no less. Quite likely, it puts your code into a file and that compiles a source file that includes the former file with #include. That source file defines my_result and main, so your code should not, or it will cause compilation and/or link errors. You need to submit just the code requested in the instructions.
Notes about your code:
The instructions say to write a routine named DoSomething. You used dosomething. These are different in C; the case matters.
You declared the routine without specifying a return type. The instructions say the instruction has no return value, but that does not mean you should just omit any return type. You should explicitly say there is no return value by using void for the return type of the function, as in void DoSomething(…). (For historic reasons, if you omit the return type in a function declaration, it defaults to int. Letting the type default like that is old syntax and should be avoided.)
The instructions did not say whether the routine should take parameters. This is a shortcoming in the instructions. However, dosomething (my_result) is incorrect for two reasons. One, my_result is described as a global variable, not a parameter. Two, it is the wrong syntax for a parameter declaration. A parameter declaration must have a type, as in dosomething(int x). Since the routine needs no parameters, a proper declaration is void DoSomething(void). (Although there is some possibility the instructor intended void DoSomething(), but that would not generally be preferred.)
A function like that:
int * getRandom( ) {
static int r[10];
int i;
/* set the seed */
srand( (unsigned)time( NULL ) );
for ( i = 0; i < 10; ++i) {
r[i] = rand();
printf( "r[%d] = %d\n", i, r[i]);
}
return r;
}
Is this one possible to be used in Vivado HLS? If possible, how can I initialize an array of unknown size because I cannot use static and malloc anymore?
Converting comments into an answer.
You cannot, in standard C, return an array from a function — you can return a pointer OK (so the code shown is permissible, though it clearly has re-entrancy and threading issues). If you can't use static or malloc() et al, then you need to pass the array to the function for it to fill in instead of returning the array. Then it is the caller's responsibility to allocate the space.
See also srand() — why call it only once.
So you mean I can set a global array as function arguments and give value to each element so I can get the array without using static and malloc?
Yes, or a local array, or an any-other-type of array you care to think of. I think the appropriate implementation might be:
void getRandom(int n_vals, int *i_vals)
{
for (int i = 0; i < n_vals; i++)
i_vals[i] = rand();
}
but the possible variations are legion. You can reinstate the printing if you really want it; you can even call srand() if you really want to (but you should only call that once). You can then use it like:
void somefunc(void)
{
int data[20];
getRandom(15, data);
…use data…;
}
or
static int data[20];
void somefunc(void)
{
getRandom(18, data);
…use data…;
}
or other variants (such as not using static in front of the file-scope definition of data — converting it into a global variable). (Yes, you'd probably use 10 as in the question, or 20 as the amount of space in the array — but 15 and 18 are also OK values in their context.)
I am learning C and I am studying functions. So, I read that when I implement my own function I have to declare it before the main(). If I miss the declaration the compiler will get an error message.
As I was studying this example (finds if the number is a prime number),
#include <stdio.h>
void prime(); // Function prototype(declaration)
int main()
{
int num, i, flag;
num = input(); // No argument is passed to input()
for(i=2,flag=i; i<=num/2; ++i,flag=i)
{
flag = i;
if(num%i==0)
{
printf("%d is not prime\n", num);
++flag;
break;
}
}
if(flag==i)
printf("%d is prime\n", num);
return 0;
}
int input() /* Integer value is returned from input() to calling function */
{
int n;
printf("\nEnter positive enter to check: ");
scanf("%d", &n);
return n;
}
I noticed that a function prime() is declared, but in the main, a function, input(), is called and also the function input() is implemented at the bottom. Ok, I thought it was a mistake and I change the name from prime to input.
However if I delete the declaration and I don’t put any there, the program is compiled without errors and it runs smoothly. (I compile and run it on Ubuntu.)
Is it necessary to declare a void function with not arguments?
If you don't have a forward declaration of your function before the place of usage, the compiler will create implicit declaration for you - with the signature int input(). It will take the name of the function you called, it will assume that the function is returning int, and it can accept any arguments (as Bartek noted in the comment).
For this function, the implicit declaration matches the real declaration, so you don't have problems. However, you should always be careful about this, and you should always prefer forward declarations instead of implicit ones (no matter if they are same or not). So, instead of just having forward declaration of the void prime() function (assuming that you will use it somewhere), you should also have a forward declaration of int input().
To see how can you pass any number of the arguments, consider this:
#include <stdio.h>
// Takes any number of the arguments
int foo();
// Doesn't takes any arguments
int bar(void)
{
printf("Hello from bar()!\n");
return 0;
}
int main()
{
// Both works
// However, this will print junk as you're not pushing
// Any arguments on the stack - but the compiler will assume you are
foo();
// This will print 1, 2, 3
foo(1, 2, 3);
// Works
bar();
// Doesn't work
// bar(1, 2, 3);
return 0;
}
// Definition
int foo(int i, int j, int k)
{
printf("%d %d %d\n", i, j, k);
return 0;
}
So, inside the definition of the function you're describing function arguments. However, declaration of the function is telling the compiler not to do any checks on the parameters.
Not declaring a prototype and relying on default argument/return type promotion is dangerous and was a part of old C. In C99 and onward it is illegal to call a function without first providing a declaration or definition of the function.
my question is, is it necessary to declare a void function with not arguments?
Yes. For this you have to put void in the function parenthesis.
void foo(void);
Declaring a function like
void foo();
means that it can take any number of arguments.
If prime is not used, then omit the declaration.
The code won't compile as C++, because the compiler would complain that function input is used but not declared. A C compiler might issue a warning, but C is more relaxed and does an implicit declaration of input as int input() which means that you can pass any value to input and input returns an int.
It is good style to always provide a function declaration before using the function. Only if you do this the compiler can see if you are passing too few, too many or wrongly typed arguments and how to correctly handle the return value (which might be short or char instead of int).
I'm using C to get a terminal size. That function will be call in the main function. Then I'm hoping to run it again to check if either the terminal size has changed or remain the same. This time the function are called in other function which is run_menu. For additional info, the run menu are also called in the main function. I will explain more in the code. The errors are "too few arguments to function 'get_terminal_size'.
//this function is to get the terminal size
//my idea is to use pointer as it will be use again in other function
void get_terminal_size(int *x, int* y)
{
int cols,lines;
assert(x);
assert(y);
#ifdef TIOCGSIZE
ioctl(0,TIOCGSIZE, &ts);
lines = ts.ts_lines;
cols = ts.ts_cols;
#elif defined(TIOCGWINSZ)
struct winsize ts;
ioctl(0,TIOCGWINSZ, &ts);
lines = ts.ws_row;
cols = ts.ws_cols;
#endif
*x = cols;
*y = lines;
}
//this function is to see either the size has changed or not
int change_terminal_size()
{
int new_cols, new_lines;
int x, y;
get_terminal_size(&x, &y);
#ifdef TIOCGSIZE
ioctl(0,TIOCGSIZE, &ts);
new_lines = ts.ts_lines;
new_cols = ts.ts_cols;
#elif defined(TIOCGWINSZ)
struct winsize ts;
ioctl(0,TIOCGWINSZ, &ts);
new_lines = ts.ws_row;
new_cols = ts.ws_cols;
#endif
log_debug("new lines=%d,new cols =%d",new_lines,new_cols);
if((new_cols !=x)||(new_lines != y)){
return 1;
}
return 0;
}
//this function is to run the menu.
static void run_menu()
{
//bla bla bla with other declaration and function
//i will not write it because its not related
while(1){
if (change_terminal_size()){
log_debug("the terminal has change size");
}
//and it will continue with other things
//this is the main function
int main()
{
//again with other declaration and function not related
get_terminal_size();
run_menu();
//continue on with other thing, then return 0
}
As you can see. I call the "get_terminal_size" function 2 times. Is it related to the problem that im having? As far as I know, if I'm using a pointer, then it shouldn't be any problem.
In here:
//this is the main function
int main()
{
get_terminal_size(); //<---Right here!
run_menu();
}
You don't pass any arguments to get_terminal_size.
get_terminal_size expects to be called with two arguments, thus the error "Too few arguments to function".
"Using a pointer" doesn't really have anything to do with it, nor does "Using a pointer" allow you to use the function from multiple places. All the pointers (x and y) do is allow the function to change values outside of its scope.
Sidebar: you probably ought to have get_terminal_size return a value - in this case probably a struct with an X field and a Y field. Functions that return values via side-effect are more difficult to reason about and more likely to contain bugs, although this particular example is probably fine since you're not mixing input arguments with output arguments.
Also your change_terminal_size() function looks pretty gnarly. Where are you keeping track of the old terminal size so you can compare it to the new terminal size?
get_terminal_size(int*, int*) is a function with two parameters of type int*. In order to call this function, you must pass it the appropriate number of arguments each with the correct type. In main, you call it with no arguments and your compiler complains, as it should.
The main function will need to pass some appropriate arguments - something like below:
int main()
{
//again with other declaration and function not related
int x = 0, y = 0;
get_terminal_size(&x, &y); // &x and &y both have type int*
run_menu();
//continue on with other thing, then return 0
}
You are calling a function which takes two parameters, but you are not using any parameters when you do it. You do use the correct number of parameters in change_terminal_size, which is why that function succeeds.
The good news, though, is that since get_terminal_size does not affect the outside world, you can replace main with:
int main()
{
run_menu();
return 0;
}