简体   繁体   English

我不确定为什么我在 C 中的代码会免费给我一个分段错误,有什么想法吗?

[英]I'm not sure why my code in C is giving me a segmentation fault at free, any ideas?

So this is my code which runs up till free(right);所以这是我的代码,一直运行到免费(右); more like it completes merge sort then has an error, any solutions?更像是它完成合并排序然后有错误,任何解决方案?

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

void bubble_sort(int *l, int len) {
    // Iterate through the list
    for (int i = 0; i < len; i++) {
        // Iterate through the list
        for (int j = 0; j < len - 1; j++) {
            // If the current element is greater than the next element, swap them
            if (l[j] > l[j + 1]) {
                // Swap the elements
                int temp = l[j];
                l[j] = l[j + 1];
                l[j + 1] = temp;
                // Print the list
                for (int k = 0; k < len; k++) {
                    printf("%d ", l[k]);
                }
                printf("\n");
            }
        }
    }
}

void selection_sort(int *l, int len) {
    // Iterate through the list
    for (int i = 0; i < len; i++) {
        // Set the minimum index to the current index
        int min_index = i;
        // Iterate through the list
        for (int j = i + 1; j < len; j++) {
            // If the current element is less than the minimum element, set the minimum index to the current index
            if (l[j] < l[min_index]) {
                min_index = j;
            }
        }
        // Swap the elements
        int temp = l[i];
        l[i] = l[min_index];
        l[min_index] = temp;
        // Print the list
        for (int k = 0; k < len; k++) {
            printf("%d ", l[k]);
        }
        printf("\n");
    }
}

void insertion_sort(int *l, int len) {
    // Iterate through the list
    for (int i = 1; i < len; i++) {
        // Set the current index to the current index
        int j = i;
        // While the current index is greater than 0 and the previous element is greater than the current element, swap them
        while (j > 0 && l[j - 1] > l[j]) {
            // Swap the elements
            int temp = l[j - 1];
            l[j - 1] = l[j];
            l[j] = temp;
            // Decrement the current index
            j--;
        }
        // Print the list
        for (int k = 0; k < len; k++) {
            printf("%d ", l[k]);
        }
        printf("\n");
    }
}
void merge(int *left, int left_len, int *right, int right_len) {
    // Create a new list
    int *result = malloc((left_len + right_len) * sizeof(int));
    // Set the left index to 0 and the right index to 0
    int i = 0;
    int j = 0;
    // While the left index is less than the length of the left list and the right index is less than the length of the right list
    while (i < left_len && j < right_len) {
        // If the left element is less than or equal to the right element, append the left element to the result list and increment the left index
        if (left[i] <= right[j]) {
            result[i + j] = left[i];
            i++;
        }
        // Else, append the right element to the result list and increment the right index
        else {
            result[i + j] = right[j];
            j++;
        }
    }
    // Append the remaining elements in the left list to the result list
    for (int k = i; k < left_len; k++) {
        result[k + j] = left[k];
    }
    // Append the remaining elements in the right list to the result list
    for (int k = j; k < right_len; k++) {
        result[k + i] = right[k];
    }
    // Print the result list
    for (int k = 0; k < left_len + right_len; k++) {
        printf("%d ", result[k]);
    }
    printf("\n");
    // Copy the result list to the original list
    for (int k = 0; k < left_len + right_len; k++) {
        left[k] = result[k];
    }
    // Free the result list
    free(result);
}
void merge_sort(int *l, int len) {
    // If the list is empty or has one element, return the list
    if (len <= 1) {
        return;
    }
    // Set the middle index to the length of the list divided by 2
    int mid = len / 2;
    // Set the left list to the first half of the list
    int *left = malloc(mid * sizeof(int));
    for (int i = 0; i < mid; i++) {
        left[i] = l[i];
    }
    // Set the right list to the second half of the list
    int *right = malloc((len - mid) * sizeof(int));
    for (int i = mid; i < len; i++) {
        right[i - mid] = l[i];
    }
    // Sort the left list
    merge_sort(left, mid);
    // Sort the right list
    merge_sort(right, len - mid);
    // Merge the left list and the right list
    merge(left, mid, right, len - mid);
    // Free the left list and the right list
    free(left);
    free(right);                                       //Error ln 142, in picture below
}

