Function Pointers not working in getopt - c

I have some code which tests the robustness of a variety of PRNGs, and I want to choose which PRNG is being tested using options.
I have a function pointer type: typedef double (*voidPRNG_ptr)(void);
I have a testing function: test_results* investigator_alloc(int N, voidPRNG_ptr RNGp)
Where test_results is a typedef'ed struct.
I have PRNG functions: double box_muller(void), double rejection(void), double RNG(void), etc...
The following code in main works FINE:
int main(int argc, char** argv){
int N = atoi(argv[1]);
voidPRNG_ptr PRNGp = &box_muller;
test_results* results = investigator_alloc(N, PRNGp);
return 0;
}
The box_muller function is used as the RNG, and data is as expected.
This also WORKS FINE:
int main(int argc, char** argv){
int N = atoi(argv[1]);
voidPRNG_ptr PRNGp = &box_muller;
PRNGp = &rejection;
test_results* results = investigator_alloc(N, PRNGp);
return 0;
}
The rejection method is used as the RNG, as expected.
However, this DOESN'T work:
int main(int argc, char **argv){
int opt;
int atest = 0;
voidPRNG_ptr PRNGp = &RNG; //set default
while((opt = getopt(argc, argv, "abur")) != -1){
if(opt == 'a') {
PRNGp = &normal_approx;
atest = 1;
}
else if(opt == 'b') PRNGp = &box_muller;
else if(opt == 'u') PRNGp = &RNG;
else if(opt == 'r') PRNGp = &rejection;
}
printf("\n %d\n",atest);
int N = atoi(argv[1]);
//PRNGp = &rejection;
//PRNGp = &normal_approx;
//PRNGp = &box_muller;
test_results *results = investigator_alloc(N,PRNGp);
return 0;
}
I know that getopt is working as atest is set to the right value depending on the option selected. But there must be something wrong with the function pointer as the data is blank.
Any ideas?
Thanks!

The issue is that you're applying atoi() to the first command-line argument, which is the option that tells your program which RNG to use. Since argv[1] is not numeric, you end up with N=0 and no data.
Change argv[1] to argv[optind] (see Using the getopt function).

Related

How do I write an argument function properly?

I have to C program called contains.c that takes two text strings as arguments and prints "true" followed by a newline if the second string is entirely contained within the first, or "false" followed by a newline otherwise.
For instance(in the command prompt)
$ ./contains 'I have a really bad feeling about this' 'bad feeling'
true
$ ./contains 'To be or not to be' 'That is the question'
false
$ ./contains 'I am the walrus' 'I am the walrus'
true
$ ./contains 'the walrus' 'I am the walrus'
false
$ ./contains 'kmjnhbvc45&^$bn' '.'
false
Here is my code so far.
#include <stdio.h>
#include <string.h>
int main( int argc, char* argv[])
{
int i;
int j;
int lenst1;
int lenst2;
int pos1;
int pos2;
if (lenst2>lenst1)
{
printf("false");
return 0;
}
for (j=0; j<lenst1;j++)
{
for (i=0; i<lenst2; i++)
{
if (st2[i]==st1[j]) //NOT SURE HOW TO DEFINE "st2" and "st1"
{
pos1=j;
pos2=i;
while (pos2<lenst2)
{
pos2++;
pos1++;
if (st2[i]==st1[j])
{
}
else
{
printf("false\n");
return 0;
}
printf("true\n");
return 0;
}
}
}
}
}
I am not entirely sure how many flaws I have in my code but Xcode claimed that st2 and st1 needs to be defined.
It would be greatly appreciated if someone could help me.
You forgot to read in your arguments.
char* st1 = argv[1];
char* st2 = argv[2];
lenst1 = strlen(st1);
lenst2 = strlen(st2);
You've had most of it right, but here are a few of the things you missed:
test the number of arguments:
if (argc != 3) {
printf("wrong number of arguments provided\n");
return -1;
}
capture your required variables:
int i, j, pos1, pos2;
char* st1 = argv[1];
char* st2 = argv[2];
int lenst1 = strlen(argv[1]);
int lenst2 = strlen(argv[2]);
Replace your if-else block with if st2[i] != st1[j]
Declare your main function to be named main
End your function with return 0;
Write printf("false\n"); to pass your last test case. (do you see why?)
build gcc contains.c -o contains

