Why do I see redefinition error in C? - c

Following is my code, I am trying to run it in Visual Studio.
#include <stdio.h>
#include <conio.h>
int main()
{
//int i;
//char j = 'g',k= 'c';
struct book
{
char name[10];
char author[10];
int callno;
};
struct book b1 = {"Basic", "there", 550};
display ("Basic", "Basic", 550);
printf("Press any key to coninute..");
getch();
return 0;
}
void display(char *s, char *t, int n)
{
printf("%s %s %d \n", s, t, n);
}
It gives an error of redefinition on the line where opening brace of function is typed.

You call display before declaring it, and in such cases the compiler assumes the return type is int, but your return type is void.
Declare the function before using it:
void display(char *s, char *t, int n);
int main() {
// ...
Also note, that you declare it as receiving char*, but pass string literals to it (const char*) either change the declaration, or change the arguments, e.g:
void display(const char *s, const char *t, int n);
int main()
{
// snip
display ("Basic", "Basic", 550);
//snap
}
void display(const char *s, const char *t, int n)
{
printf("%s %s %d \n", s, t, n);
}

Related

Function pointer pointing to functions with different number of arguments

How to handle assignment of the functions to one function pointer, each with different number of parameters ? The problem is that parameters differ in number and type. If possible give an example.
Function pointers can be cast in the same way as the other pointers. You will have a generic function pointer (similar to void * for storage types), and use it to hold/pass the address of the function. Before calling the function, you will need to cast it to the correct type.
Here is a working example:
#include <stdio.h>
typedef void (*generic_t)(void);
typedef int (*type2_t)(int);
typedef int (*type3_t)(int, char *s);
void test1(void) {
printf("Test 1\n");
}
int test2(int i) {
printf("Test 2 %i\n",i);
return i;
}
int test3(int i, char *s) {
printf("Test 3 %i, %s\n", i, s);
return i++;
}
int main(void) {
generic_t f1, f2, f3;
f1 = &test1;
f2 = (generic_t)&test2;
f3 = (generic_t)&test3;
f1();
int i = ((type2_t)f2)(10);
i = ((type3_t)f3)(20,"This is test");
}
In addition, you will need to implement a mechanism to recognize what is the type of function that the pointer is pointing to. One approach is to use a struct that holds the pointer and the enum of the type.
Another possibility is to create a union of different function pointer types:
union funptr {
void (*v)();
void (*vi)(int);
void (*vs)(char *);
int (*i)();
int (*ii)(int);
int (*iii)(int, int);
int (*is)(char *);
};
You can use void pointers to pass reference to the in and out parameters. Multiple parameters and return values you can wrap in the structs. The return value may return status.
Sometimes it used in low-level device drivers.
typedef int func(void *, void *);
func *fptr;
struct s1
{
int i;
char *s;
};
int test1(void *in, void *out)
{
printf("Test 1\n");
return 0;
}
int test2(void *in, void *out)
{
int *i = in;
printf("Test 2 %i\n", *i);
return *i;
}
int test3(void *in, void *out)
{
struct s1 *s = in;
printf("Test 3 %i, %s\n", s -> i, s -> s);
return ++s -> i;
}
int main(void)
{
fptr = test1;
fptr(NULL, NULL);
fptr = test2;
fptr((int[]){10}, NULL);
fptr = test3;
printf("Returned value: %d\n", fptr(&(struct s1){20,"This is test"}, NULL));
}
You have to declare a new function pointer type for every different signature that you need to handle.

Allocating memory for an array of struct i get an error

the code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
typedef struct word{
char word[20];
int occurrance;
} word;
int array_word_creator(word *array, FILE *fp);
void initialize(word array[], int max);
void comparator(word array[], int max, FILE *fp);
void printer(word array[], int max);
int main(int argc, char *argv[])
{
FILE *f_sent, *f_words;
word *array;
int arr_lenght=0;
if(argc!=3)
{
printf("Wrong argument number, please use NAME FILE1 FILE2;\n");
exit(EXIT_FAILURE);
}
if((f_sent=fopen(argv[1], "r"))==NULL||(f_words=fopen(argv[1], "r"))==NULL)
{
printf("Can't find or open the files, please check if the name is correct\n");
exit(EXIT_FAILURE);
}
arr_lenght=array_word_creator(array, f_words);
comparator(array, arr_lenght ,f_sent);
printer(array, arr_lenght);
return 0;
}
int array_word_creator(word *array, FILE *fp)
{
int n,i=0;
fscanf(fp,"%d",&n);
*array= malloc(n*sizeof(word));
while(fscanf(fp,"%s", array[i].word)!=EOF)
{
i++;
}
initialize(array,n);
return n;
}
void initialize(word array[], int max)
{
int i;
for(i=0;i<max;i++)
{
array[i].occurrance=0;
}
}
void comparator(word array[], int max, FILE *fp)
{
char word[MAX];
int i;
while(fscanf(fp,"%s", word)!=EOF)
{
for(i=0;i<max;i++)
{
if(strcmp(word, array[i].word)==0)
{
array[i].occurrance++;
}
}
}
}
void printer(word array[], int max)
{
int i;
for(i=0;i<max;i++)
{
if(array[i].occurrance>0)
{
printf("The word '%s' occurs %d times\n", array[i].word, array[i].occurrance);
}
}
}
And the compiler says me:
C:\Users\Matteo\Google Drive\Programming\C\lab3\es1\main.c|47|error: incompatible types when assigning to type 'word' from type 'void *'|
I just studied memory allocation so i'm having some trouble with it, especially with structures. If possible, plase link me also some good docs about this subject.
thank you!
In main word *array is a pointer to a structure of type word.
You then pass array, which does not point to anything, to the function array_word_creator.
You then try to assign the pointer returned by malloc to where array is pointing, but it doesn't point anywhere yet, and even if it did, it would be pointing to a word (since it is a word *), so it can't store a pointer, hence the compiler error.
If you want to set the array pointer in main to the result of malloc, you have to pass a pointer to the pointer. int array_word_creator(word **array, FILE *fp), then you would call it by doing array_word_creator(&array, .... ), the your *array = malloc will work.
You want this:
...
arr_lenght = array_word_creator(&array, f_words);
...
int array_word_creator(word **array, FILE *fp)
{
int n, i = 0;
fscanf(fp, "%d", &n);
*array = malloc(n * sizeof(word));
while (fscanf(fp, "%19s", (*array)[i].word) != EOF)
{
i++;
}
initialize(*array, n);
return n;
}

How do I pass a function AND a variable list of arguments to another function in C?

I want to pass an arbitrary function and it's arguments to another function in C.
For example like the code below (which obviously does not work)
#include <stdio.h>
void doit(int (*f)(...), char *fname, ...)
{
va_list argptr;
va_start(argptr, fname);
f(argptr)
va_end(argptr);
}
int func1(char *a, int b)
{
fprintf(stderr, "func1 %s %d\n", a, b);
}
int func2(char *a, int b, int c)
{
fprintf(stderr, "func2 %s %d %d\n", a, b, c);
}
int main(int argc, char **argv)
{
doit(func1, "func1", "blah", 10);
return 0;
}
You need va_list forwarders to your functions if you want to have them participate in such a scheme. Something like:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void doit(int (*f)(va_list va), char *fname, ...)
{
va_list argptr;
va_start(argptr, fname);
f(argptr);
va_end(argptr);
}
int func1(const char *a, int b)
{
fprintf(stderr, "func1 %s %d\n", a, b);
return 0;
}
int func1_va(va_list va)
{
const char * a = va_arg(va, const char*);
int b = va_arg(va, int);
return func1(a,b);
}
int func2(const char *a, int b, int c)
{
fprintf(stderr, "func2 %s %d %d\n", a, b, c);
return 0;
}
int func2_va(va_list va)
{
const char *a = va_arg(va, const char*);
int b = va_arg(va, int);
int c = va_arg(va, int);
return func2(a,b,c);
}
int main(int argc, char **argv)
{
doit(func1_va, "func1", "blah", 10);
doit(func2_va, "func2", "blahblah", 100, 200);
return 0;
}
Output
func1 blah 10
func2 blahblah 100 200
First: don't mess with va_args if you have no idea how arguments are passed or how activation records work.
Your best bet is to declare doit() with excessively many args:
void doit( void ( *p_func )(), int arg1, int arg2, int arg3, int arg4, int arg5 );
and just call ( *p_func )() with all those arguments. If the function being called doesn't reach for more than it needs, there won't be any trouble. Even if it does, it will just pull garbage values off the stack.

Passing an argument to function pointer

I just can't figure out how to pass an Argument like in the following scenario:
#include<stdio.h>
void quit(const char*);
int main(void){
const char *exit = "GoodBye";
void (*fptr)(const char*) = quit;
(*fptr)(exit);
return 0;
}
void quit(const char *s){
printf("\n\t%s\n",s);
}
This is how my program should work and it does, but when I make a text menu i just can't figure out how to do it:
#include<stdio.h>
#include<stdlib.h>
int update(void);
int upgrade(void);
int quit(void);
void show(const char *question, const char **options, int (**actions)(void), int length);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])(void) = {update,upgrade,quit};
show(question,options,actions,3);
return 0;
}
int update(void){
printf("\n\tUpdating...\n");
return 1;
}
int upgrade(void){
printf("\n\tUpgrade...\n");
return 1;
}
int quit(void){
printf("\n\tQuit...\n");
return 0;
}
void show(const char *question, const char **options, int (**actions)(void), int length){
int choose = 0, repeat = 1;
int (*act)(void);
do{
printf("\n\t %s \n",question);
for(int i=0;i<length;i++){
printf("%d. %s\n",(i+1),options[i]);
}
printf("\nPlease choose an Option: ");
if((scanf("%d",&choose)) != 1){
printf("Error\n");
}
act = actions[choose-1];
repeat = act();
if(act==0){
repeat = 0;
}
}while(repeat == 1);
}
Here I need to change the quit function (int quit(void); to int quit(char *s){};) like in the First example and call it with an argument like const char *exit = "GoodBye"; ==>> (*fptr)(exit);
I know that at this point my program takes only void as argument, but I done it only to illustrate the problem.
I'm very confused about this.
EDIT:
this int (*actions[3])(void) I think is an Array of Function pointers and all 3 function pointers takes void as argument, but I need to know if i can use one pointer to take an argument or i have to re-code the whole program.
Since you have an array of function pointers, all the functions need to be of the same type. So at the very least each function should take a const char * (not all functions need to use it) and the array type should be changed to match.
If you want something more flexible, you can have the functions accept a single void * so each function can be passed a different parameter which it then casts to the appropriate type. This is how pthreads passes parameters to functions which start a new thread. You will lose some compile-time type checking with this, so be careful if you go this route.
EDIT:
An example of the latter:
#include<stdio.h>
#include<stdlib.h>
int update(void *);
int upgrade(void *);
int quit(void *);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])(void *) = {update,upgrade,quit};
show(question,options,actions,3);
return 0;
}
int update(void *unused){
printf("\n\tUpdating...\n");
return 1;
}
int upgrade(void *unused){
printf("\n\tUpgrade...\n");
return 1;
}
int quit(void *message){
printf("\n\tQuit...%s\n", (char *)message);
return 0;
}
void show(const char *question, const char **options, int (**actions)(void *), int length){
...
if (act == quit) {
repeat = act("GoodBye");
} else {
repeat = act(NULL);
}
...
}
Since you are using a an array of function pointers, you don't know which ones to take which arguments. But have You can avoid re-coding it by making the functions to take "unspecified number of arguments". i.e. Remove the void from as the parameter from function definitions and prototypes from of the function pointers and from the quit() function.
int quit(const char*);
void show(const char *question, const char **options, int (**actions)(), int length);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])() = {update,upgrade,quit};
...
}
int quit(const char *msg){
printf("\n\tQuit...%s\n", msg);
return 0;
}
void show(const char *question, const char **options, int (**actions)(), int length){
....
int (*act)();
....
}
This works because C allows a function with no explicit parameters to take "unspecified number of arguments". Otherwise, you need to make all functions have similar signatures.

