【问题标题】:Pointers to pointers segmentation fault指向指针分段错误的指针
【发布时间】:2018-06-28 12:11:29
【问题描述】:

我创建了一个插入排序方法,它接受一个数组、它的大小和一个比较器。比较器函数是这样的:

int compare_int_ptr(void* ptr1, void* ptr2) {
  double i1 = *(double*)ptr1;
  double i2 = *(double*)ptr2;
  if(i1<i2) {
    return -1;
  }
  if(i1 == i2) {
    return 0;
  }
  return 1;
}

插入是这样的:

void insertion_sort(void** array, int size, CompFunction compare){
    int i,j;
    void* key;
    for(i = 1; i<size;i++){
        key = array[i];
        for(j = i-1; j>=0 && compare(array[j],key)>=0;j--){
            swap(&array[j+1],&array[j]);
        }
        array[j+1] = key;
    }
}

如果我尝试执行它,我会得到分段错误错误,所以我认为我没有正确使用指针。当我进行交换时,我用 & 传递它是否正确?

编辑:这是我调用方法的地方:

int main(int argc, char const *argv[]) {
    if(argc < 2) {
        printf("Usage: sortingfirstusage <file_name>\n");
        exit(EXIT_FAILURE);
      }
      double* array = load_array(argv[1]);
      insertion_sort((void**)array, 3, compare_int_ptr);
      free(array);
      return 0;

数组已正确加载,因为我在调用插入排序之前打印了所有元素并且它们都在其中。

【问题讨论】:

  • learn how to debug your programs。更具体地说,请了解如何使用 调试器 来捕捉发生的崩溃,以及如何在代码中定位它们发生的时间和位置。
  • 您还需要提供有关如何调用该函数的信息。如果调用者传递的指针与您的函数期望/假设的指针不同,那将解释您的问题。但是,如果没有这些信息,没有人可以帮助您诊断。更一般地,当您提出问题时,最好提供minimal reproducible example(点击该链接了解更多信息)。
  • 错误在哪里?您还没有展示如何生成数组。如果这是错误的,那么就会出现错误。您还没有显示交换正在做什么。它似乎需要指针,但没有大小。是函数还是宏?
  • 问题已编辑

标签: c pointers segmentation-fault comparator


【解决方案1】:

您正在尝试对双精度数组进行排序。 double *array 指向第一个 n 元素:

array ==> [ double ]  \
          [ double ]  |
              .        > n elements
              .       |
          [ double ]  /

您将array 转换为void **

(void **)array ==> [ void * ]  \
                   [ void * ]  |
                       .        > n elements
                       .       |
                   [ void * ]  /

不难确定麻烦就在眼前。 void * 不是 double。它可能与double 大小相同,也可能不同。它几乎肯定不会指向有效的内存位置,因此如果您取消引用它,您将调用未定义的行为,几乎肯定会导致您的程序被信号杀死。不幸的是,您的 insertion_sort 函数在调用比较函数时确实取消引用它:

        key = array[i];
        for(j = i-1; j>=0 && compare(array[j],key)>=0;j--){

array[i]array[j] 都是无效的void * 值(因为底层内存包含doubles,而不是void *s)。您的比较函数在此处取消引用它们:

  double i1 = *(double*)ptr1;
  double i2 = *(double*)ptr2;

ptr1ptr2 包含无意义的指针值。他们不指向doubles。取消引用它们会调用未定义的行为


这是insertion_sort 的工作版本,它使用与C 标准库中的qsort 函数相同的函数类型和等效功能(尽管该函数的效率比qsort 低很多):

insertion_sort.h

#ifndef INSERTION_SORT_H_INCLUDED__
#define INSERTION_SORT_H_INCLUDED__

#include <stddef.h>

void insertion_sort(void *base, size_t nmemb, size_t size,
        int (*compar)(const void *, const void *));

#endif

insertion_sort.c

#include <string.h>
#include "insertion_sort.h"

void insertion_sort(void *base, size_t nmemb, size_t size,
        int (*compar)(const void *, const void *))
{
    char (*b)[size] = base;
    size_t i;
    size_t j;
    int cmp;

    for (i = 1; i < nmemb; i++) {
        j = i - 1;
        /* search backwards for insertion point */
        while ((cmp = compar(b + j, b + i)) > 0 && j > 0)
            j--;
        if (cmp <= 0)
            j++;    /* went back one too far */
        if (j < i) {
            /* rotate element i to position j, j to j+1, ..., i-1 to i */
            char tmp[size];

            memcpy(&tmp[0], &b[i][0], size);
            memmove(&b[j + 1][0], &b[j][0], size * (i - j));
            memcpy(&b[j][0], &tmp[0], size);
        }
    }
}

以下是上述函数的使用示例:

ma​​in.c

#include <stdio.h>
#include "insertion_sort.h"

int compar_double(const void *a, const void *b)
{
    double d1 = *(const double *)a;
    double d2 = *(const double *)b;

    if (d1 < d2)
        return -1;
    if (d1 > d2)
        return 1;
    return 0;
}

void print_doubles(const double *d, size_t n)
{
    size_t i;

    for (i = 0; i < n; i++)
        printf("%g\n", d[i]);
}

int main(void)
{
    double numberlist[] = { 3.0, 1.0, 5.0, -4.0, 2.0 };
    size_t len = sizeof numberlist / sizeof numberlist[0];

    printf("Unsorted:\n");
    print_doubles(numberlist, len);
    printf("\n");
    insertion_sort(numberlist, len, sizeof numberlist[0], compar_double);
    printf("Sorted:\n");
    print_doubles(numberlist, len);
    return 0;
}

这是上述程序产生的输出:

Unsorted:
3
1
5
-4
2

Sorted:
-4
1
2
3
5

【讨论】:

    【解决方案2】:
    void qsort( void *ptr, size_t count, size_t size,
                int (*comp)(const void *, const void *) );
    

    与 qsort 一样,您的排序函数应该将 void * 作为第一个参数,而不是 void **。调用insertion_sort 时应该注意双重间接错误。将 double[] 数组转换为 void ** 需要强制转换,而无需强制转换即可自动转换为 void *

    【讨论】:

    • 我在调用中进行了转换:insertion_sort((void**)array, 3, compare_int_ptr);
    • 我的问题(我猜)是指针的使用。我需要将数组用作 void**。
    • void ** 不正确。当您没有演员表时,请尊重编译器打印的错误。使用void ** 完全是个错误。
    【解决方案3】:

    如果不知道load_array(argv[1]); 做了什么,答案是无法预测的,正如彼得在 cmets 中所建议的那样。

    假设这个函数调用正在做一些合法的事情,并用可以正确取消引用的指针加载数组,那么你的问题就是强制转换。您不能将指针变成指向指针的指针。你必须传递指针的地址来完成你想要的。

    insertion_sort(&array, 3, compare_int_ptr);
    

    【讨论】:

    • 为什么这个答案被否决了?它指出了代码的一个完全合理的问题,不是吗?
    猜你喜欢
    • 1970-01-01
    • 2016-01-02
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    • 2016-02-19
    • 2018-05-16
    相关资源
    最近更新 更多