-1
int main (int argc, char* argv[]){

    int toSleep;
    int produce; 
    int consume; 
    int i = 0;
    //get the values for sleep, produce, consume 
    toSleep = atoi(argv[1]);
    produce = atoi(argv[2]);
    consume = atoi(argv[3]);
    //check if the user input a vaild inpusts 

    //if(argc !=4){
   //printf("You are missing an input\n");
  //        exit(0);
  //}`enter code here`
    if(toSleep == '\0' ||  produce == '\0' || consume == '\0' ){
        printf("You are missing an input\n");
        exit(0);
    }else if (toSleep <=0 || produce<= 0 || consume <=0 ){
        printf("Please provide a vaild inputs \n");
        exit(0);
    }else {
    //continue to the program 
}

I am trying to make sure that the user will input exactly 3 inputs; if one is missing or null, I should print an error message and terminate the program. I always get this error when I tried to compile it

./a4  
 makefile:5: recipe for target 'semaphore' failed make: ***
[semaphore] Segmentation fault (core dumped)

Can someone tell me what I did wrong here?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mariam Adel
  • 7
  • 1
  • 1
  • 7
  • You commented out the `if` that uses `argc`, but that's about how you'd verify exact three arguments. Is that error when you try to compile or when you try to run the program? – Stephen Newell Mar 13 '18 at 03:01
  • Note that if you pass `NULL` to `atoi()` then undefined behavior will occur. So it would be too late to check, also `'\0'` is just fancy notation for `0`, it's to indicate that you intend to compare with the *null* character in a string, but it would not mean that `atoi()`'s argument was `NULL`. What you want is so simple that I'm sincerly surprised that you asked, google that up. – Iharob Al Asimi Mar 13 '18 at 03:03
  • I'm confused by the paragraph under the example. What is 'semaphore'? is that the name this program compiles to? You might get more help if you include the makefile, the command-line you use to run it, and the output it produces (with good formatting) – lockcmpxchg8b Mar 13 '18 at 03:04
  • I did the comment part and still give me the same error. Plus does it going to work if the user input less than or more than 3 items or not. – Mariam Adel Mar 13 '18 at 03:05
  • my make file is a4: a4.c gcc -g -pthread -o a4 a4.c semaphore: ./a4 – Mariam Adel Mar 13 '18 at 03:05
  • @StephenNewell when I run it – Mariam Adel Mar 13 '18 at 03:09
  • 1
    You really should add a formatted version of the Makefile to the question. If I'm guessing correctly at how to format that, `semaphore` is a Makefile target with no pre-requisites, whose recipe just runs `a4`...with no arguments...so of course the program crashes...you're indexing past the bounds of argv. – lockcmpxchg8b Mar 13 '18 at 03:13
  • Move the `if` before you access `argv`. Of course it's going to crash if you're accessing out of bounds memory. – Stephen Newell Mar 13 '18 at 03:14

1 Answers1

6

Check the value of argc, it tells you how many arguments have been passed.

int main(int argc, char **argv)
{
    if(argc != 4)
    {
        fprintf(stderr, "usage: %s sleep produce consume\n", argv[0]);
        return 1;
    }

    toSleep = atoi(argv[1]);
    produce = atoi(argv[2]);
    consume = atoi(argv[3]);
    ....
}

Note that argc is the value of the number of arguments plus the filename of the executed binary (more precisely how the binary was executed) and argv[0] is always that string. So when argc == 4, 3 arguments have been passed (argv[1], argv[2], argv[3]) and argv[4] == NULL. The argv list is always NULL terminated.

If you wan to check if an individual argv[i] is NULL, then

if(argv[i] == NULL)
{
    // argv[i] is NULL
}

but you usually don't have to do these checks if you properly checked argc. But sometimes it makes sense to check against NULL, for example when you have variable number of arguments, when a program can take either 3 or 4 arguments, then checking if argv[3] == NULL is also an option to see if the last optional argument has been passed. But I prefer checking argc instead anyway.

Note also that toSleep, produce and consume are int, although the check

if(toSleep == '\0' ||  produce == '\0' || consume == '\0' )

is technically correct, I suggest you do

if(toSleep == 0 ||  produce == 0 || consume == 0 )

which shows your intentions more clearly.

Pablo
  • 13,271
  • 4
  • 39
  • 59
  • Nice answer. It might be worth noting that the `argv[i] == NULL` checks are only safe for `i < argc`. (well, I suppose <=) just to drive the use of `argc` home. – lockcmpxchg8b Mar 13 '18 at 03:20