Command Line Argument - c

I am having trouble figuring out how to make this code work. What is suppose to is depending on the arguments giving from the command line, it suppose to print out a greeting.
int main (int argc, char *argv[]) {
double testscore;
if (argc == 2) {
printf("Hello, Mr.%s.\n", argv[1]);
}
else if (argc == 3 && argc == testscore) {
testscore = atof(argv[2]);
printf("Hi, Mr.%s, your score is %.1f\n", argv[1], testscore);
}
else {
printf("My name is %s %s.\n", argv[1], argv[2]);
}
}
If someone puts only their last name, then the terminal will print out...
Hello, Mr. last_name
...because they only put in one argument. This works fine.
The part where I am stuck on is when the command line arguments given are == 3. If 3 arguments are given then either the terminal is suppose to print out...
Hi, Mr. last_name, your test score is test_score
...or...
My name is first_name last_name.
If I put in the command line arguments only the last name and test score (Smith 3.4) then it prints out (example using the last name Smith) then it prints out...
My name is Smith 3.4
However, it does work for putting in the first name and last name (John Smith). This gives...
My name is John Smith.
I do not want the answer, I just want what I am doing wrong and hints on how to fix it.

I do not want the answer, I just want what I am doing wrong and hints on how to fix it.
Problem 1: You are using testscore variable before it is being initialized.
Problem 2: You are not performing error handling with atof. I would suggest to use strtod(). You can perform some error handling with it to know that the third argument is a float or not. You can also create your own implementation of atof() which will convert and report error in conversion, if any.
Hint: Try to first check that the number of arguments passed to the c program. After that, try to convert third argument to float using strtod() or your own implementation. If it successfully converts, assign the result of float convrsion to test_score and print last_name and testscore. If not, then consider third argument as last_name and print first_name and last_name.