how to return a char array from a function in C

I want to return a character array from a function. Then I want to print it in main. how can I get the character array back in main function?
#include<stdio.h>
#include<string.h>
int main()
{
int i=0,j=2;
char s[]="String";
char *test;
test=substring(i,j,*s);
printf("%s",test);
return 0;
}
char *substring(int i,int j,char *ch)
{
int m,n,k=0;
char *ch1;
ch1=(char*)malloc((j-i+1)*1);
n=j-i+1;
while(k<n)
{
ch1[k]=ch[i];
i++;k++;
}
return (char *)ch1;
}
Please tell me what am I doing wrong?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *substring(int i,int j,char *ch)
{
int n,k=0;
char *ch1;
ch1=(char*)malloc((j-i+1)*1);
n=j-i+1;
while(k<n)
{
ch1[k]=ch[i];
i++;k++;
}
return (char *)ch1;
}
int main()
{
int i=0,j=2;
char s[]="String";
char *test;
test=substring(i,j,s);
printf("%s",test);
free(test); //free the test
return 0;
}
This will compile fine without any warning
#include stdlib.h
pass test=substring(i,j,s);
remove m as it is unused
either declare char substring(int i,int j,char *ch) or define it before main
Lazy notes in comments.
#include <stdio.h>
// for malloc
#include <stdlib.h>
// you need the prototype
char *substring(int i,int j,char *ch);
int main(void /* std compliance */)
{
int i=0,j=2;
char s[]="String";
char *test;
// s points to the first char, S
// *s "is" the first char, S
test=substring(i,j,s); // so s only is ok
// if test == NULL, failed, give up
printf("%s",test);
free(test); // you should free it
return 0;
}
char *substring(int i,int j,char *ch)
{
int k=0;
// avoid calc same things several time
int n = j-i+1;
char *ch1;
// you can omit casting - and sizeof(char) := 1
ch1=malloc(n*sizeof(char));
// if (!ch1) error...; return NULL;
// any kind of check missing:
// are i, j ok?
// is n > 0... ch[i] is "inside" the string?...
while(k<n)
{
ch1[k]=ch[i];
i++;k++;
}
return ch1;
}
Daniel is right: http://ideone.com/kgbo1C#view_edit_box
Change
test=substring(i,j,*s);
to
test=substring(i,j,s);
Also, you need to forward declare substring:
char *substring(int i,int j,char *ch);
int main // ...

Resources