How do I recall main using different arguments?

I have my program and it runs like I expected, however, I want to call it again but this time I want to use different arguments. How can I do that?
It seems I cant just use main(filename1,filename2)and then follow the same routine I did last before.
My main looks like this
int main(int argc,char* argv[])
{
if (argc<3)
{
printf("Error no filenames\n");
return -1;
}
char* filename=argv[1];
char* fileout=argv[2];
int count_Pharmacy;
int count_Surgicaly;
int count_General;
int count_Counselling;
char pick;
patient* Pharmacy_head=NULL;
patient* General_head=NULL;
patient* Surgical_head=NULL;
patient* Counselling_head=NULL;
dep* dep_head=NULL;
Counselling_head=get_patient(Pharmacy_head,filename,"Counselling");
Surgical_head=get_patient(Pharmacy_head,filename,"Surgical");
General_head=get_patient(Pharmacy_head,filename,"General");
Pharmacy_head=get_patient(Pharmacy_head,filename,"Pharmacy");
count_Pharmacy=count_patient(Pharmacy_head);
count_Surgicaly=count_patient(Surgical_head);
count_General=count_patient(General_head);
count_Counselling=count_patient(Counselling_head);
dep_head=make_deparments(dep_head,"Counselling","Dr. Willy",Counselling_head,count_Counselling);
dep_head=make_deparments(dep_head,"Surgical","Dr. Neo Cortex",Surgical_head,count_Surgicaly);
dep_head=make_deparments(dep_head,"General","Dr. Ann Imezechara",General_head,count_General);
dep_head=make_deparments(dep_head,"Pharmacy","Dr. Charles Xavier",Pharmacy_head,count_Pharmacy);
treatment(dep_head,fileout);
printf("The patients have been treated would you like to add another file?(Y/N)\n");
pick=fgetc(stdin);
if (pick=='y' || pick =='Y')
{
//this is where i would like to call main again but with diffrent arguments
}
else if(pick =='N' || pick=='n')
{
printf("Goodbye have a marvelous day\n");
}
else
{
printf("Thats not a valid input but ill take that as a no\n");
}
return 1;
}
The two arguments I called main with the first time are file names.
char * new_argv [4];
int new_argc = 3;
new_argv [0] = argv [0]; // program name
new_argv [1] = "file1";
new_argv [2] = "file2";
new_argv [3] = 0;
main (new_argc, new_argv);

Commands to execute functions in C

