基于2d数组中的列的C中的qsort:意外行为

时间:2013-09-12 21:42:28

标签: c arrays qsort

我正在尝试使用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;
}

1 个答案:

答案 0 :(得分:1)

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

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

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

由于这样做是未定义的,因此产生您期望的输出属于可能的行为范围。但是,它是不正确的,因为您冒着损坏堆和读取无效数据的风险。在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)方式。您不太可能最终使用的编译器会在没有诊断的情况下使用该运算符,但您应该对此语法保持警惕,并将=-标记分开以消除歧义。

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