繁体   English   中英

c中导致分段错误的多维数组的qsort

[英]qsort of multidimensional array in c leading to segfault

我正在尝试使用C中的qsort()对2D的双精度数组进行排序。该数组包含3D点数据,可使用fscanf从文件中读取该3D点数据。 我的编程技能非常有限,但是我有非常大的数据集需要处理。 抱歉,如果我的代码很烂。

23127.947、23127.947、23127.947
523127.790、523523.790、523127.790
523127.747、523523.747、523127.747
523127.761、523127.761、523127.761
523127.768、523523.768、523127.768
(...为3,158,632点)

我使用printf来隔离代码中的问题似乎是qsort()行,这会导致分段错误。 从我阅读的有关Stack Overflow的其他问题来看,我的“比较”功能可能是一个问题。 执行一维数组的示例似乎很简单,但是我看到的用于二维数组的示例并没有用于比较其他维度(首先是X,然后如果X1 = X2,请比较Y,然后如果Y1 = Y2,请比较Z)。

    int main(int argc, char *argv[]) {
    int i,j,c;
    double x,y,z;
    int ROWS = 3158632;
    int COLS = 3;
    char buffer[100];

    double** data = Make2DDoubleArray(ROWS, COLS);

    //Open the plot file to read in, and have an output write file
    FILE *fp = fopen("Plot_1-2.txt","r");

    if(fp == NULL) {
        printf("Can't open file\n");
        exit;
    }

    fgets(buffer, 100, fp); //Ignore header

    for(i=0; ; i++){
        if ((c = fgetc(fp)) == EOF){
            break;
        }
        fscanf(fp,"%lf, %lf, %lf",&x, &y, &z);
        data[i][0] = x;
        data[i][1] = y;
        data[i][2] = z;
    }

    printf("First 5 unsorted numbers:\n");
    for(j=0;j<5;j++){
        printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
    }
    printf("Last 5 unsorted numbers:\n");

    for(j=ROWS-5;j<ROWS;j++){
        printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
    }

    /* Sort array using Quicksort algorithm: */
    printf("Sorting...\n");
    qsort(data, ROWS, COLS*sizeof(double), &compare);

    printf("First 10 sorted numbers:\n");
    for(j=0;j<10;j++){
        printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
    }

    fclose(fp);

    for (i=0; i<ROWS; i++){
        free(data[i]);
    }
    free(data);

    return 0;
}

double** Make2DDoubleArray(int arraySizeX, int arraySizeY) {  
    double** theArray; 
    int i; 
    theArray = (double**) malloc(arraySizeX*sizeof(double*));  
    for (i = 0; i < arraySizeX; i++)  
        theArray[i] = (double*) malloc(arraySizeY*sizeof(double));  
    return theArray;  
}

int compare(const void *arg1, const void *arg2) {
    //double a, b, c, d, e, f;
    double *a = (double*)arg1;
    double *b = (double*)arg2;
    double *c = ((double*)arg1 + 1);
    double *d = ((double*)arg2 + 1);
    double *e = ((double*)arg1 + 2);
    double *f = ((double*)arg2 + 2);

    if(a > b)
        return 1;
    else if(a < b)
        return -1;
    else {
        if(c > d)
            return 1;
        else if(c < d)
            return -1;
        else {
            if(e > f)
                return 1;
            else if(e < f)
                return -1;
            else
                return 0;
        }
    }
}

我想知道是否告诉qsort去“ COLS * sizeof(double)”是为2D数组分配内存的错误方法吗? 将这个问题当作一维阵列处理是否可以解决其余问题? 如果可能的话,我希望将其保留为2D数组。

qsort期望排序后的元素进入连续的内存块中。 如果所有单元格都构成一个连续的内存块,可以将其解释为1D数组并与qsort使用,则仍可以将数据保留在2D数组中。

不必像在Make2DDoubleArray那样为每行分别分配内存,而是一次为所有行分配内存。 然后,除了您现在返回的内容之外:指向行的指针数组; 您还必须返回(使用逐个参数)包含所有行的内存块。

您正在为每一行分配内存

for (i = 0; i < arraySizeX; i++)  
    theArray[i] = (double*) malloc(arraySizeY*sizeof(double));

而您可以一步分配内存

 double *cells = malloc(sizeof(double) * arraySizeX * arraySizeY);
 if (cells == NULL) { ... }
 for (i = 0; i < arraySizeX; i++)
     theArray[i] = &cells[arraySizeY * i];

然后,您将有两个数组:一个指向行的指针数组(现在在代码中称为theArray ); 和一个新的一维数组,该数组保留所有行(不是指向行的指针,而是单元格的数组)( 实际上, 每行(一个三元组)是一个数据点的 所有单元格 )可以用于qsort (在我的代码中称为cells )。

