Search code examples
cstringsegmentation-faultstrcmp

Segmentation fault c strcmp at last comparaison


I'm currently trying to compare each String from a char** with another String. In order to do so I tried to use strcmp but I get a Segmentation Fault. Then i tried to use a hand-made strcmp, and by testing I have been able to spot that my seg. fault happens when at the end of the comparaison between the word that I'm spotting and char[i].

Here are some lines and some tests so you can get the issue.

That's my main :

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

    ssize_t sz = getxattr(argv[1], "user.tag", search, sizeof(search) - 1);

    printf("Old tags: %s\n", search);

    if (sz != -1) {
        char **tab = malloc(sizeof(char **));

        tab = StringToTab(search);
        char *mot = malloc(sizeof(char));

        strcat(mot, argv[2]);
        strcat(mot, "\0");
        printf("\n%s\n", tab[3]);
        if (estDansLeTableau(tab, mot, nb_occ(search, ',') + 1)) {
            char *newtag = TabToString(removeFromTab(tab, argv[2],
                    (nb_occ(search, ','))
                ),
                (nb_occ(search, ','))
                );

            printf("\nICI 1\n");
            if (setxattr(argv[1], "user.tag", newtag, strlen(newtag), 0) == -1) {
                perror("ERREUR");
            }
            else {
                printf("\n La nouvelle liste de tag pour votre fichier est :  %s \n", newtag);
            }
            memset(newtag, 0, 0);
        }
        else {
            printf("\nle tag demandé n'est pas dans la liste des tags de ce fichier\n");
        }
        memset(tab, 0, 0);
    }
    else {
        printf("\nLe fichier n'a aucun tag a enlever\n");
    }
}

Tab is coming from the fonction StringToTab who basically takes a string like [abc,bcd,def] and turn it into a char** like ["abc","bcd","def"]:

char **
StringToTab(char *s)
{
    char **tab = malloc((nb_occ(s, ',') + 1) * sizeof(char *));
    char *add = malloc(sizeof(char *));
    char c = s[1];
    int j = 1;
    int i = 0;

    while (c != ']') {
        if (c == ',') {
            char *caracterVide = malloc(sizeof(&c));

            caracterVide = "\0";
            strcat(add, caracterVide);
            memset(caracterVide, 0, 0);
            printf("\nMot = %s\n", add);
            tab[i] = malloc(sizeof(char *));
            memcpy(tab[i], add, strlen(add));
            printf("\nAffected word = %s\n", tab[i]);
            memset(add, 0, sizeof(add));
            i++;
            j++;
            c = s[j];
        }
        else {
            char *sac = malloc(sizeof(&c));

            *sac = c;
            strcat(add, sac);
            memset(sac, 0, 0);
            printf("\nprefix = %s", add);
            j++;
            c = s[j];
        }
    }
    printf("\nMot = %s\n", add);
    tab[i] = malloc(sizeof(char *));
    memcpy(tab[i], add, strlen(add));
    printf("\nAffected word = %s\n", tab[i]);
    memset(add, 0, 0);
    i++;
    j++;
    c = s[j];
    return tab;
}

Then we go to estDansLeTableau (=isInTheTab) which is gonna take the tab that we just had, the argv[2] which is the tag that I need to spot.

int
estDansLeTableau(char **t, char *m, int t_len)
{
    // 1 si le mot est dans le tableau, 0 sinon
    int j = 0;

    while (j < t_len) {
        printf("\nword 1 = %s, word 2 = %s\n", t[j], m);
        if (strcmp(t[j], m) == 0) {
            return 1;
        }
        else {
            j++;
        }
    }
    return 0;
}

and here is a test where i'm trying to spot "lol" on the tab :

Old tags: [Amine,Chris,Sara,Kamelia,lol,Sarah,Sarah]

prefix = A
prefix = Am
prefix = Ami
prefix = Amin
prefix = Amine
Mot = Amine

Affected word = Amine

prefix = C
prefix = Ch
prefix = Chr
prefix = Chri
prefix = Chris
Mot = Chris

Affected word = Chris

prefix = S
prefix = Sa
prefix = Sar
prefix = Sara
Mot = Sara

Affected word = Sara

prefix = K
prefix = Ka
prefix = Kam
prefix = Kame
prefix = Kamel
prefix = Kameli
prefix = Kamelia
Mot = Kamelia

