1

I'm trying to create a simple command line test for is/is not a isogram (no repeated letters in a word), but i'm having problems with using argv as a character array.

I did some searching, this answer used strcopy, which then lead to me a more detailed malloc answer. Probably because my terrible google-foo I cannot find an example of looping through argv's characters. This code I tried is slicing the string?:

 /* first argument is the number of command line arguments,
  * list of command line arguments, argv[0] == function name
  */
 int main(int argc, char *argv[]) {
     if(argc != 2){
         printf("error, bad arguments!\n");
         return 1;

     } else {
         char* isogram = NULL;
         isogram = (char*)malloc(sizeof(argv[1])+1);
         strcpy(isogram, argv[1]);

         for(int i=0; i<strlen(isogram); i++){
             printf("isogram[%d]==%s\n", i, &isogram[i]);
         }

         // detect_isogram(isogram);

     }

     return 0;
 }

Output:

gcc -o isogram isogram.c -std=c99; ./isogram testing
isogram[0]==testing
isogram[1]==esting
isogram[2]==sting
isogram[3]==ting
isogram[4]==ing
isogram[5]==ng
isogram[6]==g

Note: I tried char *isogram[]=NULL thinking that's what I wanted to initialize, but as the website recommended this would only work with char *isogram = NULL.

Edit: I know how to test them, I just can't get each character to compare each other. Each indexing returns the slice[i:]...

 for(int i=0; i<strlen(argv[1]); i++){
     for(int j=i+1; j<strlen(argv[1]); j++){
         printf("isogram[%d]==%s\n", i, &argv[1][i]);
         printf("isogram[%d]==%s\n", j, &argv[1][j]);
     }
 }
Tony
  • 1,318
  • 1
  • 14
  • 36
  • I don't see a single `free` in this code which is a little concerning considering the `malloc` call. It's also not clear why that `malloc` is even there since the copy is never altered in any way. – tadman Feb 19 '18 at 20:50
  • 6
    Hint: `sizeof(argv[1])` is the *size of a pointer*, not the length of the string. You'd be better off with `strdup` if you do need a copy, or just passing in `argv[1]` if you don't. – tadman Feb 19 '18 at 20:51
  • 2
    You don't need a copy of the string. (It might be useful to make a copy of the pointer, e.g. `char *str = argv[1]`.) But all you need is two nested `for` loops that compare every letter to every other letter. – user3386109 Feb 19 '18 at 21:07
  • Everyone's right, I don't think I need to copy I just couldn't figure out how to do a character level comparison without it. If I try to just pass in argv I get sliced arrays. – Tony Feb 19 '18 at 21:27

2 Answers2

4

You don't need any argv[1] handling. You only need to pass it to the detection function.

code00.c:

#include <stdio.h>
#include <string.h>


int detect_isogram(const char *word) {
    size_t len = strlen(word), i = 0, j = 0;
    for (i = 0; i + 1 < len; i++)
        for (j = i + 1; j < len; j++)
            if (word[i] == word[j])
                return 0;
    return 1;
}

int detect_isogram2(const char *word) {
    size_t len = strlen(word), i = 0;
    for (i = 0; i + 1 < len; i++)
        if (strchr(word + i + 1, word[i]))
            return 0;
    return 1;
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("error, bad arguments!\n");
        return 1;
    } else {
        printf("detect_isogram returned: %d\ndetect_isogram2 returned: %d\n", detect_isogram(argv[1]), detect_isogram2(argv[1]));
        return 0;
    }
}

Notes:

  • The algorithm is trivial: for each char in the string (starting from the 1st, but excluding the last), check if it is in the remaining part of the string
    • The check can be either:
      • Manual (traverse the remaining of the string (starting with the char right after the searched one), and compare chars) - detect_isogram
      • Via [CPPReference]: strchr - detect_isogram2

Output:

root@testserver:/home/cfati/work/so/q048873942# gcc code.c -o isogram
root@testserver:/home/cfati/work/so/q048873942# ./isogram testing
detect_isogram returned: 0
detect_isogram2 returned: 0
root@testserver:/home/cfati/work/so/q048873942# ./isogram ""
detect_isogram returned: 1
detect_isogram2 returned: 1
root@testserver:/home/cfati/work/so/q048873942# ./isogram 1
detect_isogram returned: 1
detect_isogram2 returned: 1
root@testserver:/home/cfati/work/so/q048873942# ./isogram 12345678
detect_isogram returned: 1
detect_isogram2 returned: 1
root@testserver:/home/cfati/work/so/q048873942# ./isogram 123456781
detect_isogram returned: 0
detect_isogram2 returned: 0
root@testserver:/home/cfati/work/so/q048873942# ./isogram qq
detect_isogram returned: 0
detect_isogram2 returned: 0


Update #0

  • Incorporated @chux's improvement suggestion
CristiFati
  • 38,250
  • 9
  • 50
  • 87
0

If you just want to brute force it

int main(void) {
    char str1[] = "helloworld";
    int repeat = 0;

    for (int i = 0; i < strlen(str1); i++) {
        for (int j = i + 1; j < strlen(str1); j++) {
            if (str1[i] == str1[j]) {
                repeat = 1;
                break;
            }
            if (repeat == 1) {
                break;
            }
        }
    }

    if (repeat == 1) {
        printf("There are repeat chars\n");
    }
    else {
        printf("There are no repeats\n");
    }
}

Of course, you can replace str1 with argv[1] for your case. The thing to notice is that the second loop always starts one char after the index where the first loop currently is. This prevents you from comparing the same character to itself.

Stephen Docy
  • 4,738
  • 7
  • 18
  • 31