int binary_search(int *l, int len, int target) {
    // Set the low index to 0 and the high index to the length of the list minus 1
    int low = 0;
    int high = len - 1;
    // While the low index is less than or equal to the high index
    while (low <= high) {
        // Set the middle index to the sum of the low index and the high index divided by 2
        int mid = (low + high) / 2;
        // If the middle element is equal to the target, return the middle index
        if (l[mid] == target) {
            return mid;
        }
        // Else if the middle element is less than the target, set the low index to the middle index plus 1
        else if (l[mid] < target) {
            low = mid + 1;
        }
        // Else, set the high index to the middle index minus 1
        else {
            high = mid - 1;
        }
    }
    // If the target is not found, return -1
    return -1;
}

int main() {
    // Create a list
    int l[] = {17, 36, 3, 10, 29, 42, 34, 8};
    int len = sizeof(l) / sizeof(l[0]);
    // Print the list
    printf("Bubble Sort:\n");
    // Sort the list using bubble sort
    bubble_sort(l, len);
    // Print the list
    printf("Selection Sort:\n");
    // Sort the list using selection sort
    selection_sort(l, len);
    // Print the list
    printf("Insertion Sort:\n");
    // Sort the list using insertion sort
    insertion_sort(l, len);
    // Print the list
    printf("Merge Sort:\n");
    // Sort the list using merge sort
    merge_sort(l, len);
    // Print the list
    printf("Binary Search:\n");
    // Search for the target in the list using binary search
    printf("%d\n", binary_search(l, len, 42));
    return 0;
}

So I rewrote the code from python to C, and debugging in GDB gives me the error in the screenshot.于是我把python的代码改写成C,在GDB调试给我截图报错。

GDB ss GDB 党卫军

I've tried to edit the function itself to rectify the memory issue but it wouldn't work so i reverted back to this and hope someone has some more insight.我试图编辑 function 本身来纠正 memory 问题,但它不起作用,所以我又回到了这里,希望有人有更多的见解。

The segfault is triggered in merge() used by merge_sort() .段错误在merge_sort() merge()中触发。 Everything else is irrelevant.其他一切都无关紧要。

In merge_sort() you copy half of the input array l into a newly allocated array left and the other half into another newly allocated array right .merge_sort()中,您将输入数组l的一半复制到新分配的数组left中,另一半复制到另一个新分配的数组right中。 Then recursively merge_sort() those two halves which is fine.然后递归merge_sort()这两半就可以了。 To combine the two halves merge() is called where you incorrectly assume that the left and right arrays are allocated consecutively:合并两半merge()在您错误地假设左和右 arrays 是连续分配的地方被调用:

    for (int k = 0; k < left_len + right_len; k++) {
        left[k] = result[k];
    }

The minimal fix is to make the assumption valid:最小的修复是使假设有效:

void merge_sort(int *l, int len) {
    if (len <= 1) {
        return;
    }
    int mid = len / 2;
    int *left = malloc(len * sizeof(int));
    for (int i = 0; i < mid; i++) {
        left[i] = l[i];
    }
    int *right = left + mid;
    for (int i = mid; i < len; i++) {
        right[i - mid] = l[i];
    }
    merge_sort(left, mid);
    merge_sort(right, len - mid);
    merge(left, mid, right, len - mid);
    free(left);
}

