首页 > 解决方案 > 排序在 main() 中工作,但不在单独的函数中

问题描述

我正在处理一个 C 和 unix 编程的家庭作业问题,老师告诉我们用 C 为数组编写一个排序函数。

我已经从 main 中的一些 for 循环中进行了排序,但是我们需要的单独的排序函数不起作用。

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

int Sort(int arr[], int size){

    int i,j,a;
    for(i = 0; i < size; i++){
        for(j = i+1; j < size; j++){
            if(arr[i] > arr[j]){
                a = arr[i];
                arr[i] = arr[j];
                arr[j] = a;
            }
        }
    return arr;
    }
}

int main(){
    int a;
    int BAT[40];
    for(int i=0; i < 40; i++){
       BAT[i] = (float)(599)* ( (float)rand() / (float)RAND_MAX );
       printf("%d \n", BAT[i]);
    }
    printf(" the array should now be sorted \n"); 
    //Sort(BAT, 40); THIS IS THE FUNCTION CALL THAT DIDNT SEEM TO WORK SO I COPIED THE SORT OUT OF THE SORT FUNCTION TO TEST

    //THIS IS THE SORT CODE AND WHILE IT IS IN THE MAIN IT WORKS
    for(int i = 0; i < 40; i++){
        for(int j = i+1; j < 40; j++){
            if(BAT[i] > BAT[j]){
                a = BAT[i];
                BAT[i] = BAT[j];
                BAT[j] = a;
            }
        }
    }
    //END OF SORTING TEST
        for(int j=0; j < 40; j++){
            printf("%d \n", BAT[j]);
        }

我希望 Sort(BAT, 40) 对我尝试打印的数组进行排序,但似乎什么也没发生。

标签: carrayssorting

解决方案


您的排序例程应该按照编写的方式工作,但是您未能在代码中启用警告,因此您不允许编译器帮助您修复代码中的警告和错误——仅此一项就可以让您的代码运行美好的。

例如,您的编译器会告诉您确切的行号,以及多次检测到错误或警告的行中的确切字符,例如

bubblesortfn.c: In function ‘Sort’:
bubblesortfn.c:21:5: warning: return makes integer from pointer without a cast 
[enabled by default]
     return arr;
     ^

返回如何从指针生成整数?很简单,您的函数试图返回一个整数数组 ( int *),并且您的函数已声明int Sort。(您不需要返回任何东西,但您可以通过将声明更改为 来简单地修复它int *Sort (....))。

其余的问题是简单的语法问题和未使用的变量(例如ain main()),它们会被编译器立即标记——听它。让它帮助您编写更好的代码。

始终在启用警告的情况下进行编译,并且在没有警告的情况下干净地编译之前不要接受代码。要启用警告,请添加到您的编译字符串。对于,您可以使用. 对于VS(在 Windows 上),使用(或使用,但您会收到很多无关的非代码相关警告)。阅读并理解每个警告——然后去修复它。-Wall -Wextra -pedanticgcc/clangclang-Weverythingcl.exe/W3/Wall

正如我在评论中提到的,不要在代码中使用幻数(除非绝对需要,例如使用fscanf 字段宽度修饰符)。相反,如果您需要一个常量,#define一个(或多个),或者使用全局enum来做同样的事情。这样,如果需要,您可以在代码顶部有一个位置来更改内容,并且您不必通过声明或循环限制来更改内容。

从字面上看,修复已识别的警告并稍微整理一下是让您的代码正常工作并在您的Sort函数中正确排序数组所需的全部(我还添加了一个prnintarray()函数来打印您的数组以避免重复循环main().完全放置,并srand()在使用之前通过调用来播种随机数生成器rand(),您可以执行以下操作:

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

/* if you need a constant, define one (or more) - avoid magic numbers */
#define ROWSZ   10      /* max integers to print per-row */
#define MAXB    40      /* max integers in BAT */
#define MULTP  599      /* multiplier constant */

int *Sort (int arr[], int size)
{
    int i, j, a;
    for (i = 0; i < size; i++) {
        for (j = i + 1; j < size; j++) {
            if (arr[i] > arr[j]){
                a = arr[i];
                arr[i] = arr[j];
                arr[j] = a;
            }
        }
    }
    return arr;
}

/* simple print function to output arr of sz with rowsz int per-row */
void prnintarray (int *arr, size_t sz, size_t rowsz)
{
    for (size_t i = 0; i < sz; i++) {
        if (i && i % rowsz == 0)
            putchar ('\n');
        printf (" %4d", arr[i]);
    }
    putchar ('\n');
}

int main (void) {

    int BAT[MAXB] = {0};    /* initialize all arrays - good practice */

    srand (time(NULL));     /* seed the random number generator */

    for (int i = 0; i < MAXB; i++)      /* fill array */
        BAT[i] = MULTP * ( (float)rand() / (float)RAND_MAX );

    puts ("\nunsorted array:\n");
    prnintarray (BAT, MAXB, ROWSZ); 

    Sort (BAT, MAXB);

    puts ("\nsorted array:\n");
    prnintarray (BAT, MAXB, ROWSZ); 
}

示例使用/输出

$ ./bin/bubblesortfn

unsorted array:

  461  519  346  508  265   93  358  407  278  151
  465  531  430  148  181  227  452  206  401  202
  103  518  259  267  342  495  570  431  477  455
  164  339  375  511  248   42    6    8  450  284

sorted array:

    6    8   42   93  103  148  151  164  181  202
  206  227  248  259  265  267  278  284  339  342
  346  358  375  401  407  430  431  450  452  455
  461  465  477  495  508  511  518  519  531  570

如果您还有其他问题,请仔细查看并告诉我。

用于qsort实际排序

虽然为学习方面编写冒泡排序函数没有任何问题,但 C 库提供了qsort可以而且应该满足您的大部分排序需求的函数。你唯一的工作qsort就是编写一个简单的compare()函数来告诉qsort如何对数组的相邻成员进行排序。该compare()函数的原型通常会使新的 C 程序员陷入恐慌状态。原型是:

int compare (const void *a, const void *b)

不要让它打扰你。a并且b只是指向当前正在比较的数组的两个成员的指针。您的工作是编写函数的其余部分,以便如果 指向的值a

  • 在 指向的值之前排序b,返回一个负数;
  • 等于 指向的值b,返回零,最后
  • b返回正值后排序。(都像strcmp)。

a要处理and是 void 指针这一事实b,您只需int在取消引用之前将它们强制转换为指针以使用它们的值,例如

int compare (const void *a, const void *b)
{
    const int *pa = a,    /* a and b are pointers to elements being compared*/
              *pb = b;    /* in array, cast as required to proper type */

由于您的数组是inta并且b将是指向的指针int,因此您只需将它们转换为int *. 现在您可以通过指针访问这些值(例如,取消引用*pa以获取 持有的地址处的值pa)。

现在为了满足退货要求,简单的解决方案是:

     return *pa - *pb;

但是,如果*pa是一个很大的负值并且*pb是一个很大的正值,那么减法*pa - *pb很容易导致整数溢出未定义的行为。通过使用两个不等式而不是直接减法,可以在提供所需返回的同时消除溢出的机会。认真考虑:

    return (*pa > *pb) - (*pa < *pb);

因此,将您的qsort函数放在一起并将您的调用替换Sort为调用qsort,您将代码重写为:

int compare (const void *a, const void *b)
{
    const int *pa = a,    /* a and b are pointers to elements being compared */
              *pb = b;    /* in array, cast as required to proper type */

    /*  inequality avoids overflow from subtracting 2 large values
     *  (x > y) - (x < y) , returns -1, 0, 1 (like strcmp) for 
     *  -1 -> x sorts before y,  0 -> x equals y,  1 -> x sorts after y
     */
    return (*pa > *pb) - (*pa < *pb);
}

然后

    qsort (BAT, MAXB, sizeof *BAT, compare);

试试看。作为大型数组的奖励,数量级qsort将比冒泡排序快(大型数组最慢的排序之一)


推荐阅读