I'm using the LXLE 14.04 distribution of Linux.
I want to write a C program to read commands, interpret and perform them. I'd like the program to be efficient, and I do not want to use
a linked list.
The commands are operations on sets.
Each set can contain any of the values from 0 through 127 inclusive.
I decided to represent a set as an array of characters, containing 128 bits.
If bit at position pos is turned on then the number pos is in the set and if the bit at position pos is turned off then the number pos is
not present in the set. For example, if the bit at position 4 is 1, then the number 4 is present in the set, if the bit at position 11 is 1 then the number
11 is present in the set.
The program should read commands and interpret them in a certain way.
There are a few commands: read_set, print_set, union_set, intersect_set, sub_set and halt.
For example, the command read_set A,1,2,14,-1 in the terminal will cause the reading of values of the list into the specified set in the command.
In this case the specified set in the command is A. The end of the list is represented by -1. So after writing this command, the set A will contain the elements 1,2,14.
This is what I have so far.
Below is the file set.h
#include <stdio.h>
typedef struct
{
char array[16]; /*Takes 128 bits of storage*/
}set;
extern set A , B , C , D , E , F;
This is the file main.c
#include <stdio.h>
#include "set.h"
#include <string.h>
#include <stdlib.h>
set A , B , C , D , E , F; /*Variable definition*/
void read_set(set s,char command[])
{
int i, number = 0 , pos;
char* str_num = strtok(NULL,"A, ");
unsigned int flag = 1;
printf("I am in the function read_set right now\n");
while(str_num != NULL) /*without str_num != NULL get segmentation fault*/
{
number = atoi(str_num);
if(number == -1)
return;
printf("number%d ",number);
printf("str_num %c\n",*str_num);
i = number/8; /*Array index*/
pos = number%8; /*bit position*/
flag = flag << pos;
s.array[i] = s.array[i] | flag;
str_num = strtok(NULL, ", ");
if(s.array[i] & flag)
printf("Bit at position %d is turned on\n",pos);
else
printf("Bit at position %d is turned off\n",pos);
flag = 1;
}
}
void print_set(set s)
{
unsigned int flag = 1; int in_set = 0;
int i = 0;
while(s.array[i] != -1)
{
if(s.array[i] & flag)
{
in_set = s.array[i];
printf("%d,",in_set );
}
i++;
flag = 1;
}
}
int main()
{
#define CMD_LENGTH 256
char command[CMD_LENGTH]; char* letter;
printf("Please enter a command");
gets(command);
letter = strtok(command,"read_set ,");
switch(*letter)
{
case 'A':
{
read_set(A,command);
break;
}
case 'B':
{
read_set(B,command);
break;
}
case 'C':
{
read_set(C,command);
break;
}
case 'D':
{
read_set(D,command);
break;
}
case 'E':
{
read_set(E,command);
break;
}
case 'F':
{
read_set(F,command);
break;
}
}
return 0;
}
Clearly, it is not a good practice to write a bunch of switch statements and using strtok for each command, and repeating the code written in the main function for each command in order to call the different functions. I thought about using a pointer to a generic function, but since each function receives different parameters,
I do not think this is going to work.
Is there a better way of doing this?
Thanks in advance!
Update #1:
Here's the code. I've made some changes to it.
#include <stdio.h>
#include "set.h"
#include <string.h>
#include <stdlib.h>
set A , B , C , D , E , F; /*Variable definition*/
set sets[6];
/*Below I want to initialize sets so that set[0] = A set[1] = B etc*/
sets[0].array = A.array;
sets[1].array = B.array;
sets[2].array = C.array;
sets[3].array = D.array;
sets[4].array = E.array;
sets[5].array = F.array;
void read_set(set s,char all_command[])
{
int i, number = 0 , pos;
char* str_num = strtok(NULL,"A, ");
unsigned int flag = 1;
printf("I am in the function read_set right now\n");
while(str_num != NULL) /*without str_num != NULL get segmentation fault*/
{
number = atoi(str_num);
if(number == -1)
return;
printf("number%d ",number);
printf("str_num %c\n",*str_num);
i = number/8; /*Array index*/
pos = number%8; /*bit position*/
flag = flag << pos;
s.array[i] = s.array[i] | flag;
str_num = strtok(NULL, ", ");
if(s.array[i] & flag)
printf("Bit at position %d is turned on\n",pos);
else
printf("Bit at position %d is turned off\n",pos);
flag = 1;
}
}
typedef struct
{
char *command;
void (*func)(set,char*);
} entry;
entry chart[] = { {"read_set",&read_set} };
void (*getFunc(char *comm) ) (set,char*)
{
int i;
for(i=0; i<2; i++)
{
if( strcmp(chart[i].command,comm) == 0)
return chart[i].func;
}
return NULL;
}
int main()
{
#define PER_CMD 256
char all_comm[PER_CMD]; void (*ptr_one)(set,char*) = NULL; char* comm; char* letter;
while( (strcmp(all_comm,"halt") != 0 ) & (all_comm != NULL))
{
printf("Please enter a command");
gets(all_comm);
comm = strtok(all_comm,", ");
ptr_one = getFunc(comm);
letter = strtok(NULL,",");
ptr_one(A,all_comm);
all_comm[0] = '\0';
letter[0] = '\0';
}
return 0;
}
I get the following compile error:
main.c:9:8: error: expected ���=���, ���,���, ���;���, ���asm��� or ���attribute��� before ���.��� token
What's my mistake? How can I fix this?
Thanks a lot! #Claim Yang
However,in your case, using switch is almost the best solution to this.
Another way without switch is using a simple way to get an index. Here is a simple solution.
set sets[6];
read_set(sets[*letter - 'A'], command);
Then if you need to read a command, another array of pointers to functions is needed. Like below:
void (*functions[3])(set,char[]);
functions[0] = read_set;
And so on.
The point is coverting your string to an int, so it can be seen as an index of an array.
Then call functions like functions[string_to_int(string)](set,char[]);

is it possible to use getopt_long to parse arrays of strings similar to command line arguments in a C program?

