【问题标题】:Sort working in main() but not in separate function排序在 main() 中工作,但不在单独的函数中
【发布时间】:2019-04-09 17:53:57
【问题描述】:

我正在做一个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) 对我尝试打印的数组进行排序,但似乎什么也没发生。

【问题讨论】:

  • Sort 中的流浪 for 循环是什么?为什么return 在循环中?你应该正确缩进你的代码来整理这些东西。
  • 函数声明说Sort返回int,但你返回int *。请尝试发送minimal reproducible example
  • main() 函数缺少右大括号,Sort() 的返回类型仍然错误。
  • 修复上面提到的错误似乎可以正常工作:ideone.com/TpSvT8
  • 所以我对 C 非常不熟悉,我了解到你不能从函数返回数组,所以我发现你的返回类型应该是 int 并且你返回一个将它转换为 int* 或指针?

标签: c arrays sorting


【解决方案1】:

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

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

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 (....) 来简单地修复它。

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

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

正如我在评论中提到的,不要在代码中使用 幻数(除非绝对需要,例如使用 fscanf field-width 修饰符)。相反,如果您需要一个常量 #define 一个(或多个),或者使用全局 enum 来做同样的事情。这样一来,您就可以在代码的顶部有一个位置来根据需要进行更改,而无需通过声明或循环限制来进行更改。

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

#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)

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

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

要处理 ab 是 void 指针这一事实,您只需将它们转换为 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 */

由于您的数组是intab 将是指向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 将比冒泡排序(大型数组中最慢的排序之一)快数量级

【讨论】:

  • 谢谢大卫,正如你猜想的那样,我从 java 开始使用 C 编程大约 2 天,除了 eclipse 之外从未真正使用过任何东西我想知道编译时警告在哪里我得到了一些但不是很多有帮助的人将这些添加到 GCC 是一个很棒的提示,我希望我知道
  • 很高兴为您提供帮助。 C 是一门很棒的语言,但还有很多东西要学。你对你的程序有绝对的控制权(并且绝对有责任确保它是正确的——没有训练轮:)C 允许你处理内存到字节——java通常对你隐藏的东西(这也是是什么让 C 如此之快)我能给出的关于学习 C 的最佳建议就是放慢速度。有很多东西要学。不要把学习 C 当作竞赛,更像是一段旅程。注意细节,它们是C提供的唯一护栏。祝你好运!
猜你喜欢
  • 2021-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多