Affected word = Kamelia

prefix = l
prefix = lo
prefix = lol
Mot = lol

Affected word = lol

prefix = S
prefix = Sa
prefix = Sar
prefix = Sara
prefix = Sarah
Mot = Sarah

Affected word = Sarah

prefix = S
prefix = Sa
prefix = Sar
prefix = Sara
prefix = Sarah
Mot = Sarah

Affected word = Sarah

Kamelia

word 1 = Amine, word 2 = lol

word 1 = Chris, word 2 = lol

word 1 = Sara, word 2 = lol

word 1 = Kamelia, word 2 = lol

word 1 = lol, word 2 = lol
Segmentation fault

It's been 2 days that I'm stuck on it and i have NO CLUE on how to solve it S.O.S lmao! Thanks a lot !


Solution

  • Most of the memory allocations are for the size of a pointer. On my system that is eight bytes. That could work as long as there are no elements more than seven characters.

    char *caracterVide = malloc(sizeof(&c));
    char *add = malloc(sizeof(char *));  
    

    There are also memory leaks.

    char **tab = malloc(sizeof(char **));
    tab = StringToTab(search);
    

    The assignment following the malloc overwrites the value returned by malloc and that memory can not be freed.

    This is very curious.

    char *sac = malloc(sizeof(&c));
    *sac = c;
    strcat(add, sac);
    

    There is nothing to ensure that sac is zero terminated. The concatenation could, by pure chance, add one character or it could iterate until a zero is found and possibly crash the program.

    Here is one approach to taking the original string and breaking it into items separated by commas.
    strspn and strcspn are very useful for counting characters. strspn stops counting at the first non-matching character or the terminating zero and strcspn stops at the first matching character or the terminating zero.
    This does not show the items character by character but that could be done.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char ** StringToTab(char *s) {
        char **tab = NULL;
        char *comma = s;
        char *item = s;
        int count = 0;
        int span = 0;
    
        while ( *item) {// loop to terminating zero
            item += strcspn ( item, ",");//count of characters that are not ,
            if ( *item) {
                ++item;//advance past ,
            }
            ++count;//add one for each comma
        }
        ++count;//add one for item fillowing last comma
        //allocate extra sentinel pointer
        if ( NULL == ( tab = calloc ( sizeof *tab, ( count + 1)))) {
            fprintf ( stderr, "calloc problem\n");
            return tab;
        }
        count = 0;
    
        item = s;
        item += strspn ( s, "[");//count of characters that are [
    
        while ( *item) {//not at terminating zero
            comma = item;//set comma to the same as item
            comma += strcspn ( item, ",");//count of characters that are not ,
            if ( *comma) {
                span = comma - item;
            }
            else {//at the terminating zero
                span = strcspn ( item, "]");//count of characters that are not ]
            }
            //allocate memory for each item
            if ( NULL == ( tab[count] = malloc ( span + 1))) {//span characters plus terminating zero
                fprintf ( stderr, "malloc problem\n");
                return tab;
            }
            strncpy ( tab[count], item, span);//copy span characters
            tab[count][span] = 0;//set terminating zero
            ++count;
            item = comma;
            if ( *comma) {//not terminating zero
                ++item;//increment past ,
            }
        }
        return tab;
    }
    
    int estDansLeTableau(char **t, char *m) {
        // 1 si le mot est dans le tableau, 0 sinon
        int j = 0;
    
        while ( t[j]) {
            printf("\nword 1 = %s, word 2 = %s\n", t[j], m);
            if (strcmp(t[j], m) == 0) {
                return j;
            }
            j++;
        }
        return -1;
    }
    
    int main(int argc, char *argv[]) {
        char **tab = NULL;
        char test[] = "[Amine,Chris,Sara,Kamelia,lol,Sarah,Sarah]";
        char mot[] = "lol";
        int each = 0;
        int match = 0;
    
        printf("Old tags: %s\n", test);
    
        tab = StringToTab ( test);
        if ( tab) {
            if ( 0 <= ( match = estDansLeTableau(tab, mot))) {
                printf("match %s at %d\n", mot, match);
            }
    
            each = 0;
            while ( tab[each]) {
                free ( tab[each]);
                ++each;
            }
            free ( tab);
        }
    }