I am aware that getopt should be used to parse command line arguments, and not strings.
However, I am confused by the fact that if I pass it an array of strings that "looks like" the argv variable, getopt_long seems to work, but only the first time that I call it. For the second, and all the subsequent times, that I call it it ignores any arguments and returns the default ones.
The reason I am doing this is that I am turning an application that used to take command line arguments in an "interactive" version of it that asks the user for some arguments, then does some actions based on those arguments, then asks for more arguments and so on.
The following code is a minimal example that reproduces the error
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
struct input_parameters{
char * d; // data set
};
int solver_help(int argc, char* const argv[], struct input_parameters * p)
{
int c;
p->d = "default name";
while (1)
{
static struct option long_options[] =
{
{"data", required_argument, 0, 'd'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long (argc, argv, "d:",
long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c)
{
case 'd': p->d = optarg;
break;
default:
printf("wrong option specification\n");
exit(-1);
}
}
return 0 ;
}
int main () {
int argc_first = 3;
char * const argv_first[] = { "getopt_test", "--data", "first" };
struct input_parameters first_input;
solver_help(argc_first, argv_first, &first_input);
printf("I think the data is: %s\n", first_input.d);
int argc_second = 3;
char * const argv_second[] = { "getopt_test","--data", "second" };
struct input_parameters second_input;
solver_help(argc_second, argv_second, &second_input);
printf("I think the data is: %s\n", second_input.d);
return 0;
}
The output of this code is
I think the data is: first
I think the data is: default name
From the manual page for getopt:
In order to use getopt() to evaluate multiple sets of arguments, or
to evaluate a single set of arguments multiple times, the variable
optreset must be set to 1 before the second and each additional
set of calls to getopt(), and the variable optind must be
reinitialized.
Modifying your code slightly gives you the desired results:
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
struct input_parameters {
char * d; // data set
};
int solver_help(int argc, char* const argv[], struct input_parameters * p)
{
p->d = "default name";
static struct option long_options[] =
{
{"data", required_argument, 0, 'd'},
{0, 0, 0, 0}
};
int option_index = 0;
optreset = 1; /* ADD THIS */
optind = 1; /* ADD THIS */
int c = getopt_long(argc, argv, "d:",
long_options, &option_index);
switch ( c )
{
case -1:
break;
case 'd':
p->d = optarg;
break;
default:
printf("in default case...\n");
printf("wrong option specification\n");
exit(EXIT_FAILURE);
}
return 0;
}
int main(void) {
int argc_first = 3;
char * const argv_first[] = { "getopt_test", "--data", "first" };
struct input_parameters first_input;
solver_help(argc_first, argv_first, &first_input);
printf("I think the data is: %s\n", first_input.d);
int argc_second = 3;
char * const argv_second[] = { "getopt_test","--data", "second" };
struct input_parameters second_input;
solver_help(argc_second, argv_second, &second_input);
printf("I think the data is: %s\n", second_input.d);
return 0;
}
with output:
paul#horus:~/src/sandbox$ ./go
I think the data is: first
I think the data is: second
paul#horus:~/src/sandbox$

Define custom command-line parameters in C?

I need to pass a 'key' as a parameter from terminal. It should run as ./a.out -k100101001
where 10011001 is the key and -k is the flag to specify it.
If I need to pass a filename along with the key it should run as ./a.out -k10011001 -iparameter.txt where parameter.txt is the filename and -i is the flag to specify that.
NOTE: I have several parameters to pass and parameter values are followed after the flag without space(-iparameter.txt), plus I don't know the order of the flags so doing something like this won't help.
int main(int argc, char **argv) {
if (argc == 2) {
if (!strcmp(argv[1], "-k")) something();
if (!strcmp(argv[1], "-i")) something();
}
Any suggestion for C? I'm using Ubuntu to run my program.
Thanks.
Using a loop through argv should do it.
int main(int argc, char *argv[])
{
int numArg;
for (numArg = 1; numArg < argc; numArg++)
{
if (argv[numArg][0] == '-')
{
switch (argv[numArg][1])
{
case 'k' : somethingAboutKey(argv[numArg] + 2); // The parameter's value is passed directly to the function
break;
case 'i' : somethingAboutFile(argv[numArg] + 2);
break;
}
}
}
}

Resources