简体   繁体   中英

Unable to sort 2d character array correctly

I take in a maximum of 100 strings from and file and place them into a 2d character array. STRING_LEN = 1000

char** read_from_file(char* fname, int * size)  {

    FILE *fp = fopen(fname, "r");

    int lines = 0;
    while(fscanf(fp, "%s", buff) != EOF) {
        lines++;
    }
    *size = lines;
    if(*size > 100) {
        *size = 100;
    }

    rewind(fp);

    char** file_array = malloc(*size * sizeof(char*));

        int counter;
        for(counter = 0; counter < *size; counter++) {
            file_array[counter] = malloc((STRING_LEN + 1) * sizeof(char));
        }
    for(counter = 0; counter < *size; counter++) {
           fscanf(fp, "%s", &file_array[counter]);
        }

    fclose(fp);
    return file_array;
}

Quick sort will sort by string length.

void quick_sort(char** words, int first, int last) {

    int pivot, j, i;
    char *temp = malloc((STRING_LEN + 1)* sizeof(char));

    if(first < last) {
        pivot = first;
        i = first;
        j = last;

        while(i < j) {
            while(strlen(&words[i]) <= strlen(&words[pivot]) && i < last)
                i++;
            while(strlen(&words[j]) > strlen(&words[pivot]))
                j--;

                if(i < j) {
                    strcpy(temp, &words[i]);
                    strcpy(&words[i], &words[j]);
                    strcpy(&words[j], temp);
                }
        }

        strcpy(temp, &words[pivot]);
        strcpy(&words[pivot], &words[j]);
        strcpy(&words[j], temp);
        free(temp);
        quick_sort(words, first, j-1);
        quick_sort(words, j+1, last);
    }
}

The quick sort function will work correctly for some files but for others the information is distorted for example. File content

car 
x 
house 
door 
ash 
a 
elephantback 
back

After quick sort

x 
a 
ash 
car 
back 
door 
house 
elephanthouse

As you can see the last word has been rearranged and gets worse if the file has more words. Why has strcpy combined words together like this?

You have undefined behavior in your sorting function: The expression &words[j] returns a pointer to the pointer stored at words[j] , ie it's the type char ** and not char * . Remove all those address-of operator, and use only words[j] to get a pointer to the string.

The problem here is that you're copying strings from one array to another, but each array has just enough space for the string it contains. So if for example you try to copy a 5 character string to a space with only 3 characters allocated, you overrun the allocated memory, leading to undefined behavior.

Rather than copying the full strings around, just copy the pointers:

temp = words[i];
words[i] = words[j];
words[j] = temp;
...
temp = words[pivot];
words[pivot] = words[j];
words[j] = temp;

EDIT:

Apparently I missed that all strings are allocated the same (large) amount of space. So that's not the cause of the undefined behavior. As Joachim Pileborg mentioned in his answer, using expressions like &words[j] was the root cause.

Still, swapping the pointers as I mentioned above is more efficient than copying the actual strings, and because it addresses the same erroneous lines of code it will still fix the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM