c - 排序在 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) 对我尝试打印的数组进行排序,但似乎什么也没发生。
解决方案
您的排序例程应该按照编写的方式工作,但是您未能在代码中启用警告,因此您不允许编译器帮助您修复代码中的警告和错误——仅此一项就可以让您的代码运行美好的。
例如,您的编译器会告诉您确切的行号,以及多次检测到错误或警告的行中的确切字符,例如
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
in main()
),它们会被编译器立即标记——听它。让它帮助您编写更好的代码。
始终在启用警告的情况下进行编译,并且在没有警告的情况下干净地编译之前不要接受代码。要启用警告,请添加到您的编译字符串。对于,您可以使用. 对于VS(在 Windows 上),使用(或使用,但您会收到很多无关的非代码相关警告)。阅读并理解每个警告——然后去修复它。-Wall -Wextra -pedantic
gcc/clang
clang
-Weverything
cl.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 */
由于您的数组是int
,a
并且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
将比冒泡排序快(大型数组最慢的排序之一)
推荐阅读
- spring-mvc - 将列表对象从 thymeleaf 发送到控制器
- python-3.x - 从 CSV 文件中删除标题
- javascript - 如何使用 JavaScript 将文本从一个字段复制到另一个选项卡菜单的字段?
- php - 致命错误:在布尔值上调用成员函数 getData()
- python - ColumnTransformer 和 FeatureUnion 之间的 Scikit-Learn 管道代码差异
- android - android studio 导入 GreenDao 后无法解析 DaoMaster
- c++ - Valgrind 插入排序的大小为 8 的无效读取
- image - 更改图片时如何销毁缓存图像
- ios - 错误 ITMS-90730ITMS 无法在 Xcode 10.2.1 中上传 IPA
- bootstrap-4 - Bootstrap-4 脚本的最佳位置和脚本的标签