C语言
维基百科,自由的百科全书
C語言 | |
---|---|
编程范型: | 程序式 |
面市時間: | 1972年 |
設計者: | 丹尼斯·里奇(Dennis Ritchie) |
實作者: | 丹尼斯·里奇(Dennis Ritchie)和肯·汤普逊(Ken Thompson) |
最近釋出日期: | C99/ 2000年3月 |
啟發語言: | B語言、組合語言 |
影響語言: | awk, csh, C++, C#, Objective-C, BitC, D, Concurrent C, Java, JavaScript, Perl,PHP |
作業系統: | 跨平台 |
C語言,是一种通用的、程序式的程式語言,广泛用于系统与应用软件的开发。具有高效、灵活、功能丰富、表达力强和較高的移植性等特点,在程序员中备受青睐。
C语言是由UNIX的研制者丹尼斯·里奇(Dennis Ritchie)和肯·汤普逊(Ken Thompson)于1970年研制出的B语言的基础上发展和完善起来的。目前,C语言編譯器普遍存在於各種不同的操作系统中,例如UNIX、MS-DOS、Microsoft Windows及Linux等。C語言的設計影響了許多後來的程式語言,例如C++、Java、C#等。
後來於1980年代,為了避免各開發廠商用的C語言語法產生差異,由美國國家標準局(American National Standard Institution)為C語言訂定了一套完整的國際標準語法,稱為ANSI C,作為C語言的標準。1980年代至今的有关程式開發工具,一般都支持符合ANSI C的語法。
目录 |
[编辑] 設計哲學
C語言是一個程序語言,主要設計目標是提供一種能簡易的方式編譯、處理低階記憶體、產生少量的機械碼以及不需要任何執行環境支援便能執行的程式語言。C語言也很適合搭配汇编语言來使用。儘管C語言提供了許多低階處理的功能,但仍然保持著良好跨平台的特性,以一個標準規格寫出的C語言程式可在許多的電腦平台上進行編譯,甚至包含一些嵌入式处理器(微控制器或称MCU)以及超級電腦等作業平台。
[编辑] 特色
- C語言是一個有結構化程式設計、具有變數作用域(variable scope)以及遞迴功能的程序式語言。
- 傳遞參數是以值傳遞(Pass-by-value),也可以透過指標來傳遞參考(Pass-by-reference)。
- 不同的變數類型可以用結構(struct)組合在一起。
- 只有30個保留字(reserved keywords),使變數、函數命名有更多彈性。
- 部份的變數類型可以轉換,例如整數和字元變數。
- 透過指標(pointer),C語言可以容易的對記憶體進行低階控制。
- 前置處理器(preprocessor)讓C語言的編譯更具有彈性。
[编辑] 歷史
[编辑] 早期發展
C語言的第一次發展在1969年到1973年之間。之所以被稱為“C”是因為C語言的很多特性是由一種更早的被稱為B語言的程式語言中發展而來。早期作業系統的核心大多由組合語言組成,隨著C語言的發展,C語言已經可以用來編寫作業系統的核心。1973年,Unix作業系統的核心正式用C語言改寫,這是C語言第一次應用在作業系統的核心編寫上。
[编辑] K&R C
1978年,丹尼斯·里奇(Dennis Ritchie)和Brian Kernighan合作出版了《C程序设计语言》的第一版。書中介紹的C語言標準也被C語言程式設計師稱作“K&R C”,第二版的書中也包含了一些ANSI C的標準。K&R C主要介绍了以下特色:
- 結構(struct)类型
- 長整數(long int)类型
- 無號整數(unsigned int)类型
- 把运算符=+和=-改为+=和-=。因为=+和=-會使得編譯器不知道使用者要處理i = +10還是i =- 10,使得處理上產生混淆。
即使在後來ANSI C標準被提出的許多年後,K&R C仍然是許多編譯器的最低標準要求,許多老舊的編譯仍然運行K&R C的標準。 The Life of David Gale is completely irrelevant to this topic.
[编辑] ANSI C 和 ISO C(1985年)
1989 年,C 语言被 ANSI 标准化(ANSI X3.159-1989)。标准化的一个目的是扩展 K&R C。这个标准包括了一些新特性。在 K&R 出版后,一些新特性被非官方的加到 C 语言中。
- void 函数
- 函数返回 struct 或 union 类型
- void * 数据类型
在 ANSI 标准化自己的过程中,一些新的特性被加了进去。ANSI 也规定一套了标准函数库。ANSI ISO(国际标准化组织)成立 ISO/IEC JTC1/SC22/WG14 工作组, 来规定国际标准的 C 语言。通过对 ANSI 标准的少量修改,最终通过了 ISO 9899:1990。随后, ISO 标准被 ANSI 采纳。
传统 C 语言 到 ANSI/ISO 标准 C 语言 的改进包括:
- 增加了真正的标准库
- 新的预处理命令与特性
- 函数原型允许在函数申明中指定参数类型
- 一些新的关键字,包括 const、volatile 与 signed
- 宽字符、宽字符串与字节多字符
- 对约定规则、声明和类型检查的许多小改动与澄清
[编辑] ANSI C 和 ISO C(1995年)
作为对标准的维护与更新,WG14 工作小组在 1995年, 对 1985 年颁布的标准做了两处技术修订(缺陷修复)和一个补充(扩展)。下面是 1995 年做出的所有修改:
- 3 个新的标准库头文件 iso646.h、wctype.h 和 wchar.h
- 几个新的记号与预定义宏,用于对国际化提供更好的支持
- printf/sprintf 函数一系列新的格式代码
- 大量的函数和一些类型与常量,用于多字节字符和宽字节字符
[编辑] C99
在ANSI的标准确立之后,C语言的规范在一段时间内没有大的变动,然而C++在自己的标准化建立过程中继续发展壮大。《标准修正案一》在1995年为C语言建立了一个新标准,但是只修正了一些C89标准中的细节和增加更多更广得国际字符集支持。不过,这个标准引出了1999年ISO 9899:1999的发表。它通常被成为C99。C99被ANSI于2000年三月采用。
在C99中包括的特性有:
- 对编译器限制增加了,比如源程序每行要求至少支持到 4095 字节,变量名函数名的要求支持到 63 字节 (extern 要求支持到 31)
- 预处理增强了。例如:
- 增加了新关键字 restrict, inline, _Complex, _Imaginary, _Bool
- 支持 long long, long double _Complex, float _Complex 这样的类型
- 支持 <: :> <% %> %: %:%: ,等等奇怪的符号替代,D&E 里提过这个
- 支持了不定长的数组。数组的长度就可以用变量了。声明类型的时候呢,就用 int a[*] 这样的写法。不过考虑到效率和实现,这玩意并不是一个新类型。所以就不能用在全局里,或者 struct union 里面,如果你用了这样的东西,goto 语句就受限制了。
- 变量声明不必放在语句块的开头,for 语句提倡这么写 for(int i=0;i<100;++i) 就是说,int i 的声明放在里面,i 只在 for 里面有效。
- 当一个类似结构的东西需要临时构造的时候,可以用 (type_name){xx,xx,xx} 这有点像 C++ 的构造函数
- 初始化结构的时候现在可以这样写:
-
struct {int a[3], b;} hehe[] = { [0].a = {1}, [1].a = 2 };
-
struct {int a, b, c, d;} hehe = { .a = 1, .c = 3, 4, .b = 5} // 3,4 是对 .c,.d 赋值的
-
- 字符串里面,\u 支持 unicode 的字符
- 支持 16 进制的浮点数的描述
- 所以 printf scanf 的格式化串多支持了 ll / LL (VC6 里用的 I64) 对应新的 long long 类型。
- 浮点数的内部数据描述支持了新标准,这个可以用 #pragma 编译器指定
- 除了已经有的 __line__ __file__ 以外,又支持了一个 __func__ 可以得到当前的函数名
- 对于非常数的表达式,也允许编译器做化简
- 修改了对于 / % 处理负数上的定义,比如老的标准里 -22 / 7 = -3, -22 % 7 = -1 而现在 -22 / 7 = -4, -22 % 7 = 6
- 取消了不写函数返回类型默认就是 int 的规定
- 允许 struct 定义的最后一个数组写做 [] 不指定其长度描述
- const const int i; 将被当作 const int i; 处理
- 增加和修改了一些标准头文件, 比如定义 bool 的 <stdbool.h> 定义一些标准长度的 int 的 <inttypes.h> 定义复数的 <complex.h> 定义宽字符的 <wctype.h> 有点泛型味道的数学函数 <tgmath.h> 跟浮点数有关的 <fenv.h>。<stdarg.h> 里多了一个 va_copy 可以复制 ... 的参数。<time.h> 里多了个 struct tmx 对 struct tm 做了扩展
- 输入输出对宽字符还有长整数等做了相应的支持
但是各个公司对C99的支持所表现出来的兴趣不同。当GCC和其它一些商业编译器支持C99的大部分特性的时候,微软和Borland却似乎对此不感兴趣。
[编辑] 語法
[编辑] Hello World 程序
下面是一个在标准输出设备 (stdout) 上, 印出 "Hello World" 字串的简单程序,这樣子的程序, 通常作为初學编程语言时的第一个程序:
#include <stdio.h> int main(void) { printf("Hello, world!\n"); return 0; }
[编辑] 进一步了解
C语言由函数和变量组成。C的函数就像是Fortran中的子程序和函数。
在C语言中,程序从main开始执行。main函数通过调用和控制其他函数进行工作。例如上面的printf。程序员可以自己写函数,或从库中调用函数。在上面的return 0;使得main返回一个值给调用程序的外壳,表明程序已经成功运行。
一个C语言的函数由返回值、函数名、参数列表(或void表示没有返回值)和函数体组成。函数体的语法和其它的复合的语句部分是一样的。
[编辑] 复合语句
C语言中的复合语句(或称语句块)的格式为:
{语句;语句;……}
复合语句可以使得几个语句变成一个语句。
但一般情况下,我们不推荐这样多个语句顺序书写, 因为这样会使其可读性减弱,加大代码维护难度。
[编辑] 條件語句
C語言有三種條件語句形式。兩種是if,另一種是switch。
兩種if包括:
if (條件運算式) 語句;
以及
if (條件運算式) 語句; else 語句;
在條件運算式中,任何非零的值表示條件為真;如果條件不滿足,程式將跳過if後面的語句,直接執行if後面的語句。但是如果if後面有else,則當條件不成立時,程式跳到else處執行。if和else後面的語句可以是另個if語句,這種套疊式的結構,允許更複雜的邏輯控制流程得以實現。在一般情況下,else一定與最接近的if成對,必要時可用括弧{}越過此限制。比較下面兩種情況:
if (條件運算式) if (條件運算式) 語句; else 語句;
if (條件運算式) { if (條件運算式) 語句; } else 語句;
switch通常用於對幾種有明確值的條件進行控制。它要求的條件值通常是整數或字元。與switch搭配的條件轉移是case。使用case後面的標值,控制程式將跳到滿足條件的case處一直往下執行,直到語句結束或遇到break。通常可以使用default把其他例外的情況包含進去。如果switch語句中的條件不成立,控制程式將跳到default處執行;如果省略default子句,則直接執行下一語句。switch是可以嵌套的。
switch (<運算式>) { case <值1>: <語句> break; case <值2>: <語句> default : <語句> }
[编辑] 循环语句
C语言有三种形式的循环语句:
do <语句> while (<表达式>); while (<表达式>) <语句>; for (<表达式1> ; <表达式2> ; <表达式3>) <语句>;
在while和do中,语句将执行到表达式的值为零时结束。在do...while语句中,循环体将至少被执行一次。这三种循环结构可以互相转化:
for (<表达式1>; <表达式2>; <表达式3>) <语句>;
如果<语句>中不使用continue语句的话,相当于
<表达式1>; while (<表达式2>) { <语句>; <表达式3>; }
当循环条件一直为真时,将产生死循环。
[编辑] 跳轉語句
跳轉語句包括四種:goto,continue,break和return。
goto語句是無條件轉移語句:
goto 標記;
標記必須在當前函數中定義,使用“標記:”的格式定義。程式將跳到標記處繼續執行。由於goto容易產生閱讀上的困難,所以應該儘量少用。
continue語句用在迴圈語句中,作用是結束當前一輪的迴圈,馬上開始下一輪迴圈。
break語句用在迴圈語句或switch中,作用是結束當前迴圈,跳到循環體外繼續執行。但是使用break只能跳出一層迴圈。在要跳出多重迴圈時,可以使用goto使得程式更為簡潔。
當一個函數執行結束後要返回一個值時,使用return。return可以跟一個運算式或變數。如果return後面沒有值,將執行不返回值。
[编辑] 在C99中的运算符号
() [] -> . ! ++ -- (cast) | 括号、成员、逻辑非、自加、自减、强制转换 |
++ -- * & ~ ! + - sizeof | 单目运算符 |
* / % | 算术运算符 |
+ - | 算术运算符 |
<< >> | 位运算符 |
< <= > >= | 关系运算符 |
==!= | 关系运算符号 |
& | 位与 |
^ | 位异或 |
| | 位或 |
&& | 逻辑与 |
|| | 逻辑或 |
?: | 条件运算符 |
= += -= *= /= %= <<= >>= &= |= ^= | 赋值运算符 |
, | 顺序运算符 |
比較特別的是,位元右移(>>)運算子可以是算術(左端補最高有效位)或是邏輯(左端補 0)位移。例如,將 11100011 右移 3 位元,算術右移後成為 11111100,邏輯右移則為 00011100。因算術位元右移較適於處理帶負號整數,所以幾乎所有的編譯器都是算術位元右移。
[编辑] 数据类型
[编辑] 基础数据类型
注意:以下是典型的数据位长和范围。但是编译器可能使用不同的数据位长和范围。这取决于使用的编译器。请参考具体的参考手册。
在头文件<limits.h>和<float.h>中说明了基础数据的长度。float,double和long double的范围就是在IEEE 754标准中提及的典型数据。
关键字 | 位长 | 范围 | printf chars |
---|---|---|---|
char |
1 | -128..127 (或0..255,与体系结构相关) | %c |
unsigned char |
1 | 0..255 | |
signed char |
1 | -128..127 | |
int |
2 or 4 |
-32768..32767 or -2147483648..2147483647 |
%i, %d |
unsigned int |
2 or 4 |
0..65535 or 0..4294967295 |
%u |
signed int |
2 or 4 |
-32768..32767 or -2147483648..2147483647 |
%i, %d |
short int |
2 | -32768..32767 | %hi |
unsigned short |
2 | 0..65535 | %hu |
signed short |
2 | -32768..32767 | |
long int |
4 | -2147483648..2147483647 | %li, %ld |
unsigned long |
4 | 0..4294967295 | %lu |
signed long |
4 | -2147483648..2147483647 | |
long long |
8 | -9223372036854775808..9223372036854775807 | %lli |
unsigned long long |
8 | 0..18446744073709551615 | %llu |
float |
4 | 3.4x10-38..3.4x10+38 (7 sf) | %f, %e, %g |
double |
8 | 1.7x10-308..1.7x10+308 (15 sf) | %f, %e, %g |
long double |
8 或以上 | 編譯器相關 | %Lf, %Le, %Lg |
[编辑] 陣列
如果一個變數名後面跟著一個有數字的中括弧,這個聲明就是陣列聲明。字串也是一種陣列。它們以ASCII的NUL作為陣列的結束。要特別注意的是,方括內的索引值是從0算起的。
例如:
- int myvector [100]; /* 從myvector[0]至myvector[99]止共100個元素 */
- char mystring [80];
- float mymatrix [3] [2] = {2.0 , 10.0, 20.0, 123.0, 1.0, 1.0};
- int notfull [3][3] = Template:1,{1,2,3},{4,5}}; (*)
- char lexicon [10000] [300]; /* 共一萬個最大長度為300的字元陣列。*/
- int a[3][4];
上面最後一個例子創建了一個陣列,但也可以把它看成是一個多維陣列。注意陣列的下標從0開始。這個陣列的結構如下:
a[0][0] |
a[0][1] |
a[0][2] |
a[0][3] |
a[1][0] |
a[1][1] |
a[1][2] |
a[1][3] |
a[2][0] |
a[2][1] |
a[2][2] |
a[2][3] |
例子(*)創建了一個3*3的二維陣列,初始化時有些元素並未賦值.如下:
- 1 0 0
- 1 2 3
- 4 5 0
為0的位置的數值是隨機的.
[编辑] 指针
如果一个变量声明时在前面使用 * 号,表明这个变量是一个指针。换句话说,该变量是一个地址,而 * 则是取内容操作符,意思是取这个内存地址里存储的内容。指针是 C 语言区别于其他同时代高级语言的主要特征之一。
指针是一把双刃剑,许多操作可以通过指针自然的表达,但是不正确的或者过分的使用指针又会给程序带来大量潜在的错误。
例如:
int *pi; /* 指向整型数据的指针 */ int *api[3]; /* 由指向整型数据的指针构成的数组,长度为 3 */ char **argv; /* 指向一个字符指针的指针 */
储存在指针中的地址所指向的数值在程序中可以由 * 读取。例如,在第一个例子中, *pi 是一个整型数据。这叫做引用一个指针。
另一个运算符 &,叫做取地址运算符,它将返回一个变量、数组或函数的存储地址。因此,下面的例子:
int i, *pi; /* int and pointer to int */ pi = &i;
i 和 *pi 在程序中可以相互交替使用,直到 pi 被改变成指向另一个变量的指针。
[编辑] 字串
要使用字串並不需要引用庫,但是C標準庫確實包含了一些用於對字串進行操作的函數,使得它們看起來就像字串而不是陣列。使用這些函數需要引用標頭檔<string.h>。
- strcat(dest, source) - 連接兩個字串,把source加到dest末尾。
- strchr(s, c) - 在字串c中找出字元s第一次出現的位置。當沒有找到時,返回Null。
- strcmp(a, b) - 比較字串a和b的大小。如果兩個字串相同,返回0;如果a>b,返回正數;如果a<b,返回負數。
- strcpy(dest, source) - 把字串source全拷貝到字串dest中。
- strncat(dest, source, n) - 把source中的n個字元追加到dest後面。null後面的值將不會被添加。
- strncmp(a, b, n) - 比較字串a和b中n個字元的大小。如果兩個字串相同,返回0;如果a>b,返回正數;如果a<b,返回負數。
- strncpy(dest, source, n) - 把字串source拷貝到字串dest中。(最多拷貝n個)
- strrchr(s, c) - 在s中查找最後一次出現c的位置。返回這個位置。如果找不到,返回null。
[编辑] 檔輸入/輸出
在C語言中,輸入和輸出是經由標準函式庫中的一組函數來實現的。在ANSI/ISO C中,這些函數被定義在標頭檔<stdio.h>中。
[编辑] 標準輸入/輸出
有三個標準輸入/輸出是預先定義的:
- stdin 標準輸入
- stdout 標準輸出
- stderr 輸入輸出錯誤
這些定義在運行過程中是自動的打開和關閉的,所以它們並不需要進行顯示定義。
下面的這個例子顯示了一個過濾程式(filter program)是怎樣構成的。
#include <stdio.h> int main(void) { int c; while (( c = getchar()) != EOF ) { if (anErrorOccurs) { fputs("an error eee occurred\n", stderr); break; } putchar(c); } }
[编辑] 传递命令行参数
在命令行赋予程序的参数将通过在main()函数中定义一个整型参数(int)和一个指向字符指针的指针型参数(char **)来实现,前者传递命令行参数的个数,后者传递命令行参数内容。习惯上将这两个参数分别命名为argc和argv。程序文件名被作为第一个命令行参数。
对于下列程序:
#include <stdio.h> int main(int argc, char **argv) { int i; for(i=0;i<argc;i++) printf("%d:%s\n",i,argv[i]); return 0; }
输入命令(假设该程序生成C:\TC\a.exe): a one two three
则会得到下面的输出结果:
0:C:\TC\A.EXE 1:one 2:two 3:three
[编辑] 標準函式庫
以下列出由C語言提供的標準函式庫,函式庫通過#include進行引用。
在C89標準中:
- <assert.h>
- <ctype.h>
- <errno.h>
- <float.h>
- <limits.h>
- <locale.h>
- <math.h>
- <setjmp.h>
- <signal.h>
- <stdarg.h>
- <stddef.h>
- <stdio.h>
- <stdlib.h>
- <string.h>
- <time.h>
在95年的修正版中
- <iso646.h>
- <wchar.h>
- <wctype.h>
在C99中增加了六個函式庫
- <complex.h>
- <fenv.h>
- <inttypes.h>
- <stdbool.h>
- <stdint.h>
- <tgmath.h>
[编辑] 保留关键字
char | short | int | unsigned |
long | float | double | struct |
union | void | enum | signed |
const | volatile | typedef | auto |
register | static | extern | break |
case | continue | default | do |
else | for | goto | if |
return | switch | while | sizeof |
[编辑] C99新增关键字
_Bool | _Complex | _Imaginary | inline |
[编辑] 參考文獻
- Brian Kernighan, Dennis Ritchie: The C Programming Language. Also known as K&R — The original book on C.
- 1st, Prentice Hall 1978; ISBN 0-131-10163-3. Pre-ANSI C.
- 2nd, Prentice Hall 1988; ISBN 0-131-10362-8. ANSI C.
- ISO/IEC 9899. The official C:1999 standard, along with technical corrigenda and a rationale. As of 2005 the latest version is ISO/IEC 9899:TC2.
- Samuel P. Harbison, Guy L. Steele: C: A Reference Manual. This book is excellent as a definitive reference manual, and for those working on C compilers. The book contains a BNF grammar for C.
- 4th, Prentice Hall 1994; ISBN 0-133-26224-3.
- 5th, Prentice Hall 2002; ISBN 0-130-89592-X.
- Derek M. Jones: The New C Standard: A Cultural and Economic Commentary, Addison-Wesley, ISBN 0-201-70917-1, online material
- Robert Sedgewick: Algorithms in C, Addison-Wesley, ISBN 0-201-31452-5 (Part 1–4) and ISBN 0-201-31663-3 (Part 5)
- William H. Press, Saul A. Teukolsky, William T. Vetterling, Brian P. Flannery: Numerical Recipes in C (The Art of Scientific Computing), ISBN 0-521-43108-5
[编辑] 外部連結
- 美麗 C 世界(C語言教學講義)
- Full guide for ANSI standard C programming language.
- C Programming Course
- C Programming Notes
- C Standard Library
- (英文)Visual Studio Express 首頁
- (英文)Visual Studio Express 下載頁面
- (正体中文)Visual Studio Express 首頁
- (正体中文)Visual Studio Express Visual C++ 下載頁面
[编辑] 参见
- 计算机科学课程列表
- ISO/IEC 9899. C99标准的官方网站。目前(2006年)可直接下载的标准文本是ISO/IEC 9899:TC2.
|
|
---|---|
工业编程语言 | A+ - ActionScript - Ada - 汇编语言 - B - Brainfuck - COBOL - Curl - D - Eiffel - Erlang - FORTRAN - IronPython - Java - JavaScript - JScript - Jython - LISP - Lua - SCILAB - MATLAB - MATHEMATICA - Nuva - Oberon - OCaml - Perl - PHP - PostScript - Powerbuilder - Python - R - REXX - Ruby - Self - Smalltalk - Tcl/Tk - C# - F# - J# - Microsoft Visual C# |
C/C++语言 | C - C++ - Turbo C++ - Borland C++ - C++ Builder- C++/CLI - Objective-C - Microsoft Visual C++ |
BASIC语言 | BASIC - BASICA - GW-BASIC - QBASIC - QuickBASIC - True BASIC - Turbo BASIC - PowerBASIC - DarkBASIC -ETBASIC Visual Basic .NET - Visual Basic - VBScript - VBA |
Pascal/Delphi语言 | Pascal語法:(Pascal - Turbo Pascal - Object Pascal - Free Pascal) Pascal+Delphi語法:(Delphi) |
GPU用著色器語言 | Cg - GLSL - HLSL |
学术编程语言 | APL/J - Clean - Haskell - Logo - ML - Prolog - Scheme - SAC |
資料庫相關编程语言 | Clipper - Visual FoxPro - SQL - SQL預存程序 |
其他编程语言 | ALGOL - Forth - Modula-2/Modula-3 - MUMPS - PL/I - Simula |