A even better resolution would be to:更好的解决方案是:

  1. Strictly separate the code under test and your test harness.将被测代码和您的测试工具严格分开。 In this case you want to delegate to main() the task of duplicating the input array instead of doing that in your sort algorithm.在这种情况下,您希望将复制输入数组的任务委托给main() ,而不是在您的排序算法中执行该任务。 This allows merge_sort() to operate on the input array in-place ( merge() still uses the temporary array).这允许merge_sort()对输入数组进行操作( merge()仍然使用临时数组)。
  2. Eliminate the right array pointer argument to merge() .消除merge()right数组指针参数。 This documents that the left and right arrays are part of the the same array.该文档表明左右 arrays 是同一数组的一部分。
  3. Refactor the merge() and merge_sort() interface so the length argument is before the array argument so you can document how they relate.重构merge()merge_sort()接口,使长度参数位于数组参数之前,这样您就可以记录它们之间的关系。
  4. (Not fixed). (不固定)。 You could allocate the temporary space needed for merging once in merge_sort() and pass it to merge_sort2() and merge2() .您可以在merge_sort()中分配一次合并所需的临时空间,并将其传递给merge_sort2()merge2() That way you only have O(n) space overhead instead of O(n*log(n)) .这样你只有O(n)空间开销而不是O(n*log(n)) It is worth pointing out that malloc() may require a kernel context switch which in turn would be the most expensive operation th the merge() + merge_sort() implementation.值得指出的是, malloc()可能需要 kernel 上下文切换,这反过来又是merge() + merge_sort()实现中最昂贵的操作。 Doing 1 instead of n*log(n) calls to malloc() could be a significant (constant) factor in run-time.malloc()执行 1 而不是 n*log(n) 调用可能是运行时中的一个重要(常数)因素。 Sharing the temporary space, however, comes a cost as you would no longer be able to do the otherwise non-overlapping merge sorts in parallel.然而,共享临时空间是有代价的,因为您将无法再并行执行其他非重叠合并排序。
  5. Prefer the type size_t to int for lengths.对于长度,首选类型size_t而不是int sizeof() in particular returns a size_t value, and the cast to the (signed) int will be problematic for sizes greater than INTMAX . sizeof() 特别返回一个size_t值,并且对于大于INTMAX的大小,转换为(带符号的) int会出现问题。
  6. Prefer memcpy() instead of explicit loops when possible.尽可能使用memcpy()而不是显式循环。 memcpy() is highly optimized, and succinctly expresses intent. memcpy()经过高度优化,并简洁地表达了意图。
  7. Prefer passing a variable instead of a type to sizeof() .更喜欢将变量而不是类型传递给sizeof() The former is robust if you change the type of the variable where the latter requires a code change if you didn't use a typedef for the type.如果您更改变量的类型,前者是健壮的,而如果您没有对类型使用typedef ,则后者需要更改代码。
  8. Finally, I added a print() function so you don't need the debug print statements in the sorting functions themselves.最后,我添加了一个print() function 这样您就不需要排序函数本身中的调试打印语句。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void merge(size_t left_len, size_t right_len, int l[left_len + right_len]) {
    int *result = malloc((left_len + right_len) * sizeof(*l));
    int i = 0;
    int j = 0;
    while (i < left_len && j < right_len) {
        if (l[i] <= l[left_len + j]) {
            result[i + j] = l[i];
            i++;
        } else {
            result[i + j] = l[left_len + j];
            j++;
        }
    }
    memcpy(result + i + j, l + i, (left_len - i) * sizeof(*l));
    memcpy(result + left_len + j, l + left_len + j, (right_len - j) * sizeof(*l));
    memcpy(l, result, (left_len + right_len) * sizeof(*l));
    free(result);
}

void merge_sort(size_t len, int l[len]) {
    if (len < 2) return;
    int mid = len / 2;
    merge_sort(mid, l);
    merge_sort(len - mid, l + mid);
    merge(mid, len - mid, l);
}

void print(size_t len, int a[len]) {
    for(size_t i = 0; i < len; i++) {
        printf("%d%s", a[i], i + 1 < len ? ", " : "\n");
    }
}

int main() {
    int l[] = {17, 36, 3, 10, 29, 42, 34, 8};
    size_t len = sizeof(l) / sizeof(*l);
    int l2[len];
    memcpy(l2, l, sizeof(l));
    merge_sort(len, l2);
    print(len, l2);
}

and it returns:它返回:

3, 8, 10, 17, 29, 34, 36, 42

valgrind is happy: valgrind 很高兴:

ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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