排序工作在main()中,但不在单独的函数中

时间:2019-04-09 17:53:58

标签: c arrays sorting

我正在处理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)对数组进行排序,然后尝试打印该数组,但是似乎什么也没有发生。

1 个答案:

答案 0 :(得分:2)

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

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

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 (....)即可对其进行修复。)

剩下的问题是简单的语法问题和未使用的变量(例如a中的main()),编译器会立即对其进行标记-听一下。让它帮助您编写更好的代码。

始终在启用了警告的情况下进行编译,并且在进行无警告的干净编译之前,不接受的代码。要启用警告,请在您的-Wall -Wextra -pedantic编译字符串中添加gcc/clang。对于clang,您可以使用-Weverything。对于 VS (在Windows上为cl.exe),请使用/W3(或使用/Wall,但您会收到很多无关的与代码无关的警告)。阅读并理解每个警告-然后修复它。

如我的评论中所述,请勿在代码中使用魔术数字(除非绝对需要,例如fscanf field-width 修饰符) 。相反,如果您需要一个常数,则#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进行实际排序

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

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

别让它困扰您。 ab只是指向当前正在比较的数组的两个成员的指针。您的工作是编写函数的其余部分,以便于a指向的值:

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

要处理ab是空指针的事实,只需在取消引用以使用它们的值之前将它们强制转换为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 */

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

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

     return *pa - *pb;

但是,如果*pa是一个较大的负值,而*pb是一个较大的正值,则减去*pa - *pb会很容易导致整数溢出和< em>未定义的行为。通过使用两个不等式,而不是直接相减,可以消除溢出的机会,同时提供所需的回报。想一想:

    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的速度要比气泡排序(大型数组中最慢的排序之一)快 Magnitudes