然后,将后一个- cells (而不是 data )传递给qsort

 
 
 
  
   qsort(cells, ROWS * COLS, sizeof(double), &compare);
 
  

还要注意,在问题代码中的调用

 
 
 
  
   qsort(data, ROWS, COLS*sizeof(double), &compare);
 
  

这是错误的,因为您没有对一定数量的 ROWS行进行排序,每个行的大小为 COLS*sizeof(double)

编辑:嗯,我很抱歉。 我误解了您拥有二维数组的条目,但是现在我看到COLS代表一个单元格的字段。 在这种情况下,最好使用@SpacedMonkey的解决方案。 仅供参考,我的答案也可以,然后您将像以前一样调用qsort,但是在单元格上

  qsort(cells, ROWS, COLS*sizeof(double), &compare); 

尝试改用数据结构:

typedef struct {
    double x;
    double y;
    double z;
} point_data;

然后,您只需要此新类型的1维数组:

point_data *array = malloc(linesRead * sizeof *array);

而且您的比较功能仍然相当相似:

int compare(const void *arg1, const void *arg2) {
    point_data *point1 = arg1,
               *point2 = arg2;

    if ( point1->x > point2->x ) {
        return 1;
    else if ( point1->x < point2->x ) {
        return -1;
    } else {
        if ( point1->y > point2->y ) {
            return 1;
        else if ( point1->y < point2->y ) {
            return -1;
        } else {
            if ( point1->z > point2->z ) {
                return 1;
            else if ( point1->z < point2->z ) {
               return -1;
            } else {
               return 0;
            }
        }
    }
}

另外,请不要硬编码点数,而要计算读入的数字。

这些都不意味着没有标题的任何内容,例如<stdio.h><stdlib.h>等。

请说明exit; 我认为您的意思是exit(0);

您的main有一些问题。 由于存在fgetc ,您的代码可能会丢失第一个值的最高有效位数,这是一个微妙的错误。 如果要测试EOF,请测试scanf的返回值( Jee!我没想到!我希望他们将这些内容写在手册中! Du,他们确实...)。 文件末尾的示例比此示例更好,因为该示例可确保fscanf实际解析了三个值。

for(size_t i=0; fscanf(fp,"%lf, %lf, %lf",&x, &y, &z) != EOF; i++){
    data[i][0] = x;
    data[i][1] = y;
    data[i][2] = z;
}

Make2DDoubleArray函数中存在问题。 它分配了许多 qsort无法处理的不相交的数组。 一步分配数组是否更干净?

void *Make2DDoubleArray(size_t x) {  
    double (*theArray)[3] = malloc(x * sizeof *theArray);
    return theArray;
}

theArray被声明为指向3个double数组的指针。 您甚至不需要Make2DDoubleArray

compare功能有问题。

double *a = (double*)arg1;
double *b = (double*)arg2;

ab是指针,

if(a > b)
    return 1;
else if(a < b)
    return -1;

...但是您的代码会将它们作为整数进行比较,从而使排序出现故障。 array[0]的地址将始终小于array[1]的地址。


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

int main(int argc, char *argv[]) {
    int j,c;
    double x,y,z;
    size_t ROWS = 3158632;
    size_t COLS = 3;
    char buffer[100];
    double (*theArray)[COLS] = malloc(ROWS * sizeof *theArray);

    //Open the plot file to read in, and have an output write file
    FILE *fp = fopen("Plot_1-2.txt","r");

    if(fp == NULL) {
        printf("Can't open file\n");
        exit(0);
    }

    fgets(buffer, 100, fp); //Ignore header

    for(size_t i=0; fscanf(fp,"%lf, %lf, %lf", &x, &y, &z) == 3; i++){
        data[i][0] = x;
        data[i][1] = y;
        data[i][2] = z;
    }

    printf("First 5 unsorted numbers:\n");
    for(size_t j=0; j<5; j++){
        printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
    }
    puts("Last 5 unsorted numbers:");

    for(size_t j=ROWS-5; j<ROWS; j++){
        printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
    }

    /* Sort array using Quicksort algorithm: */
    puts("Sorting...");
    qsort(data, ROWS, sizeof *data, compare);

    puts("First 10 sorted numbers:");
    for(size_t j=0;j<10;j++){
        printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
    }

    fclose(fp);
    free(data);

    return 0;
}

int compare(const void *arg1, const void *arg2) {
    double (*x)[3] = arg1;
    double (*y)[3] = arg2;

    if ((*x)[0] > (*y)[0])
        return 1;
    else if ((*x)[0] < (*y)[0])
        return -1;
    else if ((*x)[1] > (*y)[1])
        return 1;
    else if ((*x)[1] < (*y)[1])
        return -1;
    else if ((*x)[2] > (*y)[2])
        return 1;
    else if ((*x)[2] < (*y)[2])
        return -1;
    else
        return 0;
}

暂无
暂无

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

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