1

The last part of the code where I am allocating memory to common_set is not working whereas other mallocs worked fine above. Similarly when I freed the unique_set for the third time it is not done properly. I am not able to get the printf sentences which I wrote after them. I am not able to free the pointer of the union_set. Also I am not able to allocate memory to a new pointer common_pointer.

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

void dict(char **str, int man, int MAY) {
    char temp[MAY];

    for (int i = 0; i < man; ++i) {
        for (int j = i + 1; j < man; ++j) {
            if (strcmp(str[i], str[j]) > 0) {
                strcpy(temp, str[i]);
                strcpy(str[i], str[j]);
                strcpy(str[j], temp);
            }
        }
    }
}

//int k = 0;
char **unique_set;
char **a_new_sumset;

int unique(char **s, int l, int d, int k) {
    if (d == l) {
        unique_set[k] = (char*)malloc((strlen(s[l]) + 1) * sizeof(char));
        strcpy(unique_set[k], s[l]);
        return k;
    } else {
        for (int i = l; i < d; i++) {
            if (strcmp(s[i], s[i + 1]) == 0 && i + 1 == d) {
                unique_set[k] = (char*)malloc((strlen(s[i + 1]) + 1) * sizeof(char));
                strcpy(unique_set[k], s[i + 1]);
                return k;
                //printf("demo: %s\n", unique_set[k]);
            } else
            if (strcmp(s[i], s[i + 1]) != 0) {
                unique_set[k] = (char*)malloc((strlen(s[i]) + 1) * sizeof(char));
                strcpy(unique_set[k], s[i]);
                //printf("demo1: %s\n", unique_set[k]);
                k++;
                unique(s, i + 1, d, k);
                break;
            }
        }
    }
}

char **common_set;

char **intersection(char **sum_set, int d) {
    int k = 0;
    for (int i = 0; i < d; i++) {
        if (strcmp(sum_set[i], sum_set[i + 1]) == 0 && strcmp(sum_set[i], sum_set[i + 2]) != 0 && i + 2 < d) {
            common_set[k] = (char*)malloc((strlen(sum_set[i]) + 1) * sizeof(char));
            strcpy(common_set[k], sum_set[i]);
            k++;
        } else
        if (strcmp(sum_set[i], sum_set[i + 1]) == 0 && i + 2 > d) {
            common_set[k] = (char*)malloc((strlen(sum_set[i]) + 1) * sizeof(char));
            strcpy(common_set[k], sum_set[i]);
            k++;
        }
    }
    return common_set;
}

#define maxx1  3   // number of words in grp 1
#define maxy1  10  // word limit for the first group of words
#define maxx2  3   // number of words in grp2
#define maxy2  10  // word limit for the next group of words

