繁体   English   中英

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

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

所以这是我的代码,一直运行到免费(右); 更像是它完成合并排序然后有错误,任何解决方案?

#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;
}

于是我把python的代码改写成C,在GDB调试给我截图报错。

GDB 党卫军

我试图编辑 function 本身来纠正 memory 问题,但它不起作用,所以我又回到了这里,希望有人有更多的见解。

段错误在merge_sort() merge()中触发。 其他一切都无关紧要。

merge_sort()中,您将输入数组l的一半复制到新分配的数组left中,另一半复制到另一个新分配的数组right中。 然后递归merge_sort()这两半就可以了。 合并两半merge()在您错误地假设左和右 arrays 是连续分配的地方被调用:

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

最小的修复是使假设有效:

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);
}

更好的解决方案是:

  1. 将被测代码和您的测试工具严格分开。 在这种情况下,您希望将复制输入数组的任务委托给main() ,而不是在您的排序算法中执行该任务。 这允许merge_sort()对输入数组进行操作( merge()仍然使用临时数组)。
  2. 消除merge()right数组指针参数。 该文档表明左右 arrays 是同一数组的一部分。
  3. 重构merge()merge_sort()接口,使长度参数位于数组参数之前,这样您就可以记录它们之间的关系。
  4. (不固定)。 您可以在merge_sort()中分配一次合并所需的临时空间,并将其传递给merge_sort2()merge2() 这样你只有O(n)空间开销而不是O(n*log(n)) 值得指出的是, malloc()可能需要 kernel 上下文切换,这反过来又是merge() + merge_sort()实现中最昂贵的操作。 malloc()执行 1 而不是 n*log(n) 调用可能是运行时中的一个重要(常数)因素。 然而,共享临时空间是有代价的,因为您将无法再并行执行其他非重叠合并排序。
  5. 对于长度,首选类型size_t而不是int sizeof() 特别返回一个size_t值,并且对于大于INTMAX的大小,转换为(带符号的) int会出现问题。
  6. 尽可能使用memcpy()而不是显式循环。 memcpy()经过高度优化,并简洁地表达了意图。
  7. 更喜欢将变量而不是类型传递给sizeof() 如果您更改变量的类型,前者是健壮的,而如果您没有对类型使用typedef ,则后者需要更改代码。
  8. 最后,我添加了一个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);
}

它返回:

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

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