Your problem is with this line:
else if (argc == 3 && argc == testscore) {
In fact, when argc == 3, then you want to check if argv[2] is a numeric argument.
else if ( (argc==3) && (is_numeric_arg(argv[2])==1)) {
A possible implementation would be:
int is_numeric_arg(char* arg)
{
int isInt = 0;
int isFloat = 0;
int isChar = 0;
char* currChar;
int i = 0;
currChar = arg;
isInt = 1;
while (*currChar != '\0')
{
if(*currChar < '0' || *currChar > '9')
{
if(*currChar == '.' && isInt == 1)
{
isInt = 0;
isFloat = 1;
}
else
{
isInt = 0;
isChar = 1;
}
}
currChar++;
}
if (isChar == 1){ return 0; } // argument is a string
else { return 1; } // argument is a int or float
}
int main (int argc, char *argv[]) {
double testscore;
if (argc == 2) {
printf("Hello, Mr.%s.\n", argv[1]);
}
else if ( (argc==3) && (is_numeric_arg(argv[2])==1)) {
testscore = atof(argv[2]);
printf("Hi, Mr.%s, your score is %.1f\n", argv[1], testscore);
}
else {
printf("My name is %s %s.\n", argv[1], argv[2]);
}
}
I did not test the code and there is probably a better way to check that the argument from the command line is "numeric".

Got it the answer guys. To check it without using another function, it would be
....
else if ( argc==3 && sscanf(argv[2], "%f", testscore)
{
testscore = atof(argv[2]);
printf("Hi, Mr.%s, your score is %.1f\n", argv[1], testscore);
}
...

Related

Print using command line arguments

Im trying make a program print a specific output using a enviroment variable in the command line, but the program seems to be stuck on my first input.
Here's my code
#include <stdio.h>
#include <stdlib.h>
void print_data(char*select);
int main (int argc, char * argv[]){
int ret;
char *ch = NULL;
if( argc == 2)
{
ch = argv[1];
}
else
{
ch = getenv("V1");
}
void print_data(ch);
return 0;
}
void print_data(char* select){
if(select, "k")
{
printf("Value set to key\n");
}
else if(select, "l")
{
printf("Value set to last name\n");
}
else if (select, " ")
{
printf("Value set to %s\n", select);
}
}
My problem is that the program either only prints "Value set to key" or "Value set to last name".
How can I use the pointer in Print_data to check what command is entered in the command line?
Output:
if(select, "k") is almost certainly not doing what you want, but it is not entirely clear what it is that you want. That expression is equivalent to if(1), which is why you get the behavior you see. Perhaps you intend:
if( select[0] == 'k' ) ...
else if( select[0] == 'l' ) ...
else if( select[0] == ' ' ) ...
which would be better written:
switch( select[0] ) {
case 'k': ...;
...

Trouble reading in Tokens in C

I can't seem to figure out, how to correctly read in a .txt file that has the following appereance: (example)
+ 1
+ 2
- 2
+ 5
p -1
? 5
and so on...
what I need now is to store the operator / token which can be '+' '-' 'p' or something like that, and the int that follows in two different variables because I need to check them later on.
char oprtr[1];
int value;
FILE *fp = fopen(args[1], "r");
while(!feof(fp) && !ferror(fp)){
if(fscanf(fp, "%s %d\n", oprtr, &value) < 1){
printf("fscanf error\n");
}
if(strcmp(oprtr, "+") == 0){
function1(bst, value);
} else if(strcmp(oprtr, "-") == 0){
function2(bst, value);
} else if((strcmp(oprtr, "p") == 0) && value == -1){
function3(root);
//some other functions and so on...
}
printing out oprtr and value in the loop shows that they are not being red in correctly, but it does compile. Does someone have a solution?
You have single characters, you can use == to compare them instead of strcmp. Just read the input in pairs and use a switch for example.
char c;
int x;
while(fscanf(fp, "%c %d", &c, &x) == 2)
{ switch(c)
{ case '+': /* ... */
}
}
Your string oprtr is too small to hold anything but an empty string (remember that C strings need a terminating 0 character!). So:
char oprtr[1];
needs to be at least:
char oprtr[2]; // string of maximum size 1
or more defensively:
char oprtr[256]; // string of maximum size 255
You can use the fscanf function, you can get the input from the file.
int fscanf(FILE *stream, const char *format, ...);
fscanf(fp," %c %d",&c,&d);

C - Comparing two characters

I am having trouble comparing two characters. I've written a very basic C problem to try out command line arguments.
Here is my code so far:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char ch;
char *type = "";
char *gender = "";
int baby = 0;
int count = 0;
/* Options:
* -t = type of pet
* -g = gender
* -b = baby or adult
*/
while ((ch = getopt(argc, argv, "t:g:b")) != EOF)
switch (ch) {
case 't':
type = optarg;
break;
case 'g':
gender = optarg;
break;
case 'b':
baby = 1;
break;
default:
fprintf(stderr, "Invalid option.\n");
return 1;
}
argc -= optind;
argv += optind;
printf("You have chosen a %s.\n", type);
if (gender == 'f')
puts("It's a girl");
if (gender == 'b')
puts("It's a boy.");
// The main command line arguments should be about the traits of the pet
printf("%s", "Traits: ");
for (count = 0; count < argc; count++)
printf("%s ", argv[count]);
return 0;
}
So if I type this into the terminal:
$ ./pet_shop -t dog -g f cute small
I get this as output:
You have chosen a dog:
Traits: cute small
The output it missing information about the gender, it should be a girl since I entered f. But I tried checking by printf("%i", gender) which gave the value 0. Is g == 'f' the incorrect way of comparing two characters?
gender is a char*, i.e. a pointer to a string's first charadcter. When you compare that to a single char, both the char and the pointer are converted to integers and an integer comparison is done.
To compare strings, use strcmp from <string.h>:
if (strcmp(gender, "f") == 0)
// it's a girl
Note the double quote (") which signifies a string, rather than a single character.
The problem is that you're comparing a string (or rather, a char*) to a char. This comparison (i.e. if(gender == 'f')) will compare the raw pointer value to the character instead of comparing the contents of the string to the character. Instead, you need to dereference the pointer and then compare that value, or index into the string, i.e. if(gender[0] == 'f').
Of course, it would also be a good idea to check that the string actually contains something before attempting that in order to avoid a segfault.
You have:
char *gender = "";
So gender is a string, not a character. To compare strings, use strcmp.
You first declared gender as a string:
char *gender = "";
Then you later treat is as a single character:
if(gender == 'f')
[...]
if(gender == 'b')
You need to clarify in your own mind what gender is, before you try and code it.
Pick one definition, and stick with it.

Storing details into C Structure

I'm writing the C program to find the function and calculate the number of lines of a function in C file and I am storing it into a structure. I've given my codes below.
#include <stdio.h>
#include <string.h>
#define SIZE 1024
struct fundetails
{
int nooflines;
char *funcname;
}s[20];
char *ffname(char *line)
{
int i=1,j=0;
char *dt;
char name[SIZE];
strtok(line,"(");
dt = strchr(line,' ');
if(dt[i] == '*')
i++;
while(dt[i] != '\0')
{
name[j]=dt[i];
i++;
j++;
}
name[j] ='\0';
return name;
}
int main(int argc, char **argv)
{
if(argc < 2)
{
printf("Give the filename \n");
printf("Usage: %s filename\n", argv[0]);
return -1;
}
int i, lines =0, funlines =0,count =0, fn =0, flag =0, size=0,emptyflag=0;
char c[SIZE],b[SIZE];
char *fname;
FILE *fd;
fd = fopen(argv[1],"r");
while(fgets(c,SIZE,fd))
{
emptyflag=0;
lines++;
size = strlen(c);
if(size == 1 && (strcmp(c,"\n"))== 0)
emptyflag=1;
for(i=0;i<size;i++)
{
while( c[i] =='\t' || c[i] == ' ')
{
i++;
}
if( c[i] == '{')
{
count++;
if(flag)
{
if(!emptyflag)
funlines++;
else
emptyflag=0;
}
if(count == 1)
{
fn++;
printf("Function %d is Started..............\n", fn);
flag = 1;
fname=ffname(b);
printf("Function name is:%s\n",fname);
}
break;
}
else if( c[i] == '}')
{
count--;
if(!count)
{
flag = 0;
printf("No of lines in the function %d is: %d\n", fn, funlines);
printf("Function %d is finished..........\n", fn);
s[fn-1].nooflines=funlines;
s[fn-1].funcname=fname;
funlines = 0;
}
else
{
if(!emptyflag)
funlines++;
else
emptyflag=0;
}
break;
}
else if(flag)
{
if(!emptyflag)
funlines++;
else
emptyflag=0;
break;
}
}
strcpy(b,c);
}
printf("FUN_NAME\tNO_OF_LINES\n");
for(i=0;i<fn;i++)
{
printf("%s\t\t%d\n",s[i].funcname,s[i].nooflines);
}
return 0;
}
It produces warning as try.c:26:2: warning: function returns address of local variable [enabled by default]. And It produces output as given below.
Function 1 is Started..............
Function name is:fundetails
No of lines in the function 1 is: 2
Function 1 is finished..........
Function 2 is Started..............
Function name is:dhahira
No of lines in the function 2 is: 1
Function 2 is finished..........
Function 3 is Started..............
Function name is:add
No of lines in the function 3 is: 3
Function 3 is finished..........
Function 4 is Started..............
Function name is:sub
No of lines in the function 4 is: 9
Function 4 is finished..........
Function 5 is Started..............
Function name is:main
No of lines in the function 5 is: 13
Function 5 is finished..........
FUN_NAME NO_OF_LINES
main 2
main 1
main 3
main 9
main 13
I'm storing function name and no of lines in same loop.WQhile i1m running it in GDB,for each time of
s[fn-1].nooflines=funlines;
s[fn-1].funcname=fname;
above line,the number of line is storing in a structure correctly.But not in the case of
function name.
Problem:I don't understand that why is it working properly for line and not working for function name? is it because of that warning? Please guide me, Thanks.
In ffname(), name[] is local, it's pushed to stack when execute the function. After ffname() return, the stack is popped, that means the memory seized by name[] got released, system could reuse the memory, but before the memory is reused, data is still there. That's why sometime it works and sometime not. Also, that's why you get warning.
You should define funcname in the struct as array rather than pointer. Because when funcname, you always point funcname to same name[], while name[] is written in each loop, so that at last you print same name 5 times.
After you change funcname to array, you should use strcpy to copy name:
strcpy(funcname, name); // this is right way when funcname is array
Rather than:
funcname = name;
First make the struct
struct fundetails
{
int nooflines;
char funcname[128];
}s[20];
then fix the returning value of the func ffname: you can't return a pointer to data that will disappear going out of scope (in this case, the function's end). As cheap quick modification, just turn your
char name[SIZE];
into
static char name[SIZE];
Then
strcpy(s[fn-1].funcname, fname);
instead of your
s[fn-1].funcname=fname;
The output would be like
FUN_NAME NO_OF_LINES
fundetails
2
ffname 15
main 82
I haven't checked how you identify functions but it seems too much naive. (The answer may not fix all the problem of your code; e.g. there could be path in your code that brings to the use of fname before it being assigned?...)

How to parse integer command line arguments in C?

I would like a user to pass either two parameters or leave it blank. For instance:
./program 50 50
or
./program
When I tried to use int main(int argc, char *argv[]), first thing I have done was to change char *argv[] to int *argv[] but it did not work. What I want is from the user is just to enter two integers between 0 and 100. So if it is not two integers then it should give an error.
I was sort of thinking to give out an error with types (as I used to program on C#) but whatever I enter, argv[1] would be 'char' type all the time.
So what I have done is
for (int i = 0; i <= 100; i++) {
//printf("%d", i);
if (argv[1] == i) {
argcheck++;
printf("1st one %d\n", i);
}
else if (argv[2] == i) {
argcheck++;
printf("2nd one %d\n", i);
}
This does not work as well. Also it gives warning when compiling, but if I change argv with atoi(argv[1]) for instance, then it gives a Segmentation fault (core dumped) error.
I need a simple way to solve this problem.
EDIT:
So I fixed with atoi(), the reason why it was giving segmentation fault was because I was trying it with null value when I have no parameter. So I fixed it up by adding an extra cond. But now the problem is if the value is let's say
./program asd asd
Then the output of atoi(argv[1]) would be 0. Is there a way to change this value?
Don't use atoi() and don't use strtol(). atoi() has no error checking (as you found out!) and strtol() has to be error-checked using the global errno variable, which means you have to set errno to 0, then call strtol(), then check errno again for errors. A better way is to use sscanf(), which also lets you parse any primitive type from a string, not just an integer, and it lets you read fancy formats (like hex).
For example, to parse integer "1435" from a string:
if (sscanf (argv[1], "%i", &intvar) != 1) {
fprintf(stderr, "error - not an integer");
}
To parse a single character 'Z' from a string
if (sscanf (argv[1], "%c", &charvar)!=1) {
fprintf(stderr, "error - not a char");
}
To parse a float "3.1459" from a string
if (sscanf (argv[1], "%f", &floatvar)!=1) {
fprintf(stderr, "error - not a float");
}
To parse a large unsigned hexadecimal integer "0x332561" from a string
if (sscanf (argv[1], "%xu", &uintvar)!=1) {
fprintf(stderr, "error - not a hex integer");
}
If you need more error-handling than that, use a regex library.
This will do:
int main(int argc, char*argv[])
{
long a,b;
if (argc > 2)
{
a = strtol(argv[1], NULL, 0);
b = strtol(argv[2], NULL, 0);
printf("%ld %ld", a,b);
}
return 0;
}
The arguments are always passed as strings, you can't change the prototype of main(). The operating system and surrounding machinery always pass strings, and are not able to figure out that you've changed it.
You need to use e.g. strtol() to convert the strings to integers.
You want to check whether
0 or 2 argument is received
two values received are between 0 and 100
received argument is not a string. If string comes sscanf will return
0.
Below logic will helps you
int main(int argc, char *argv[])
{
int no1 = 0, no2 = 0, ret = 0;
if ((argc != 0) && (argc != 2))
{
return 0;
}
if (2 == argc)
{
ret = sscanf(argv[1], "%d", &no1);
if (ret != 1)return 0;
ret = sscanf(argv[2], "%d", &no2);
if (ret != 1)return 0;
if ((no1 < 0) || (no1 >100)) return 0;
if ((no2 < 0) || (no2 >100)) return 0;
}
//now do your stuff
}
The things you have done so innocently are blunder in C. No matter what, you have to take strings or chars as your arguments and then later you can do whatever you like with them. Either change them to integer using strtol or let them be the strings and check each char of the string in the range of 48 to 57 as these are the decimal values of char 0 to 9. Personally, this is not a good idea and not so good coding practice. Better convert them and check for the integer range you want.
You can still use atoi, just check whether the argument is a number first ;)
btw ppl will tell you goto is evil, but they're usually brainwashed by non-sensible "goto is bad", "goto is evil", "goto is the devil" statements that were just tossed out without elaboration on the internet.
Yes, spaggethi code is less managable. And goto in that context is from an age where it replaced functions...
int r, n, I;
for (I = 0; I < argc; ++I)
{
n = 0;
do
if ( !((argv + I) [n] >= '0' && (argv + I) [n] <= '9') )
{
err:
fprintf(stderr,"ONLY INTEGERS 0-100 ALLOWED AS ARGUMENTS!\n");
return 1;
}
while ((argv + I) [++n] != '\0')
r = atoi(argv[I]);
if (r > 100)
goto err;
}
You can not change the arguments of main() function. So you should just use atoi() function to convert arguments from string to integer.
atoi() has its drawbacks. Same is true for strtol() or strtoul() functions. These functions will return a 0 value if the input to the function is non-numeric i.e user enters asdf or anything other than a valid number. To overcome this you will need to parse the string before passing it to atoi() and call isdigit() on each character to make sure that the user has input a valid number. After that you can use atoi() to convert to integer.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
main(int argc,char *args[])
{
int i,sum=0;
for(i=0;i<=argc;i++)
{
printf("\n The %d argument is: %s",i,args[i]);
}
printf("\nTHe sum of given argumnets are:");
for(i=1;i<argc;i++)
{
int n;
n=atoi(args[i]);
printf("\nN=%d",n);
sum += n;
}
printf("\nThe sum of given numbers are %d",sum);
return(0);
}
check this program i added another library stdlib.h and so i can convert the character array to string using function atoi.

Resources