int main() {
    char **sum_set;
    char **str_g1;
    char **str_g2;
    char words1[maxy1];
    str_g1 = (char**)malloc(maxx1 * sizeof(char*));
    char words2[maxy2];
    str_g2 = (char**)malloc(maxx2 * sizeof(char*));
    printf("Enter the first group:\n");
    for (int i = 0; i < maxx1; i++) {
        gets(words1);
        str_g1[i] = (char*)malloc((strlen(words1) + 1) * sizeof(char));
        strcpy(str_g1[i], words1);
        //puts(ptr[i]);
        //printf("%d", i);
    }
    printf("Enter the second group:\n");
    for (int i = 0; i < maxx2; i++) {
        gets(words2);
        str_g2[i] = (char*)malloc((strlen(words2) + 1) * sizeof(char));
        strcpy(str_g2[i], words2);
        //puts(ptr[i]);
        //printf("%d", i);
    }

    dict(str_g1, maxx1, maxy1); //to lexicographically arrange the string 1 group
    dict(str_g2, maxx2, maxy2);

    sum_set = (char**)malloc((maxx1 + maxx2) * sizeof(char*));
    a_new_sumset = (char**)malloc((maxx1 + maxx2) * sizeof(char*));
    for (int i = 0; i < maxx1; i++) {
        sum_set[i] = (char*)malloc((strlen(str_g1[i]) + 1) * sizeof(char));
        strcpy(sum_set[i], str_g1[i]);
        //puts(sum_set[i]);
    }
    for (int i = 0; i < maxx2; i++) {
        sum_set[i + maxx1] = (char*)malloc((strlen(str_g2[i]) + 1) * sizeof(char));
        strcpy(sum_set[i + maxx2], str_g2[i]);
        //puts(sum_set[i + maxx1]);
    }
    dict(sum_set, maxx1 + maxx2, maxy1 + maxy2);

    unique_set = (char**)malloc((maxx1) * sizeof(char*));//allocating memory to next string group to compute its set
    int k = unique(str_g1, 0, maxx1 - 1, 0);
    printf("%d \n", k);
    printf("The set of the string A in arranged order is:\n");
    for (int i = 0; i <= k; i++) {
        a_new_sumset[i] = (char*)malloc((strlen(unique_set[i]) + 1) * sizeof(char));
        strcpy(a_new_sumset[i], unique_set[i]);
        puts(unique_set[i]);
        //
    }

    //printf("freed the pointers\n");
    for (int i = 0; i <= k; ++i) {//freeing the arrays
        free(unique_set[i]);
    }
    free(unique_set);
    //printf("freed the pointers\n");//freeing the top pointer
    int a = k;
    unique_set = (char**)malloc((maxx2) * sizeof(char*));//allocating memory to next string group to compute its set
    k = unique(str_g2, 0, maxx2 - 1, 0);
    int b = k;
    printf("The set of the string B in arranged order is:\n");
    for (int i = 0; i <= k; i++) {
        a_new_sumset[i + 1 + a] = (char*)malloc((strlen(unique_set[i]) + 1) * sizeof(char));
        strcpy(a_new_sumset[i + a + 1], unique_set[i]);
        puts(unique_set[i]);
        //strcpy(a_new_sumset[i + a + 1], unique_set[i]);
    }
    printf("%d \n", k);
    for (int i = 0; i <= k; ++i) {//freeing the arrays
        free(unique_set[i]);
    }
    free(unique_set);//freeing the top pointer
    printf("freed the pointers\n");

    unique_set = (char**)malloc((a + b) * sizeof(char*));//allocating memory to unique_set for computing the union of the sets
    k = unique(sum_set, 0, (maxx1 + maxx2) - 1, 0);
    printf("The set of the string A+B in arranged order is:\n");
    for (int i = 0; i <= k; i++)
        puts(unique_set[i]);

    for (int i = 0; i <= k; ++i) {//freeing the arrays
        free(unique_set[i]);
    }
    printf("freed the pointers\n");
    free(unique_set);
    printf("freed the pointers\n");
    printf("The intersection_set of the string A+B in arranged order is:\n");

    common_set = (char**)malloc((maxx1 + maxx2) * sizeof(char*));

    printf("The intersection_set of the string A+B in arranged order is:\n");
    char **p;
    p = intersection(a_new_sumset, (maxx1 + maxx2) - 1);
    printf("The intersection_set of the string A+B in arranged order is:\n");
    for (int i = 0; i <maxx1 + maxx2; i++) {
        puts(p[i]);
    }
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Amit
  • 33
  • 4
  • welcome to SO, could you create a minimal example which shows just the failing part? this is way too much code – schetefan24 Feb 13 '21 at 18:33
  • 1
    Can you clarify what you mean by "not working"? I suspect that you're writing past the end of allocated memory. – 1201ProgramAlarm Feb 13 '21 at 18:34
  • 1
    The code you show us is very low quality. Way to many pointers, [casting the reult of `malloc`](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc), global variables, no usable documentation or comments, inconsistent indentation, to many one-letter variable names, way to much code for a [mcve], [using `gets`](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used), and probably more. – Some programmer dude Feb 13 '21 at 18:36
  • Also, build with verbose warnings enabled, and treat them as errors. When you can get the code to build without warnings (without cheating by using e.g. casting), then learn how to use a *debugger* to be able to step through the code statement by statement while monitoring variables and their values. – Some programmer dude Feb 13 '21 at 18:37

2 Answers2

1

There are many issues in the code:

  • in function dict, you should not copy the strings, but swap the pointers instead, which is simpler and works for any string length. Furthermore the name dict is confusing for this function, prefer a more informative name such as sort_strings:

      void sort_strings(char **str, int man) {
          for (int i = 0; i < man; ++i) {
              for (int j = i + 1; j < man; ++j) {
                  if (strcmp(str[i], str[j]) > 0) {
                      char *temp = str[i];
                      str[i] = str[j];
                      str[j] = temp;
                  }
              }
          }
      }
    
  • global variables are not necessary for this task, prefer local variables, pass destination arrays as arguments and return the number of strings as the return value.

  • the string allocation code is duplicated everywhere... using the strdup() function or a wrapper that tests for memory allocation failure would improve readability.

  • avoid variable name l, which looks confusingly similar to 1

  • the uniq function does not return a value in the else branch, it is unclear what it does and why it is recursive.

  • the loop to add the strings from the second group has a bug: strcpy(sum_set[i + maxx2], str_g2[i]); should be strcpy(sum_set[i + maxx1], str_g2[i]);. This mistake has no effect now because maxx1 == maxx2 but should be fixed.

  • in function intersection, you compare strings at offset d + 1 and d + 2 before testing if these index values are within the array boundaries.

  • selecting duplicated strings in intersection makes the assumption that strings are not duplicated in group 1 and 2.

  • the number of common strings is not returned, nor stored into a global variable, so main() cannot determine this number and uses maxx1 + maxx2 which is always wrong for non trivial cases.

Here is a modified version using functions to read lines, sort an array, find unique values, compute the union and intersection of sets and free the string arrays:

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

// allocate a copy of a string or die
char *xstrdup(const char *str) {
    char *p = strdup(str);
    if (p == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(1);
    }
    return p;
}

// read a line of at most max bytes
char *get_line(int max) {
    char buf[max + 1];
    int i = 0;
    int c;

    while ((c = getchar()) != EOF && c != '\n') {
        if (i < max) {
            buf[i++] = (char)c;
        }
    }
    buf[i] = '\0';
    return xstrdup(buf);
}

// free the strings in an array of size n
void free_strings(char **strings, int n) {
    for (int i = 0; i < n; i++) {
        free(strings[i]);
    }
}

// copy strings in lexicographical order
int sort_strings(char **sorted, char **str, int n) {
    int i, j;
    for (i = 0; i < n; i++) {
        for (j = i; j > 0 && strcmp(sorted[j - 1], str[i]) > 0; j--) {
            sorted[j] = sorted[j - 1];
        }
        sorted[j] = xstrdup(str[i]);
    }
    return n;
}

// copy unique strings in lexicographical order
int uniq_strings(char **unique_strings, char **strings, int n) {
    int i, k = 0;
    for (i = 0; i < n; i++) {
        if (i == 0 || strcmp(strings[i - 1], strings[i]) != 0) {
            unique_strings[k++] = xstrdup(strings[i]);
        }
    }
    return k;
}

int intersection_strings(char **intersection_set, char **str1, int n1, char **str2, int n2) {
    int i = 0, j = 0, k = 0;
    while (i < n1 && j < n2) {
        int c = strcmp(str1[i], str2[j]);
        if (c < 0) {
            i++;
        } else
        if (c > 0) {
            j++;
        } else {
            intersection_set[k++] = xstrdup(str1[i]);
            i++;
            j++;
        }
    }
    return k;
}

int union_strings(char **union_set, char **str1, int n1, char **str2, int n2) {
    int i = 0, j = 0, k = 0;
    while (i < n1 && j < n2) {
        int c = strcmp(str1[i], str2[j]);
        if (c < 0) {
            union_set[k++] = xstrdup(str1[i]);
            i++;
        } else
        if (c > 0) {
            union_set[k++] = xstrdup(str2[j]);
            j++;
        } else {
            union_set[k++] = xstrdup(str1[i]);
            i++;
            j++;
        }
    }
    while (i < n1) {
        union_set[k++] = xstrdup(str1[i++]);
    }
    while (j < n2) {
        union_set[k++] = xstrdup(str2[j++]);
    }
    return k;
}

void print_set(char **set, int n, const char *desc) {
    if (desc) {
        printf("%s", desc);
    }
    for (int i = 0; i < n; i++) {
        puts(set[i]);
    }
}

#define maxx1 3   // number of words in grp 1
#define maxy1 10  // word limit for the first group of words
#define maxx2 3   // number of words in grp2
#define maxy2 10  // word limit for the second group of words

int main() {
    char *str_g1[maxx1];
    char *str_s1[maxx1];
    char *str_u1[maxx1];
    char *str_g2[maxx2];
    char *str_s2[maxx2];
    char *str_u2[maxx2];
    char *union_set[maxx1 + maxx2];
    char *intersection_set[maxx1 < maxx2 ? maxx1 : maxx2];

    printf("Enter the first group:\n");
    for (int i = 0; i < maxx1; i++) {
        str_g1[i] = get_line(maxy1);
    }
    printf("Enter the second group:\n");
    for (int i = 0; i < maxx2; i++) {
        str_g2[i] = get_line(maxy2);
    }

    sort_strings(str_s1, str_g1, maxx1);
    int n1 = uniq_strings(str_u1, str_s1, maxx1);
    sort_strings(str_s2, str_g2, maxx1);
    int n2 = uniq_strings(str_u2, str_s2, maxx2);

    print_set(str_u1, n1, "The set of the string A in arranged order is:\n");
    print_set(str_u2, n2, "The set of the string B in arranged order is:\n");

    // compute union and intersection
    int nu = union_strings(union_set, str_u1, n1, str_u2, n2);
    int ni = intersection_strings(intersection_set, str_u1, n1, str_u2, n2);

    print_set(union_set, nu, "The set of the string A+B in arranged order is:\n");
    print_set(intersection_set, ni, "The intersection_set of the string A*B in arranged order is:\n");

    free_strings(str_g1, maxx1);
    free_strings(str_g2, maxx2);
    free_strings(str_s1, maxx1);
    free_strings(str_s2, maxx2);
    free_strings(str_u1, n1);
    free_strings(str_u2, n2);
    free_strings(union_set, nu);
    free_strings(intersection_set, ni);

    return 0;
}

To improve on this code, you can define a structure string_set to combine the string array along with variables describing its allocated size and active count. Here is a modified version:

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

typedef struct string_set {
    int count, size;
    char **array;
} string_set;

// allocate a copy of a string or die
char *xstrdup(const char *str) {
    char *p = strdup(str);
    if (p == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(1);
    }
    return p;
}

void *xalloc(size_t n) {
    void *p = malloc(n);
    if (p == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(1);
    }
    return p;
}

string_set *string_set_allocate(int size) {
    string_set *set = xalloc(sizeof(*set));
    set->count = 0;
    set->size = size;
    set->array = xalloc(sizeof(*set->array) * size);
    return set;
}

void string_set_free(string_set *set) {
    while (set->count --> 0) {
        free(set->array[set->count]);
    }
    free(set->array);
    free(set);
}

// read a line of at most max bytes
char *get_line(int max) {
    char buf[max + 1];
    int i = 0;
    int c;

    while ((c = getchar()) != EOF && c != '\n') {
        if (i < max) {
            buf[i++] = (char)c;
        }
    }
    buf[i] = '\0';
    return xstrdup(buf);
}

string_set *string_set_clone(string_set *set) {
    string_set *copy = string_set_allocate(set->size);
    for (int i = 0; i < set->count; i++) {
        copy->array[i] = xstrdup(set->array[i]);
    }
    copy->count = set->count;
    return copy;
}

void string_set_sort(string_set *set) {
    for (int i = 0; i < set->count; i++) {
        for (int j = i + 1; j < set->count; j++) {
            if (strcmp(set->array[i], set->array[j]) > 0) {
                char *temp = set->array[i];
                set->array[i] = set->array[j];
                set->array[j] = temp;
            }
        }
    }
}

void string_set_uniq(string_set *set) {
    if (set->count > 0) {
        int j = 1;
        for (int i = 1; i < set->count; i++) {
            if (strcmp(set->array[i], set->array[j - 1]) == 0) {
                free(set->array[i]);
                set->array[i] = NULL;
            } else {
                set->array[j++] = set->array[i];
            }
        }
        set->count = j;
    }
}

string_set *string_set_intersection(string_set *set1, string_set *set2) {
    int n1 = set1->count;
    int n2 = set2->count;
    string_set *res = string_set_allocate(n1 < n2 ? n1 : n2);
    int i = 0, j = 0, k = 0;
    while (i < n1 && j < n2) {
        int c = strcmp(set1->array[i], set2->array[j]);
        if (c < 0) {
            i++;
        } else
        if (c > 0) {
            j++;
        } else {
            res->array[k++] = xstrdup(set1->array[i]);
            i++;
            j++;
        }
    }
    res->count = k;
    return res;
}

string_set *string_set_union(string_set *set1, string_set *set2) {
    int n1 = set1->count;
    int n2 = set2->count;
    string_set *res = string_set_allocate(n1 + n2);
    int i = 0, j = 0, k = 0;
    while (i < n1 && j < n2) {
        int c = strcmp(set1->array[i], set2->array[j]);
        if (c < 0) {
            res->array[k++] = xstrdup(set1->array[i]);
            i++;
        } else
        if (c > 0) {
            res->array[k++] = xstrdup(set2->array[j]);
            j++;
        } else {
            res->array[k++] = xstrdup(set1->array[i]);
            i++;
            j++;
        }
    }
    while (i < n1) {
        res->array[k++] = xstrdup(set1->array[i++]);
    }
    while (j < n2) {
        res->array[k++] = xstrdup(set2->array[j++]);
    }
    res->count = k;
    return res;
}

void string_set_print(string_set *set, const char *desc) {
    if (desc) {
        printf("%s", desc);
    }
    for (int i = 0; i < set->count; i++) {
        puts(set->array[i]);
    }
}

#define maxx1 3   // number of words in grp 1
#define maxy1 10  // word limit for the first group of words
#define maxx2 3   // number of words in grp2
#define maxy2 10  // word limit for the second group of words

int main() {
    string_set *str_g1 = string_set_allocate(maxx1);
    string_set *str_g2 = string_set_allocate(maxx2);

    printf("Enter the first group:\n");
    for (int i = 0; i < maxx1; i++) {
        str_g1->array[str_g1->count++] = get_line(maxy1);
    }
    printf("Enter the second group:\n");
    for (int i = 0; i < maxx2; i++) {
        str_g2->array[str_g2->count++] = get_line(maxy2);
    }

    string_set *str_u1 = string_set_clone(str_g1);
    string_set_sort(str_u1);
    string_set_uniq(str_u1);
    string_set *str_u2 = string_set_clone(str_g2);
    string_set_sort(str_u2);
    string_set_uniq(str_u2);

    string_set_print(str_u1, "The set of the string A in arranged order is:\n");
    string_set_print(str_u2, "The set of the string B in arranged order is:\n");

    string_set *union_set = string_set_union(str_u1, str_u2);
    string_set *intersection_set = string_set_intersection(str_u1, str_u2);

    string_set_print(union_set, "The set of the string A+B in arranged order is:\n");
    string_set_print(intersection_set, "The intersection set of the string A*B in arranged order is:\n");

    string_set_free(str_g1);
    string_set_free(str_g2);
    string_set_free(str_u1);
    string_set_free(str_u2);
    string_set_free(union_set);
    string_set_free(intersection_set);

    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
0

The last part of the code where I am allocating memory to common_set is not working ...

The problem in this part is not the allocation, but the implementation of the intersection function. You haven't provided a means for this function to return the number of elements in the intersection set, and you haven't initialized the allocated set space - you just try to access maxx1 + maxx2 set elements, most of which are undefined. Fixing this design would be a start.

Armali
  • 18,255
  • 14
  • 57
  • 171