常用C庫簡介


一、數學庫<math.h>

數學庫包含許多有用的數學函數。頭文件math.h提供了這些函數的函數聲明或原型。注意角度的單位為弧度。

ANSI C標准數學函數原型描述
原型 描述
double acos (double x) 返回余弦值為x的角度值
double asin (double x) 返回正弦值為x的角度值
double atan (double x) 返回正切值為x的角度值
double atan2 (double y, double x) 返回正切值為y/x的角度值
double cos (double x) 返回x的余弦值
double sin (double x) 返回x的正弦值
double tan (double 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 ceil (double x) 返回不小於x的最小整數值
double fabs (double x) 返回x的絕對值
double floor (double x) 返回不大於x的最大整數值

pi的值可以通過計算表達式4 * atan(1)得到:

const int PI = 4 * atan (1);

UNIX系統要求使用-lm標記以指示鏈接器搜索數學庫:

cc rect_pol.c -lm

Linux的gnu編譯器也使用相同的形式:

gcc rect_pol.c -lm

 

二、通用工具庫<stdlib.h>

通用工具庫包含各種函數,其中包括隨機數產生函數、搜索和排序函數、轉換函數和內存管理函數等。

1. exit( )atexit( )函數

void exit (int)
int atexit (void (*)(void))

程序從main( )返回時會自動調用exit( )函數。另外,ANSI C標准還增加了一些新功能。其中一個是,可以指定執行exit( )時調用的特定函數。通過對退出時調用的函數進行注冊,atexit( )函數也提供這項功能;atexit( )函數使用函數指針作為參數。示例程序如下:

// byebye.c -- atexit( )示例程序
#include <stdio.h>
#include <stdlib.h>

void sign_off (void);
void too_bad (void);

int main (void)
{
    int n;

    atexit (sign_off); // 注冊sign_off( )函數
    puts ("Enter an integer: ");
    if (scanf ("%d", &n) != 1)
    {
        puts ("That's no integer!");
        atexit (too_bad);
        exit (EXIT_FAILURE);
    }
    printf ("%d is %s.\n", n, (n % 2 == 0) ? "even" : "odd");

    return 0;
}

void sign_off(void)
{
    puts ("Thus terminates another magnificent program from");
    puts ("SeeSaw Software!");
}

void too_bad (void)
{
    puts ("SeeSaw Software extends its heartfelt condolences");
    puts ("to you upon the failure of your program");
}

atexit( )把作為其參數的函數在調用exit( )時執行的函數列表中進行注冊。ANSI保證在這個列表中至少可放置32個函數。通過使用一個單獨的atexit( )調用把每個函數添加到列表中。最后,調用exit( )函數時,按先進后出的順序執行這些函數。

由atexit( )注冊的函數的類型應該為不接受任何參數的返回void的函數。通常它們執行內部處理事務。

注意,main( )終止時會隱式地調用exit( );因此,即使未顯式地調用eixt( ),也會調用經atexit( )注冊的函數。

對於exit( )函數:exit( )函數執行了atexit( )指定的函數之后,將做一些自身清潔工作。它會刷新所有輸出流、關閉所有打開的流,並關閉通過調用標准I/O函數tmpfile()創建的臨時文件。然后,exit( )把通知返回給主機環境。習慣上,UNIX程序用0表示終止,用非零值表示失敗。ANSI C定義了可移植的表示失敗的宏EXIT_FAILURE和表示成功的宏EXIT_SUCCESS,但是exit( )也接受用0表示成功。ANSI C中,在非遞歸的main( )函數中使用exit( )函數等價於使用關鍵字return。但是,在main( )之外的函數中使用exit( )也會終止程序。

 

2. qsort( )函數

void qsort (void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

快速排序法是最有效的排序算法之一,對大型數組而言更是如此。

函數的第一個參數為指向要排序的數組頭部的指針;第二個參數為需要排序的項目數量;第三個參數為每個數組元素的大小;最后一個參數為一個指向函數的指針,被指向的函數用於確定排序順序。

函數調用的結果是數組被按照遞增的順序被排序。

比較函數:

int (*compar) (const void *, const void *)

比較函數接受兩個參數,即分別指向進行比較的兩個項目的指針。如果第一個項目的值大於第二個項目的指,那么比較函數返回整數;如果兩個項目的值相等,那么返回0;如果第一個項目的值小於第二個項目的值,那么返回負數。示例程序如下:

// qsorter.c -- 使用qsort()對一組數字排序
#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 ("Sorted 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)
{
    const double * a1 = (const double *)p1;
    const double * a2 = (const double *)p2;

    return *a1 - *a2;
}

 

三、診斷庫<assert.h>

診斷庫是設計用於輔助調試程序的小型庫,有宏assert( )構成。該宏接受整數表達式作為參數。如果表達式值為假(非零),宏assert()向標准錯誤流(stderr)寫一條錯誤信息並調用abort( )函數以終止程序;值為真則什么也不做。錯誤信息包括失敗的判斷表達式、該判斷所在的文件名和行號。例如:

assert (z >= 0)

如果z < 0,則判斷失敗。assert會中斷程序,並且可能的輸出如下:

Assertion failed: z >= 0, file C:\use_assert.c, line 14

如果您認為已經排除了程序的漏洞不再需要assert調試,那么可以把宏定義#define NDEBUG放在assert.h包含語句的前面,並重新編譯該程序。編譯器將禁用文件中所有的assert()語句。去掉#define NDEBUG並重新編譯程序,就又重新啟動了assert( )語句。

 

四、string.h庫中的memcpy( )memmove( )

不能把一個數組的值直接賦予另一個數組,因此,我們使用循環把數組中的元素逐個復制到另一個數組。一個例外情況是:可以使用strcpy( )和strncoy( )函數復制字符數組。memcpy( )和memmove( )函數為復制其他類型的數組提供了類似的便利工具。下面是這兩個函數的原型:

void *memcpy (void * restrict s1, const void * restrict s2, size_t n);
void *memmove (void *s1, const void *s2, size_t n);

這兩個函數均從s2指向的位置復制n字節數據到s1指向的位置,且返回s1的指。兩者間的差異由關鍵字restrict造成,即memcpy( )可以假定兩個內存區域之間沒有重疊。memmove( )函數則不作這個假設,因此,復制過程類似於首先將所有字節復制到一個臨時緩沖區,然后再復制到最終目的地。對存在重疊的兩個區域使用memcpy( )的結果是不可欲知的。因此,使用memcpy( )時,您必須確保沒有重疊區域。第三個參數指定要復制的字節數。注意,字節數不一定等於元素的個數。一般情況下,n = nmemb * sizeof(type)。

 

五、可變參數:stdarg.h

頭文件stdarg.h為函數提供了接受可變個數的參數的能力。為使用這個特性,需要按如下步驟進行操作:

  1. 在函數原型中使用省略號。double sum(int lim, ...) {......}
  2. 在函數定義中創建一個va_list類型的變量。va_list ap;
  3. 用宏將該變量初始化為一個參數列表。va_start (ap, lim);
  4. 用宏訪問這個參數列表。double tic = va_arg(ap, double);
  5. 用宏完成清理工作。va_end(ap);
  6. 附加操作:復制va_list,應當在va_list被初始化后進行。va_copy(ls_list dest, ls_list src);

可變參數列表必須為函數的參數列表的最后一個,且之前需要至少存在一個普通參量:

void f1 (int n, ...); // 合法
int f2 (int n, char * s, ...); // 合法
char f3 (char c1, ..., char c2); // 非法,省略號不是最后一個參量
double f3 (...); //非法,沒有普通參量

需要使用到的數據類型和宏:

va_list ap; // 用於存放參數的變量

va_start(ap, lim); // 初始化參數列表。lim為函數列表中最后一個普通參量

double tic = va_arg(ap, double); // 依此取得一個參數,第二個參數為需要獲得的數據類型。

va_end(ap); // 最后的清理工作

va_copy(apcopy, ap); // 將參數列表ap復制到apcopy,注意要在ap被初始化后進行。

程序示例:

// varargs.c -- 使用可變個數的參數
#include <stdio.h>
#include <stdarg.h>

double sum (int, ...);

int main (void)
{
    double s, t;
    s = sum(3, 1.1, 2.5, 13.3);
    t = sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1);
    printf("return value for "
           "sum(3, 1.1, 2.5, 13.3): %g\n",s);
    printf("return value for "
           "sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1): %g\n", t);

    return 0;
}

double sum (int lim, ...) // 使用lim記錄傳入參數的個數
{
    va_list ap;  // 聲明用於存放參數的變量
    double tot = 0;
    int i;
    va_start(ap, lim); // 初始化為參數列表。注意:需要由最后一個普通參量來確定不定參數列表的地址。
    for (i = 0; i < lim; i++)
        tot += va_arg(ap, double); // 訪問參數列表中的項目
    va_end(ap); // 清理參數列表
    return tot;
}

va_copy的使用:

va_list ap;
va_list apcopy;
double tic;
...
va_start(ap, lim);
va_copy(apcopy, ap); // 將ap復制到apcopy
tic = va_arg(ap, double);
...

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM