【问题标题】:qsort in C based on a column in 2d array: unexpected behaviorC中的qsort基于二维数组中的列:意外行为
【发布时间】:2013-09-12 21:42:27
【问题描述】:

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

【问题讨论】:

  • 当您将所有索引更改回从 0 开始时,您会得到什么结果?
  • 您可能希望以列优先顺序存储矩阵,然后对每个列调用排序(然后将在连续的内存块中)
  • @OliCharlesworth colnum=0 给了我垃圾。这就是让我感到困惑的地方。 +1 偏移量从何而来?

标签: c arrays qsort


【解决方案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; /*...*/

【讨论】:

  • 我想我明白你在说什么。但是,由于我将数组列初始化为 0 和 1,为什么设置 colnum=1 按第 1 列排序我的数组, colnum=2 按第 2 列排序,设置 colnum=0 给我垃圾?令我困惑的是我的代码中的 +1 偏移量来自哪里?
  • 您的程序未在第 0 列和第 1 列初始化您的数组。
  • 我现在明白了。我已经更改了一些测试的索引,然后没​​有将其更改回来。现在它的行为正常。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-08
  • 2014-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-24
相关资源
最近更新 更多