0

I want to clear up my understanding of Segmentation faults while using command-line arguments and isalpha() but this particular situation confused me more. So I declared argv[1] a char * as a way around it as advised by this SO answer.

However, Segmentation Fault still occurs if I used less than 2 command line arguments, and isalpha() is ignored in the if 3rd condition

#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h> //atoi is here

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


    char *input = argv[1];
    // Error handling
    if ((argc > 2) || (argc < 1) || (isalpha(input[1])))
    {
        printf("Unwanted input\n");
        return 1;
    }
   
    return 0;

}

Why do I get undefined behaviour when not using a command-line argument, and why then does isalpha() get ignored rather than giving me a seg fault?

Thanks for taking the time to read this post

user13641095
  • 107
  • 6
  • 1
    You get a segfault when you supply no arguments because in that case, argc is 1; argv[1] is NULL, and NULL[1] is undefined behaviour, usually a segfault (so isalpha is never called, because its argument could not be computed). – rici Dec 31 '20 at 19:45
  • `char *input = argv[1];` should be after you check that `argc > 1`, not before. As an aside, I don't recommend typedefing away `char *`. Just be explicit instead of hiding the pointer. – ggorlen Dec 31 '20 at 19:45
  • Where does `string` come from? – alk Dec 31 '20 at 19:50
  • 1
    @alk Probably from an unstated `#include `, in which case it's a `typedef` for `char*` – ikegami Dec 31 '20 at 19:59
  • @rici. Thanks for your answer! `isalpha()` still doesn't do anything at all even after solving the segfault. I've even tried putting it in a separate `if else` statement. `else if (isalpha(input[1])) { printf("Not accepting alphabet\n"); }` – user13641095 Dec 31 '20 at 22:08
  • @ggorlen If I try put `char *input = argv[1]` I get a `error: expected expression else if (isalpha(input[1]))` when I put the `isalpha()` lower or I get `undeclared identifier 'input'`. – user13641095 Dec 31 '20 at 22:14
  • @alk Sorry, yeah. It's from the cs50 library. Read `string` as `char*` – user13641095 Dec 31 '20 at 22:15
  • Yes, you obviously can't just move it in one go and expect to be finished with the refactor or you'll get errors because `input` won't have been declared. You need to rearrange the logic in a couple steps, but however you decide to do it, the point is that you're indexing out of bounds before you've bothered checking the length and that is going to cause a segfault. Write logic that always guarantees the index will be in bounds before doing it. – ggorlen Dec 31 '20 at 22:17
  • Another bug: it should be `isalpha((unsigned char)input[1])` in case `char` is signed on your system. Some libraries will let you get away without it, though. – Nate Eldredge Dec 31 '20 at 23:29

1 Answers1

2

When you execute the program with no args, argc is 1 (cause the program name itself counts as an arg), and argv[1] is NULL.

(argc > 2) || (argc < 1)   // Considers argc == 1 and argc == 2 acceptable

should be

(argc > 2) || (argc < 2)    // Only considers argc == 2 acceptable

or just

argc != 2
ikegami
  • 367,544
  • 15
  • 269
  • 518