一、数学库
math.h头文件提供这些函数的原型。
弧度角度转换公式:角度=弧度乘以180/π。
π的值为4*atan(1)。
原型 | 描述与说明 |
double acos(double x) | 返回余弦值为x的角度(0~π) |
double asin(double x) | 返回正弦值为x的角度(-π/2~π/2) |
double atan(double x) | 返回正切值为x的角度(-π/2~π/2) |
double atan2(double y,double x) | 返回正切值为y/x的角度(-π~π) |
double cos(double x) | 返回x的余弦值,x的单位为弧度 |
double sin(double x) | 返回x的正弦值,x的单位为弧度 |
double tan(double x) | 返回x的余正切值,x的单位为弧度 |
double exp(double x) | 返回x的指数函数的值(e^x) |
double log(double x) | 返回x的自然对数值 |
double log10(double x) | 返回x的以10为底的对数值 |
double pow(double x,double y) | 返回x的y次幂 |
double sqrt(double x) | 返回x的平方根 |
double cbrt(double x) | 返回x的立方根 |
double ceil(double x) | 返回不小于x的最小整数值 |
double fabs(double x) | 返回x的绝对值 |
double floor(double x) | 返回不大于x的最大整数值 |
e.g.把直角坐标转化为极坐标
#include <stdio.h>
#include <math.h>
#define RAD_TO_DEG (180/(4 * atan(1)))
typedef struct polar_v {
double magnitude;
double angle;
} Polar_V;
typedef struct rect_v {
double x;
double y;
} Rect_V;
Polar_V rect_to_polar(Rect_V);
int main(void)
{
Rect_V input;
Polar_V result;
puts("Enter x and y coordinates; enter q to quit:");
while (scanf("%lf %lf", &input.x, &input.y) == 2)
{
result = rect_to_polar(input);
printf("magnitude = %0.2f, angle = %0.2f\n",
result.magnitude, result.angle);
}
puts("Bye.");
return 0;
}
Polar_V rect_to_polar(Rect_V rv)
{
Polar_V pv;
pv.magnitude = sqrt(rv.x * rv.x + rv.y * rv.y);
if (pv.magnitude == 0)
pv.angle = 0.0;
else
pv.angle = RAD_TO_DEG * atan2(rv.y, rv.x);
return pv;
}
二、泛型宏
泛型平方根函数
sqrtf()是sqrt()的float版本,sqrtl()是sqrt()的long double版本。
#include <stdio.h>
#include <math.h>
#define RAD_TO_DEG (180/(4 * atanl(1)))
// 泛型平方根函数
#define SQRT(X) _Generic((X),\
long double: sqrtl, \
default: sqrt, \
float: sqrtf)(X)
// 泛型正弦函数
#define SIN(X) _Generic((X),\
long double: sinl((X)/RAD_TO_DEG),\
default: sin((X)/RAD_TO_DEG),\
float: sinf((X)/RAD_TO_DEG)\
)
int main(void)
{
float x = 45.0f;
double xx = 45.0;
long double xxx =45.0L;
long double y = SQRT(x);
long double yy= SQRT(xx);
long double yyy = SQRT(xxx);
printf("%.17Lf\n", y); // 匹配 float
printf("%.17Lf\n", yy); // 匹配 default
printf("%.17Lf\n", yyy); // 匹配 long double
int i = 45;
yy = SQRT(i); // 匹配 default
printf("%.17Lf\n", yy);
yyy= SIN(xxx); // 匹配 long double
printf("%.17Lf\n", yyy);
return 0;
}
三、tgmath.h库(C99)
该库定义了泛型宏。
#include <tgmath.h>
```
float x=5.0;
double y;
y=sqrt(x); //调用宏,本质上是sqrtf(x)
y=(sqrt) (x); //调用函数sqrt(x)
注:如果包含了tgmath.h,要调用sqrt()函数而不是sqrt()宏,可以用圆括号把被调用的函数名括起来。
四、stdlib.h库
qsort()函数
用于快速排序数组的数据对象。
void qsort(void*base,size_t number,size_t size,
int (*compar)(const void *, const void*));
第一个参数是指针。指向待排序的数组的首元素。即首元素地址,即数组名。
第二个参数是待排序的数量。
第三个参数是指明待排序数组中每个元素的大小。
第四个参数是一个指向函数的指针。确定了比较函数的形式。
e.g.
#include <stdio.h>
#include <stdlib.h>
#define NUM 40
void fillarray(double ar[], int n);
void showarray(const double ar[], int n);
int mycomp(const void * p1, const void * p2);
int main(void)
{
double vals[NUM];
fillarray(vals, NUM);
puts("Random list:");
showarray(vals, NUM);
qsort(vals, NUM, sizeof(double), mycomp);
puts("\nSorted list:");
showarray(vals, NUM);
return 0;
}
void fillarray(double ar[], int n)
{
int index;
for( index = 0; index < n; index++)
ar[index] = (double)rand()/((double) rand() + 0.1);
}
void showarray(const double ar[], int n)
{
int index;
for( index = 0; index < n; index++)
{
printf("%9.4f ", ar[index]);
if (index % 6 == 5)
putchar('\n');
}
if (index % 6 != 0)
putchar('\n');
}
//按从小到大的顺序排序
int mycomp(const void * p1, const void * p2)
{
//使用指向double的指针来访问这两个值
const double * a1 = (const double *) p1; //将类型从void*强制转换成double*
const double * a2 = (const double *) p2; //将类型从void*强制转换成double*
if (*a1 < *a2)
return -1;
else if (*a1 == *a2)
return 0;
else
return 1;
}
五、string.h库中的memcpy()和memmove()
memcpy
和memmove
是两个常用的内存操作函数,它们都用于复制内存区域的内容。
1、memcpy()
函数:
函数声明:void *memcpy(void *dest, const void *src, size_t n);
这个函数用于将src
指向的内存区域的前n
个字节复制到dest
指向的内存区域。src
和dest
之间的内存区域不能重叠。
e.g.
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20];
memcpy(dest, src, 12);
printf("dest: %s\n", dest); // 输出:dest: Hello, World!
return 0;
}
2、memmove()函数
函数声明:void *memmove(void *dest, const void *src, size_t n);
这个函数用于将src
指向的内存区域的前n
个字节复制到dest
指向的内存区域。与memcpy
不同的是,src
和dest
之间的内存区域可以重叠。当重叠发生时,memmove
会正确地处理数据,确保原始数据不会被破坏。
e.g.
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20] = "Hello, ";
memmove(dest + 5, src, 7); // 将src的内容复制到dest的特定位置,并覆盖dest原有的内容
printf("dest: %s\n", dest); // 输出:dest: Hello, World!
return 0;
}
注:在这个例子中,dest
和src
有重叠的部分。如果我们使用memcpy
,那么原始的dest[5:]
部分的数据将会被覆盖,导致结果不正确。但是使用memmove
,它能够正确地处理这种情况,保证原始数据不会被破坏。