1

我正在尝试使用 C 中的 qsort 根据特定列对二维数组进行排序。我附上了我正在使用的最小工作代码。本质上,我将指向数组行的指针传递给 qsort,并根据我要排序的列号,修改要在比较函数中进行比较的元素。现在,根据 C 约定,如果我有 2 列,我希望 colnum=0 和 colnum=1 对应于第 1 列和第 2 列。但是,在我的实现中,如果 colnum=1 表示第 1 列和 colnum,我会得到正确的结果=2 表示第 2 列。我很困惑为什么会这样?(我还包括了我使用的数组分配函数)。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "myfun.h"

static int colnum = 0;

int cmp(const void * a,const void * b);

int main(){

int i;
double **z1;

z1=matrix(5,2);
for (i=0; i<5; i++){
    z1[i][1]=-i-1; z1[i][2]=16*i+10; 
    printf("before sort z1 %lf %lf \n",z1[i][1],z1[i][2]);
}

colnum=2;
qsort(z1,5,sizeof(double*),cmp);

for (i=0; i<5; i++){
    printf("after sort z1 %lf %lf \n",z1[i][1],z1[i][2]);
}

getchar();
}

int cmp(const void * a,const void * b)
{
double** x = (double**) a;
double** y = (double**) b;

double xval, yval;

xval = *(*(x)+colnum);
yval = *(*(y)+colnum);

printf("%lf %lf \n",xval,yval);

if (xval < yval )
{
    return 1;
}
else if (xval > yval)
{
    return -1;
}
else
{
    return 0;
}
}

double** matrix(int rows,int cols){
int k;
double **m;
m = (double **)malloc(rows * sizeof(double *));
for (k=0; k<rows; k++){
    m[k] = (double *)malloc(cols * sizeof(double));
}
return m;
}
4

1 回答 1

1

您的程序具有未定义的行为,因为您正在访问超出内部分配循环分配的边界的内存matrix()

    m = (double **) malloc(rows * sizeof(double *));
    for (k = 0; k < rows; k++) {
        m[k] = (double *) malloc(cols * sizeof(double));
    }

由于cols值为 2,因此malloc()仅返回 2 个 type 元素的内存double。但是,您的代码正在初始化并读取一个不存在的第三个元素。

由于这样做是未定义的,因此产生您期望的输出在可能的行为范围内。但是,这是不正确的,因为您冒着损坏堆和读取无效数据的风险。由于程序中的此问题,在下运行您的程序valgrind会产生“无效写入”和许多“无效读取”错误。

正确的方法是在初始化时将值存储在正确的 0 和 1 列索引中,设置colnum为 1 以按第二列排序,并在打印数组值时从正确的 0 和 1 索引中读取。

    z1 = matrix(5, 2);
    for (i = 0; i < 5; i++) {
        z1[i][0] = -i - 1;
        z1[i][1] = 16 * i + 10;
        printf("before sort z1 %lf %lf \n", z1[i][0], z1[i][1]);
    }

    colnum = 1;
    qsort(z1, 5, sizeof(double *), cmp);

    for (i = 0; i < 5; i++) {
        printf("after sort z1 %lf %lf \n", z1[i][0], z1[i][1]);
    }

作为旁注,当我为这个答案格式化你的代码时,我注意到你使用了一个旧的 C 时代错误,可能是无意的:

    z1[i][1]=-i-1; /*...*/

=-构造是原始 C(C.89 之前)拼写-=运算符的方式。您最终不太可能使用会在没有诊断的情况下尊重该运算符的编译器,但您应该警惕这种语法,并将 the=-标记分开以消除歧义。

    z1[i][1] = -i - 1; /*...*/
于 2013-09-13T00:14:44.270 回答