我有一些代码和一些测试用例。第一个案例通过了,第二个失败了。 我不明白问题是什么。
问题: 您会得到N个三角形,具体来说是它们的边a [i],b [i]和c [i]。以相同的样式打印它们,但按其面积从最小到最大进行排序。保证所有区域都不同。
我正在使用苍鹭的公式:
double p = (a + b + c) / 2;
double area = sqrt(p*(p-a)*(p-b)*(p-c))
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct triangle
{
int a;
int b;
int c;
};
typedef struct triangle triangle;
double area(int a, int b, int c)
{
a = (double) a;
b = (double) b;
c = (double) c;
double p = (a + b + c) / 2;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
int compareTringle(const void* left, const void* right){
double leftArea = area(((triangle *)left)->a, ((triangle *)left)->b,
((triangle *)left)->c);
double rightArea =
area(((triangle *)right)->a, ((triangle *)right)->b,
((triangle *)right)->c);
if (leftArea > rightArea)
return 1;
if (leftArea < rightArea)
return -1;
return 0;
}
void sort_by_area(triangle* tr, int n) {
qsort(tr, n, sizeof(triangle), compareTringle);
}
int main()
{
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}
First test:
Input:
3
7 24 25
5 12 13
3 4 5
Output:
3 4 5
5 12 13
7 24 25
通过了
Second case: https://pastebin.com/DFBGz2KD
怎么了?
答案 0 :(得分:4)
这没有做你想要的:
a = (double) a;
b = (double) b;
c = (double) c;
问题在于变量a
,b
和c
仍然是整数。因此,您要将它们转换为两倍,然后将它们隐式转换回整数,并以整数形式存储回去。然后以下内容将不起作用:
double p = (a + b + c) / 2;
由于a + b + c
是整数,所以除法是整数除法。
您可以通过以下方式解决此问题:
double da = a;
double db = b;
double dc = c;
,然后使用da
,db
,dc
代替a
,b
,c
。
但是,如果您希望让编译器为您执行类型提升,则可以省去分配,而只需将分配从p
更改为:
double p = (a + b + c) / 2.0;
这会将a
,b
和c
作为整数相加,然后将结果转换为double
,因为它现在被一个双常量{{1}除以}。
这两种方法都可以。
答案 1 :(得分:2)
汤姆给了您一个很好的答案,可以解决整数提升问题,但是有很多问题只是邀请未定义行为而您可以解决。 >
首先,您必须始终验证所有输入。否则,您不知道scanf
是否发生了 matching 或 input 失败,并且您盲目地使用了在两种情况下均不确定的值失败。只需验证scanf
的返回值,例如
if (scanf("%d", &n) != 1) { /* validate every input */
fputs ("error: invalid formate - 'n'.\n", stderr);
return 1;
}
...
for (int i = 0; i < n; i++)
if (scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c) != 3) {
fputs ("error: invalid format - a,b,c.\n", stderr);
return 1;
}
出于完全相同的原因,您必须验证每个分配(无论使用malloc, calloc
还是realloc
)。这不是"if"
的问题,分配将失败,这是"when"
的问题。由于分配失败设置了errno
,因此您的错误报告是对perror
的一次小小的调用,例如
triangle *tr;
...
if (!(tr = malloc (n * sizeof *tr))) { /* validate every allocation */
perror ("malloc-tr");
return 1;
}
在C中,当您声明一个函数并将括号为空()
时,您已指定该函数采用 unspecified 个参数,而不是零。为了使您声明main()
符合,您应该使用:
int main (void) {
请参阅:C11 Standard - §5.1.2.2.1 Program startup(p1)
area
中不需要任何类型转换,只需在'.'
之后添加2
来解决整数除法问题,然后让默认促销处理其余部分,例如< / p>
double area (int a, int b, int c) /* remove all casts, add '.' after 2 */
{
double p = (a + b + c) / 2.;
return sqrt (p*(p-a)*(p-b)*(p-c));
}
尽管您可以自由地分别声明struct
和typedef
,但是也可以在单个声明中进行声明,例如
typedef struct { /* you can simply create the typedef */
int a, b, c;
} triangle;
修复整数除法问题后,您的代码将正常运行,但您应修复其他问题,以确保不会因可预见的分配输入而遇到未定义行为错误。固定整数除法后,针对您的测试输入运行将导致:
使用/输出示例
$ ./bin/triangle_sort_area < dat/triangles_20.txt
22 18 5
31 41 14
20 23 21
54 62 11
26 41 65
58 31 31
20 39 32
26 41 62
44 48 18
23 37 47
53 18 54
28 36 40
31 46 39
33 45 49
57 33 45
28 56 56
41 38 55
55 44 44
48 49 67
58 61 50